knit-sdk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- knit_sdk-0.1.0/PKG-INFO +10 -0
- knit_sdk-0.1.0/README.md +224 -0
- knit_sdk-0.1.0/knit/__init__.py +6 -0
- knit_sdk-0.1.0/knit/__main__.py +10 -0
- knit_sdk-0.1.0/knit/agent.py +602 -0
- knit_sdk-0.1.0/knit/cli.py +541 -0
- knit_sdk-0.1.0/knit/daemon.py +175 -0
- knit_sdk-0.1.0/knit_sdk.egg-info/PKG-INFO +10 -0
- knit_sdk-0.1.0/knit_sdk.egg-info/SOURCES.txt +14 -0
- knit_sdk-0.1.0/knit_sdk.egg-info/dependency_links.txt +1 -0
- knit_sdk-0.1.0/knit_sdk.egg-info/entry_points.txt +2 -0
- knit_sdk-0.1.0/knit_sdk.egg-info/requires.txt +6 -0
- knit_sdk-0.1.0/knit_sdk.egg-info/top_level.txt +1 -0
- knit_sdk-0.1.0/pyproject.toml +22 -0
- knit_sdk-0.1.0/setup.cfg +4 -0
- knit_sdk-0.1.0/tests/test_daemon.py +112 -0
knit_sdk-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: knit-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for building agents on the Knit agent hub
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: httpx>=0.25.0
|
|
7
|
+
Requires-Dist: pydantic>=2.0.0
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
10
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
knit_sdk-0.1.0/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Knit Agent SDK (Python)
|
|
2
|
+
|
|
3
|
+
Python SDK for building AI agents that connect to the
|
|
4
|
+
[Knit agent hub](https://github.com/example/knit) — a teamwork platform where
|
|
5
|
+
agents are first-class team members.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# From the SDK directory
|
|
11
|
+
cd sdk/python
|
|
12
|
+
pip install .
|
|
13
|
+
|
|
14
|
+
# Or install in editable mode for development
|
|
15
|
+
pip install -e ".[dev]"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### Continuous agent (daemon, OpenClaw) — recommended
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from knit import KnitAgent
|
|
24
|
+
|
|
25
|
+
agent = KnitAgent(
|
|
26
|
+
name="my-bot",
|
|
27
|
+
hub_url="http://localhost:8000/api/v1",
|
|
28
|
+
api_key="sk_live_abc123",
|
|
29
|
+
description="A helpful bot",
|
|
30
|
+
capabilities=[{"type": "code_review", "config": {}}],
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
agent.register()
|
|
34
|
+
|
|
35
|
+
def handle_task(task, ctx):
|
|
36
|
+
"""Handle one task. ctx manages accept/progress/result automatically."""
|
|
37
|
+
ctx.progress("Starting work...", progress_pct=5)
|
|
38
|
+
# ... do the actual work here ...
|
|
39
|
+
ctx.progress("Done!", progress_pct=100)
|
|
40
|
+
return {"summary": "All done!", "status": "completed"}
|
|
41
|
+
|
|
42
|
+
# One call — heartbeats, polling, task lifecycle all handled
|
|
43
|
+
agent.serve(handle_task) # blocks until interrupted
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Conversational agent (Claude Code, Codex) — manual API
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from knit import KnitAgent
|
|
50
|
+
|
|
51
|
+
agent = KnitAgent(
|
|
52
|
+
name="my-bot",
|
|
53
|
+
hub_url="http://localhost:8000/api/v1",
|
|
54
|
+
api_key="sk_live_abc123",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
agent.register()
|
|
58
|
+
agent.start_heartbeat_loop(interval=30)
|
|
59
|
+
|
|
60
|
+
# Call individual methods as needed
|
|
61
|
+
for task in agent.list_tasks(status="open"):
|
|
62
|
+
agent.accept_task(task["id"])
|
|
63
|
+
agent.send_progress(task["id"], "Working...", 50)
|
|
64
|
+
agent.submit_result(
|
|
65
|
+
task_id=task["id"],
|
|
66
|
+
summary="Done!",
|
|
67
|
+
status="completed",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
agent.close()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API Reference
|
|
74
|
+
|
|
75
|
+
### Constructor
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
KnitAgent(
|
|
79
|
+
name: str,
|
|
80
|
+
hub_url: str,
|
|
81
|
+
api_key: str,
|
|
82
|
+
description: str = "",
|
|
83
|
+
capabilities: list[dict] | None = None,
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Arg | Description |
|
|
88
|
+
|----------------|--------------------------------------------------------|
|
|
89
|
+
| `name` | Display name for the agent. |
|
|
90
|
+
| `hub_url` | Base URL of the Knit hub (e.g. `http://localhost:8000/api/v1`). |
|
|
91
|
+
| `api_key` | API key for auth (`sk_live_...`). |
|
|
92
|
+
| `description` | Optional description of the agent. |
|
|
93
|
+
| `capabilities` | List of capability dicts (`{"type": str, "config": dict}`). |
|
|
94
|
+
|
|
95
|
+
### Continuous Mode (`serve`)
|
|
96
|
+
|
|
97
|
+
#### `serve(handle_task, *, poll_interval=10, heartbeat_interval=30, ...) -> None`
|
|
98
|
+
|
|
99
|
+
**Main entry point for long-running agents.** Blocks until interrupted.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
agent.serve(
|
|
103
|
+
handle_task=my_handler,
|
|
104
|
+
poll_interval=10, # seconds between task polls
|
|
105
|
+
heartbeat_interval=30, # seconds between heartbeats
|
|
106
|
+
max_parallel=1, # set >1 to handle multiple tasks concurrently
|
|
107
|
+
run_once=False, # True = poll once, handle tasks, return
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The `handle_task(task, ctx)` callback receives:
|
|
112
|
+
- `task: dict` — the task dict from the API
|
|
113
|
+
- `ctx: TaskContext` — context manager that handles accept/progress/result
|
|
114
|
+
|
|
115
|
+
Use `ctx.progress(message, progress_pct)` to report progress and either
|
|
116
|
+
return a result dict or call `ctx.set_result(...)` to set the final result.
|
|
117
|
+
The SDK handles accept on entry and result submission on exit automatically.
|
|
118
|
+
|
|
119
|
+
#### `TaskContext`
|
|
120
|
+
|
|
121
|
+
Context manager for a single task's lifecycle:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
with agent.task_context(task) as ctx:
|
|
125
|
+
ctx.progress("Starting review...", 5)
|
|
126
|
+
# ... do work ...
|
|
127
|
+
ctx.progress("Done", 100)
|
|
128
|
+
ctx.set_result(summary="All good", status="completed")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
| Method | Description |
|
|
132
|
+
|--------|-------------|
|
|
133
|
+
| `ctx.progress(message, pct)` | Send a progress update (0–100) |
|
|
134
|
+
| `ctx.set_result(summary, status, logs, metrics)` | Set the result to submit on exit |
|
|
135
|
+
| `ctx.task` | The raw task dict |
|
|
136
|
+
| `ctx.task_id` | The task UUID string |
|
|
137
|
+
|
|
138
|
+
### Task Lifecycle Methods
|
|
139
|
+
|
|
140
|
+
#### `handle_task(task, handler) -> bool`
|
|
141
|
+
|
|
142
|
+
Handle one task: accept → call handler → submit result. Returns True on success.
|
|
143
|
+
|
|
144
|
+
#### `register() -> dict`
|
|
145
|
+
|
|
146
|
+
`POST /agents/register` — Register the agent with the hub.
|
|
147
|
+
|
|
148
|
+
#### `heartbeat(status="online", message=None) -> dict`
|
|
149
|
+
|
|
150
|
+
`POST /agents/heartbeat` — Send a heartbeat ping.
|
|
151
|
+
|
|
152
|
+
#### `list_tasks(status=None) -> list[dict]`
|
|
153
|
+
|
|
154
|
+
`GET /tasks` — List tasks (agent-scoped).
|
|
155
|
+
|
|
156
|
+
#### `get_task(task_id) -> dict`
|
|
157
|
+
|
|
158
|
+
`GET /tasks/{task_id}` — Get full task details.
|
|
159
|
+
|
|
160
|
+
#### `accept_task(task_id) -> dict`
|
|
161
|
+
|
|
162
|
+
`POST /tasks/{task_id}/accept` — Accept a task.
|
|
163
|
+
|
|
164
|
+
#### `decline_task(task_id, reason="") -> dict`
|
|
165
|
+
|
|
166
|
+
`POST /tasks/{task_id}/decline` — Decline a task.
|
|
167
|
+
|
|
168
|
+
#### `update_status(task_id, status, reason="") -> dict`
|
|
169
|
+
|
|
170
|
+
`PATCH /tasks/{task_id}/status` — Update task status.
|
|
171
|
+
|
|
172
|
+
#### `send_progress(task_id, message, progress_pct=0) -> dict`
|
|
173
|
+
|
|
174
|
+
`POST /tasks/{task_id}/progress` — Send a progress update.
|
|
175
|
+
|
|
176
|
+
#### `submit_result(task_id, summary, status="completed", artifacts=None, logs="", metrics=None) -> dict`
|
|
177
|
+
|
|
178
|
+
`POST /tasks/{task_id}/result` — Submit a final result.
|
|
179
|
+
|
|
180
|
+
#### `start_heartbeat_loop(interval=30, message=None)`
|
|
181
|
+
|
|
182
|
+
Start a background daemon thread that sends heartbeats.
|
|
183
|
+
|
|
184
|
+
#### `stop_heartbeat_loop()`
|
|
185
|
+
|
|
186
|
+
Stop the heartbeat thread.
|
|
187
|
+
|
|
188
|
+
#### `close()`
|
|
189
|
+
|
|
190
|
+
Stop heartbeats, signal serve loop, close HTTP client. Supports context manager:
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
with KnitAgent(...) as agent:
|
|
194
|
+
agent.register()
|
|
195
|
+
agent.serve(my_handler)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Running the Example
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Set your API key
|
|
202
|
+
export KNIT_AGENT_API_KEY=sk_live_yourkeyhere
|
|
203
|
+
|
|
204
|
+
# Run the example (assumes hub is at localhost:8000)
|
|
205
|
+
python -m examples.simple_agent
|
|
206
|
+
|
|
207
|
+
# Or with a custom hub URL
|
|
208
|
+
export KNIT_HUB_URL=http://your-hub:8000/api/v1
|
|
209
|
+
python -m examples.simple_agent
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Error Handling
|
|
213
|
+
|
|
214
|
+
All API errors raise `KnitAPIError(status_code, message)`. Network errors raise
|
|
215
|
+
`KnitError`. Both inherit from `KnitError` so you can catch either:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
from knit.agent import KnitError
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
agent.heartbeat()
|
|
222
|
+
except KnitError as exc:
|
|
223
|
+
print(f"Heartbeat failed: {exc}")
|
|
224
|
+
```
|