Skip to content

Commit d07ce0b

Browse files
committed
fix: add proper imports and modernize README
- Add blank lines after imports for PEP 8 compliance - Modernize README with badges, quick start, and streaming examples
1 parent f97d5f4 commit d07ce0b

2 files changed

Lines changed: 35 additions & 166 deletions

File tree

README.md

Lines changed: 32 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1-
# hawk-sdk
2-
3-
Python SDK for the [Hawk](https://github.com/hawk-eco/hawk) daemon API.
1+
<p align="center">
2+
<h1 align="center">Hawk SDK for Python</h1>
3+
<p align="center">
4+
<strong>Official Python client for the Hawk daemon API</strong>
5+
</p>
6+
<p align="center">
7+
<a href="https://python.org/"><img src="https://img.shields.io/badge/Python-3.10+-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python"></a>
8+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License"></a>
9+
<a href="https://github.com/GrayCodeAI/hawk-sdk-python/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/GrayCodeAI/hawk-sdk-python/ci.yml?style=flat-square&label=tests" alt="CI"></a>
10+
</p>
11+
</p>
12+
13+
---
14+
15+
The Hawk SDK for Python provides an idiomatic client for interacting with the [Hawk](https://github.com/GrayCodeAI/hawk) daemon API. It supports both synchronous and async operations, including streaming.
16+
17+
## Features
18+
19+
- **Sync and async** - Use `HawkClient` or `AsyncHawkClient`
20+
- **Streaming support** - Real-time response streaming
21+
- **Context managers** - Automatic resource cleanup
22+
- **Type hints** - Full type annotations for IDE support
23+
- **Error handling** - Detailed exception types
424

525
## Installation
626

@@ -14,191 +34,38 @@ pip install hawk-sdk
1434
from hawk import HawkClient
1535

1636
with HawkClient() as client:
17-
# Check health
37+
# Health check
1838
health = client.health()
19-
print(f"Status: {health.status}, Version: {health.version}")
39+
print(f"Version: {health.version}")
2040

2141
# Chat
22-
response = client.chat("Explain async/await in Python")
42+
response = client.chat("Explain decorators in Python")
2343
print(response.response)
2444
```
2545

2646
## Async Usage
2747

2848
```python
29-
import asyncio
3049
from hawk import AsyncHawkClient
3150

32-
async def main():
33-
async with AsyncHawkClient() as client:
34-
response = await client.chat("Hello!")
35-
print(response.response)
36-
37-
asyncio.run(main())
51+
async with AsyncHawkClient() as client:
52+
response = await client.chat("Hello!")
53+
print(response.response)
3854
```
3955

4056
## Streaming
4157

4258
```python
43-
from hawk import HawkClient
44-
4559
with HawkClient() as client:
4660
with client.chat_stream("Write a haiku") as stream:
4761
for event in stream.events():
4862
print(event.data, end="", flush=True)
49-
print()
50-
```
51-
52-
Or collect the full text:
53-
54-
```python
55-
with HawkClient() as client:
56-
with client.chat_stream("Write a haiku") as stream:
57-
text = stream.collect_text()
58-
print(text)
59-
```
60-
61-
## Tools
62-
63-
```python
64-
from hawk import HawkClient, Tool, tool, chat_with_tools
65-
66-
@tool(
67-
name="get_weather",
68-
description="Get current weather for a location",
69-
parameters={
70-
"type": "object",
71-
"properties": {"location": {"type": "string"}},
72-
"required": ["location"],
73-
},
74-
)
75-
def get_weather(location: str) -> str:
76-
return f"Sunny, 72F in {location}"
77-
78-
with HawkClient() as client:
79-
response = chat_with_tools(
80-
client,
81-
"What's the weather in NYC?",
82-
tools=[get_weather],
83-
)
84-
print(response.response)
85-
```
86-
87-
## Workflow
88-
89-
```python
90-
from hawk import Workflow
91-
from hawk.retry import RetryConfig
92-
93-
def fetch(url: str) -> str:
94-
import httpx
95-
return httpx.get(url).text
96-
97-
def summarize(text: str) -> str:
98-
# Process the text
99-
return text[:100]
100-
101-
wf = (
102-
Workflow("fetch-and-summarize")
103-
.step("fetch", fetch, timeout=10.0)
104-
.step("summarize", summarize, retry=RetryConfig(max_retries=2))
105-
.build()
106-
)
107-
108-
result = wf.run("https://example.com")
109-
```
110-
111-
## Agent
112-
113-
```python
114-
from hawk import HawkClient, Agent, AgentConfig, Tool
115-
116-
weather_tool = Tool(
117-
name="get_weather",
118-
description="Get weather",
119-
parameters={"type": "object", "properties": {"location": {"type": "string"}}},
120-
fn=lambda location: f"72F in {location}",
121-
)
122-
123-
with HawkClient() as client:
124-
agent = Agent(client, AgentConfig(
125-
name="weather-bot",
126-
model="claude-sonnet-4-20250514",
127-
tools=[weather_tool],
128-
))
129-
130-
response = agent.chat("What's the weather in San Francisco?")
131-
print(response.response)
132-
133-
# Conversation history is maintained
134-
response = agent.chat("What about New York?")
135-
print(response.response)
136-
```
137-
138-
## Sessions
139-
140-
```python
141-
from hawk import HawkClient
142-
143-
with HawkClient() as client:
144-
# List sessions
145-
sessions = client.list_sessions(limit=10)
146-
for s in sessions.data:
147-
print(f"{s.id}: {s.turns} turns")
148-
149-
# Get session details
150-
detail = client.get_session("session-id")
151-
print(f"Model: {detail.model}, Messages: {detail.message_count}")
152-
153-
# Get messages
154-
messages = client.list_messages("session-id")
155-
for m in messages.data:
156-
print(f"[{m.role}] {m.content}")
157-
158-
# Delete session
159-
client.delete_session("session-id")
160-
```
161-
162-
## Configuration
163-
164-
```python
165-
from hawk import HawkClient, RetryConfig
166-
167-
client = HawkClient(
168-
base_url="http://localhost:4590", # Daemon URL
169-
api_key="sk-...", # Optional API key
170-
timeout=60.0, # Request timeout in seconds
171-
retry_config=RetryConfig(
172-
max_retries=5,
173-
initial_backoff=1.0,
174-
max_backoff=60.0,
175-
),
176-
)
177-
```
178-
179-
## Error Handling
180-
181-
```python
182-
from hawk import HawkClient, NotFoundError, RateLimitError, HawkAPIError
183-
184-
with HawkClient() as client:
185-
try:
186-
session = client.get_session("nonexistent")
187-
except NotFoundError as e:
188-
print(f"Not found: {e.message}")
189-
except RateLimitError as e:
190-
print(f"Rate limited, retry after {e.retry_after}s")
191-
except HawkAPIError as e:
192-
print(f"API error {e.status_code}: {e.message}")
19363
```
19464

195-
## Development
65+
## Examples
19666

197-
```bash
198-
pip install -e ".[dev]"
199-
pytest
200-
```
67+
See the [examples/](examples/) directory for complete runnable examples.
20168

20269
## License
20370

204-
MIT
71+
MIT - see [LICENSE](LICENSE) for details.

examples/basic/main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#!/usr/bin/env python3
22
"""Basic example of using the Hawk SDK."""
33

4-
from hawk import HawkClient
4+
from hawk import HawkClient # noqa: E402
5+
56

67
def main():
78
with HawkClient() as client:
@@ -20,5 +21,6 @@ def main():
2021
print(event.data, end="", flush=True)
2122
print()
2223

24+
2325
if __name__ == "__main__":
2426
main()

0 commit comments

Comments
 (0)