handoffkit 0.2.0__tar.gz → 0.4.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.
- {handoffkit-0.2.0 → handoffkit-0.4.0}/MANIFEST.in +3 -0
- handoffkit-0.4.0/PKG-INFO +474 -0
- handoffkit-0.4.0/README.md +445 -0
- handoffkit-0.4.0/examples/context_handoff_demo.py +116 -0
- handoffkit-0.4.0/examples/fake_provider_tool_call_demo.py +62 -0
- handoffkit-0.4.0/examples/memory_demo.py +55 -0
- handoffkit-0.4.0/examples/project_context_demo.py +66 -0
- handoffkit-0.4.0/examples/tool_execution_demo.py +42 -0
- handoffkit-0.4.0/handoffkit/__init__.py +49 -0
- handoffkit-0.4.0/handoffkit/agent.py +323 -0
- handoffkit-0.4.0/handoffkit/context.py +182 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/handoff.py +3 -1
- handoffkit-0.4.0/handoffkit/memory.py +239 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/protocol.py +62 -60
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/protocols/hybrid_state.py +55 -52
- handoffkit-0.4.0/handoffkit/safety.py +33 -0
- handoffkit-0.4.0/handoffkit/tool_execution.py +211 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/tools/shell.py +38 -53
- handoffkit-0.4.0/handoffkit.egg-info/PKG-INFO +474 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit.egg-info/SOURCES.txt +11 -4
- {handoffkit-0.2.0 → handoffkit-0.4.0}/pyproject.toml +1 -1
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_cli.py +1 -1
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_contract_validation.py +2 -2
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_handoff.py +34 -32
- handoffkit-0.4.0/tests/test_imports.py +24 -0
- handoffkit-0.4.0/tests/test_memory_context.py +180 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_protocols.py +14 -0
- handoffkit-0.4.0/tests/test_tool_execution.py +194 -0
- handoffkit-0.2.0/PKG-INFO +0 -317
- handoffkit-0.2.0/README.md +0 -288
- handoffkit-0.2.0/examples/output/calculator_cli/README.md +0 -16
- handoffkit-0.2.0/examples/output/calculator_cli/calculator.py +0 -62
- handoffkit-0.2.0/examples/output/calculator_cli/test_calculator.py +0 -28
- handoffkit-0.2.0/handoffkit/__init__.py +0 -22
- handoffkit-0.2.0/handoffkit/agent.py +0 -91
- handoffkit-0.2.0/handoffkit/memory.py +0 -44
- handoffkit-0.2.0/handoffkit.egg-info/PKG-INFO +0 -317
- handoffkit-0.2.0/tests/test_imports.py +0 -7
- {handoffkit-0.2.0 → handoffkit-0.4.0}/LICENSE +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/coding_team.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/freemodel_best_model_demo.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/freemodel_coding_team.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/freemodel_openai_compatible.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/handoff_demo.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/ollama_agent.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/real_task_calculator.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/repo_inspired_protocols.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/simple_agent.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/tool_agent.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/examples/tool_schema_demo.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/cli.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/errors.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/protocols/__init__.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/protocols/compressed.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/protocols/hybrid_min.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/protocols/natural.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/providers/__init__.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/providers/base.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/providers/echo_provider.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/providers/ollama_provider.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/providers/openai_compatible.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/providers/openai_provider.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/py.typed +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/runner.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/schemas.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/tool.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/tools/__init__.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/tools/filesystem.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit/tools/text.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit.egg-info/dependency_links.txt +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit.egg-info/entry_points.txt +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit.egg-info/requires.txt +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/handoffkit.egg-info/top_level.txt +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/setup.cfg +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_agent.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_coding_team.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_ollama_provider_mock.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_openai_model_selection.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_openai_provider_mock.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_real_task_demo.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_shell_safety.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_team.py +0 -0
- {handoffkit-0.2.0 → handoffkit-0.4.0}/tests/test_tool.py +0 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: handoffkit
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A lightweight Python framework for building multi-agent workflows with structured state transfer protocols.
|
|
5
|
+
Author: DaosPath
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/DaosPath/handoffkit
|
|
8
|
+
Project-URL: Source, https://github.com/DaosPath/handoffkit
|
|
9
|
+
Project-URL: Issues, https://github.com/DaosPath/handoffkit/issues
|
|
10
|
+
Keywords: agents,handoff,multi-agent,state-transfer,protocols,ai
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff>=0.8.0; extra == "dev"
|
|
27
|
+
Requires-Dist: twine>=6.0.0; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
<div align="center">
|
|
31
|
+
|
|
32
|
+
# HandoffKit
|
|
33
|
+
|
|
34
|
+
**Structured state transfer for multi-agent Python workflows.**
|
|
35
|
+
|
|
36
|
+
Build agent chains where each agent receives a clear contract: task, decisions,
|
|
37
|
+
files, errors, next steps, and metadata. No messy context soup.
|
|
38
|
+
|
|
39
|
+
[](https://github.com/DaosPath/handoffkit/actions/workflows/ci.yml)
|
|
40
|
+
[](https://pypi.org/project/handoffkit/)
|
|
41
|
+

|
|
42
|
+

|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install handoffkit
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## What It Is
|
|
53
|
+
|
|
54
|
+
HandoffKit is a lightweight Python framework for building multi-agent AI
|
|
55
|
+
workflows where agents pass **structured state** instead of free-text summaries.
|
|
56
|
+
|
|
57
|
+
Most multi-agent demos do this:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
Agent A -> "Here is roughly what happened..." -> Agent B
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
HandoffKit does this:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
Architect
|
|
67
|
+
task: "Build a calculator CLI"
|
|
68
|
+
decisions: ["Use argparse", "Keep operations pure"]
|
|
69
|
+
files: ["calculator.py", "test_calculator.py"]
|
|
70
|
+
next_steps: ["Implement CLI", "Run pytest"]
|
|
71
|
+
|
|
|
72
|
+
v
|
|
73
|
+
Coder
|
|
74
|
+
receives HandoffState, not a vague paragraph
|
|
75
|
+
|
|
|
76
|
+
v
|
|
77
|
+
Tester
|
|
78
|
+
receives decisions, files, errors, and test evidence
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
That makes agent workflows easier to inspect, test, replay, and improve.
|
|
82
|
+
|
|
83
|
+
## What 0.4.0 Adds
|
|
84
|
+
|
|
85
|
+
HandoffKit 0.4.0 adds a lightweight memory and project context engine:
|
|
86
|
+
|
|
87
|
+
- `MemoryItem`, `MemoryStore`, and `JsonMemoryStore` for structured memory,
|
|
88
|
+
- `ProjectIndexer` for scanning local project files,
|
|
89
|
+
- `ContextRetriever` for deterministic keyword retrieval,
|
|
90
|
+
- `ContextPack` for bundling relevant files and memories,
|
|
91
|
+
- `Agent.run_with_context()` for context-aware agent runs,
|
|
92
|
+
- `HandoffState.context_refs` so agents can pass explicit context references.
|
|
93
|
+
|
|
94
|
+
No vector database. No heavy dependency stack. Just transparent, inspectable
|
|
95
|
+
context for agent workflows.
|
|
96
|
+
|
|
97
|
+
## What 0.3.0 Added
|
|
98
|
+
|
|
99
|
+
HandoffKit 0.3.0 adds a real tool execution loop:
|
|
100
|
+
|
|
101
|
+
- `ToolCall` and `ToolResult` models,
|
|
102
|
+
- `ToolRegistry` for registering and executing tools by name,
|
|
103
|
+
- `Agent.run_with_tools()` for structured tool loops,
|
|
104
|
+
- deterministic local tool execution with `EchoProvider`,
|
|
105
|
+
- provider JSON tool-call mode for fake or real providers,
|
|
106
|
+
- basic safety checks for shell and write operations,
|
|
107
|
+
- `ToolExecutionReport` with JSON and Markdown export.
|
|
108
|
+
|
|
109
|
+
## Why HandoffKit?
|
|
110
|
+
|
|
111
|
+
Multi-agent systems break when context handoffs are vague. One agent makes a
|
|
112
|
+
decision, another agent never sees it. One agent finds an error, the next agent
|
|
113
|
+
gets only a polished summary. Files, constraints, and validation evidence vanish.
|
|
114
|
+
|
|
115
|
+
HandoffKit gives you:
|
|
116
|
+
|
|
117
|
+
- `Agent`: a small role-based agent abstraction.
|
|
118
|
+
- `HandoffState`: a JSON-friendly contract between agents.
|
|
119
|
+
- `HandoffProtocol`: protocol modes for different transfer styles.
|
|
120
|
+
- `Team`: sequential multi-agent execution.
|
|
121
|
+
- `tool`: typed Python tools with schema metadata.
|
|
122
|
+
- `EchoProvider`: deterministic local provider for tests and demos.
|
|
123
|
+
- `OllamaProvider`: local Ollama integration.
|
|
124
|
+
- `OpenAIProvider`: OpenAI and OpenAI-compatible APIs.
|
|
125
|
+
|
|
126
|
+
## Core Concept
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from handoffkit import Agent, HandoffProtocol
|
|
130
|
+
|
|
131
|
+
architect = Agent("Architect", "Create implementation plans.")
|
|
132
|
+
coder = Agent("Coder", "Implement from structured handoff state.")
|
|
133
|
+
|
|
134
|
+
protocol = HandoffProtocol(mode="hybrid_state")
|
|
135
|
+
|
|
136
|
+
state = protocol.transfer(
|
|
137
|
+
from_agent=architect,
|
|
138
|
+
to_agent=coder,
|
|
139
|
+
task="Create a small Python CLI calculator with tests.",
|
|
140
|
+
summary="Build a dependency-free CLI with pytest coverage.",
|
|
141
|
+
decisions=["Use argparse.", "Keep calculator operations pure."],
|
|
142
|
+
important_files=["calculator.py", "test_calculator.py"],
|
|
143
|
+
next_steps=["Implement code.", "Run pytest."],
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
state.validate()
|
|
147
|
+
print(state.to_json())
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Protocols
|
|
151
|
+
|
|
152
|
+
| Mode | What it passes | Best for |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `natural` | Human-readable summary | Simple demos and debugging |
|
|
155
|
+
| `compressed` | Compact summary | Token-sensitive transfers |
|
|
156
|
+
| `hybrid_min` | Task, summary, next steps | Lightweight structured chains |
|
|
157
|
+
| `hybrid_state` | Full state contract | Replayable, testable workflows |
|
|
158
|
+
|
|
159
|
+
## Quickstart
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from handoffkit import Agent
|
|
163
|
+
|
|
164
|
+
agent = Agent(
|
|
165
|
+
name="Planner",
|
|
166
|
+
role="Create concise implementation plans.",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
print(agent.run("Create a plan for a Python CLI app with tests."))
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
No API key required. By default, HandoffKit uses `EchoProvider`, so examples and
|
|
173
|
+
tests run locally and deterministically.
|
|
174
|
+
|
|
175
|
+
## Tool Schema Example
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from handoffkit import tool
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@tool
|
|
182
|
+
def add(a: int, b: int) -> int:
|
|
183
|
+
"""Add two numbers."""
|
|
184
|
+
return a + b
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
print(add.to_schema())
|
|
188
|
+
print(add.run(a=2, b=3))
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Output:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
{
|
|
195
|
+
"name": "add",
|
|
196
|
+
"description": "Add two numbers.",
|
|
197
|
+
"parameters": {
|
|
198
|
+
"type": "object",
|
|
199
|
+
"properties": {
|
|
200
|
+
"a": {"type": "integer"},
|
|
201
|
+
"b": {"type": "integer"},
|
|
202
|
+
},
|
|
203
|
+
"required": ["a", "b"],
|
|
204
|
+
},
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Tool Execution Loop
|
|
209
|
+
|
|
210
|
+
Register Python tools, let an agent create structured `ToolCall` objects, execute
|
|
211
|
+
them through a `ToolRegistry`, and receive structured `ToolResult` objects.
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from handoffkit import Agent
|
|
215
|
+
from handoffkit.tools.filesystem import list_files, read_file
|
|
216
|
+
|
|
217
|
+
agent = Agent(
|
|
218
|
+
name="FileAgent",
|
|
219
|
+
role="Use tools to inspect files.",
|
|
220
|
+
tools=[read_file, list_files],
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
result = agent.run_with_tools("read file README.md")
|
|
224
|
+
print(result.final_output)
|
|
225
|
+
print(result.tool_results)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
There are two modes:
|
|
229
|
+
|
|
230
|
+
- **Deterministic/local mode**: with `EchoProvider`, HandoffKit handles simple
|
|
231
|
+
tasks such as `read file README.md`, `list files .`, `write file ...`, or
|
|
232
|
+
`run command ...`. This is honest local automation, not hidden AI reasoning.
|
|
233
|
+
- **Provider JSON mode**: if a provider returns JSON with `tool_calls`,
|
|
234
|
+
HandoffKit executes those tools and feeds results into the next step until the
|
|
235
|
+
provider returns `{"final": "..."}` or `max_steps` is reached.
|
|
236
|
+
|
|
237
|
+
Provider tool-call JSON:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"tool_calls": [
|
|
242
|
+
{
|
|
243
|
+
"tool_name": "read_file",
|
|
244
|
+
"arguments": {
|
|
245
|
+
"path": "README.md"
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
"final": null
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Safety:
|
|
254
|
+
|
|
255
|
+
- dangerous shell commands such as `rm -rf`, `del /s`, `format`, `shutdown`,
|
|
256
|
+
`reboot`, `mkfs`, and `diskpart` are blocked;
|
|
257
|
+
- when `require_approval=True`, write and shell tools return
|
|
258
|
+
`approval_required` instead of executing.
|
|
259
|
+
|
|
260
|
+
## Memory + Project Context
|
|
261
|
+
|
|
262
|
+
HandoffKit can store durable project decisions, index local files, retrieve
|
|
263
|
+
relevant context, and hand explicit references from one agent to the next.
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
from handoffkit import (
|
|
267
|
+
Agent,
|
|
268
|
+
ContextPack,
|
|
269
|
+
ContextRetriever,
|
|
270
|
+
JsonMemoryStore,
|
|
271
|
+
ProjectIndexer,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
memory = JsonMemoryStore("examples/output/memory.json")
|
|
275
|
+
memory.add(
|
|
276
|
+
"Calculator CLI should use argparse and pure functions.",
|
|
277
|
+
kind="decision",
|
|
278
|
+
tags=["calculator", "cli"],
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
documents = ProjectIndexer(".").index()
|
|
282
|
+
retriever = ContextRetriever(documents)
|
|
283
|
+
matches = retriever.search("calculator argparse tests", limit=3)
|
|
284
|
+
|
|
285
|
+
context = ContextPack(
|
|
286
|
+
query="Create a calculator CLI implementation plan.",
|
|
287
|
+
documents=matches,
|
|
288
|
+
memories=memory.search("calculator cli", limit=3),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
agent = Agent("Architect", "Create concise implementation plans.")
|
|
292
|
+
result = agent.run_with_context(
|
|
293
|
+
"Create a concise architecture plan for a Python CLI calculator.",
|
|
294
|
+
context=context,
|
|
295
|
+
memory=memory,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
print(result.final_output)
|
|
299
|
+
print(context.to_markdown())
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Run the included demos:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
python examples/memory_demo.py
|
|
306
|
+
python examples/project_context_demo.py
|
|
307
|
+
python examples/context_handoff_demo.py
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Real Task Demo
|
|
311
|
+
|
|
312
|
+
HandoffKit includes a reproducible real task demo:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
python examples/real_task_calculator.py
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
It runs this workflow:
|
|
319
|
+
|
|
320
|
+
```text
|
|
321
|
+
Architect -> Coder -> Tester -> Reporter
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Task:
|
|
325
|
+
|
|
326
|
+
```text
|
|
327
|
+
Create a tiny Python CLI calculator with add, subtract, multiply and divide
|
|
328
|
+
operations, plus tests.
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
The demo creates a real generated project:
|
|
332
|
+
|
|
333
|
+
```text
|
|
334
|
+
examples/output/calculator_cli/
|
|
335
|
+
calculator.py
|
|
336
|
+
test_calculator.py
|
|
337
|
+
README.md
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
It also writes reproducibility reports:
|
|
341
|
+
|
|
342
|
+
```text
|
|
343
|
+
reports/real_task_calculator.md
|
|
344
|
+
reports/real_task_calculator.json
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
The generated project is tested with `pytest`, and the report captures command,
|
|
348
|
+
cwd, return code, stdout, stderr, files created, provider used, model used, and
|
|
349
|
+
handoff flow.
|
|
350
|
+
|
|
351
|
+
## Providers
|
|
352
|
+
|
|
353
|
+
### Local deterministic provider
|
|
354
|
+
|
|
355
|
+
```python
|
|
356
|
+
from handoffkit import Agent
|
|
357
|
+
|
|
358
|
+
agent = Agent("Planner", "Plan work.")
|
|
359
|
+
print(agent.run("Prepare a package release."))
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Ollama
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
ollama pull llama3.1
|
|
366
|
+
ollama serve
|
|
367
|
+
python examples/ollama_agent.py --model llama3.1
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### OpenAI-compatible APIs
|
|
371
|
+
|
|
372
|
+
```powershell
|
|
373
|
+
$env:OPENAI_API_KEY="..."
|
|
374
|
+
$env:OPENAI_BASE_URL="https://api.freemodel.dev/v1"
|
|
375
|
+
$env:OPENAI_MODEL="gpt-4o-mini"
|
|
376
|
+
python examples/freemodel_openai_compatible.py
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Optional real API tests are skipped unless explicitly enabled:
|
|
380
|
+
|
|
381
|
+
```powershell
|
|
382
|
+
$env:HANDOFFKIT_RUN_API_TESTS="1"
|
|
383
|
+
$env:OPENAI_API_KEY="..."
|
|
384
|
+
$env:OPENAI_BASE_URL="https://api.freemodel.dev/v1"
|
|
385
|
+
$env:OPENAI_MODEL="gpt-4o-mini"
|
|
386
|
+
pytest tests_api -q
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Use temporary or scoped provider tokens. Do not commit API keys.
|
|
390
|
+
|
|
391
|
+
## CLI
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
handoffkit --version
|
|
395
|
+
handoffkit demo
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Examples
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
python examples/simple_agent.py
|
|
402
|
+
python examples/handoff_demo.py
|
|
403
|
+
python examples/coding_team.py
|
|
404
|
+
python examples/tool_schema_demo.py
|
|
405
|
+
python examples/tool_execution_demo.py
|
|
406
|
+
python examples/fake_provider_tool_call_demo.py
|
|
407
|
+
python examples/memory_demo.py
|
|
408
|
+
python examples/project_context_demo.py
|
|
409
|
+
python examples/context_handoff_demo.py
|
|
410
|
+
python examples/real_task_calculator.py
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Development
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
git clone https://github.com/DaosPath/handoffkit.git
|
|
417
|
+
cd handoffkit
|
|
418
|
+
pip install -e ".[dev]"
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Run checks:
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
ruff check .
|
|
425
|
+
pytest -q
|
|
426
|
+
python -m build
|
|
427
|
+
python -m twine check dist/*
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Publishing
|
|
431
|
+
|
|
432
|
+
Build and validate:
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
python -m build
|
|
436
|
+
python -m twine check dist/*
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Upload to TestPyPI first:
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
python -m twine upload --repository testpypi dist/*
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Upload to PyPI only after TestPyPI install verification:
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
python -m twine upload dist/*
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Inspiration
|
|
452
|
+
|
|
453
|
+
HandoffKit is inspired by the research and reproducibility repository
|
|
454
|
+
[`DaosPath/state-transfer-protocols`](https://github.com/DaosPath/state-transfer-protocols),
|
|
455
|
+
especially its comparison of `natural`, `compressed`, `hybrid_min`, and
|
|
456
|
+
`hybrid_state` handoff protocols for multi-agent workflows.
|
|
457
|
+
|
|
458
|
+
HandoffKit is a developer library, not a copy of that repository.
|
|
459
|
+
|
|
460
|
+
## Roadmap
|
|
461
|
+
|
|
462
|
+
- richer contract validators,
|
|
463
|
+
- broader tool schema coverage,
|
|
464
|
+
- provider adapters,
|
|
465
|
+
- structured tool calling loops,
|
|
466
|
+
- handoff quality metrics,
|
|
467
|
+
- memory integrations,
|
|
468
|
+
- project context retrieval,
|
|
469
|
+
- benchmark-inspired examples,
|
|
470
|
+
- multi-agent workflow templates.
|
|
471
|
+
|
|
472
|
+
## License
|
|
473
|
+
|
|
474
|
+
MIT.
|