handoffkit 0.2.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.
Files changed (66) hide show
  1. handoffkit-0.2.0/LICENSE +21 -0
  2. handoffkit-0.2.0/MANIFEST.in +8 -0
  3. handoffkit-0.2.0/PKG-INFO +317 -0
  4. handoffkit-0.2.0/README.md +288 -0
  5. handoffkit-0.2.0/examples/coding_team.py +57 -0
  6. handoffkit-0.2.0/examples/freemodel_best_model_demo.py +57 -0
  7. handoffkit-0.2.0/examples/freemodel_coding_team.py +67 -0
  8. handoffkit-0.2.0/examples/freemodel_openai_compatible.py +32 -0
  9. handoffkit-0.2.0/examples/handoff_demo.py +36 -0
  10. handoffkit-0.2.0/examples/ollama_agent.py +51 -0
  11. handoffkit-0.2.0/examples/output/calculator_cli/README.md +16 -0
  12. handoffkit-0.2.0/examples/output/calculator_cli/calculator.py +62 -0
  13. handoffkit-0.2.0/examples/output/calculator_cli/test_calculator.py +28 -0
  14. handoffkit-0.2.0/examples/real_task_calculator.py +533 -0
  15. handoffkit-0.2.0/examples/repo_inspired_protocols.py +20 -0
  16. handoffkit-0.2.0/examples/simple_agent.py +17 -0
  17. handoffkit-0.2.0/examples/tool_agent.py +19 -0
  18. handoffkit-0.2.0/examples/tool_schema_demo.py +19 -0
  19. handoffkit-0.2.0/handoffkit/__init__.py +22 -0
  20. handoffkit-0.2.0/handoffkit/agent.py +91 -0
  21. handoffkit-0.2.0/handoffkit/cli.py +49 -0
  22. handoffkit-0.2.0/handoffkit/errors.py +33 -0
  23. handoffkit-0.2.0/handoffkit/handoff.py +86 -0
  24. handoffkit-0.2.0/handoffkit/memory.py +44 -0
  25. handoffkit-0.2.0/handoffkit/protocol.py +60 -0
  26. handoffkit-0.2.0/handoffkit/protocols/__init__.py +5 -0
  27. handoffkit-0.2.0/handoffkit/protocols/compressed.py +31 -0
  28. handoffkit-0.2.0/handoffkit/protocols/hybrid_min.py +17 -0
  29. handoffkit-0.2.0/handoffkit/protocols/hybrid_state.py +52 -0
  30. handoffkit-0.2.0/handoffkit/protocols/natural.py +22 -0
  31. handoffkit-0.2.0/handoffkit/providers/__init__.py +21 -0
  32. handoffkit-0.2.0/handoffkit/providers/base.py +16 -0
  33. handoffkit-0.2.0/handoffkit/providers/echo_provider.py +26 -0
  34. handoffkit-0.2.0/handoffkit/providers/ollama_provider.py +48 -0
  35. handoffkit-0.2.0/handoffkit/providers/openai_compatible.py +140 -0
  36. handoffkit-0.2.0/handoffkit/providers/openai_provider.py +80 -0
  37. handoffkit-0.2.0/handoffkit/py.typed +1 -0
  38. handoffkit-0.2.0/handoffkit/runner.py +51 -0
  39. handoffkit-0.2.0/handoffkit/schemas.py +45 -0
  40. handoffkit-0.2.0/handoffkit/tool.py +196 -0
  41. handoffkit-0.2.0/handoffkit/tools/__init__.py +15 -0
  42. handoffkit-0.2.0/handoffkit/tools/filesystem.py +34 -0
  43. handoffkit-0.2.0/handoffkit/tools/shell.py +53 -0
  44. handoffkit-0.2.0/handoffkit/tools/text.py +54 -0
  45. handoffkit-0.2.0/handoffkit.egg-info/PKG-INFO +317 -0
  46. handoffkit-0.2.0/handoffkit.egg-info/SOURCES.txt +64 -0
  47. handoffkit-0.2.0/handoffkit.egg-info/dependency_links.txt +1 -0
  48. handoffkit-0.2.0/handoffkit.egg-info/entry_points.txt +2 -0
  49. handoffkit-0.2.0/handoffkit.egg-info/requires.txt +6 -0
  50. handoffkit-0.2.0/handoffkit.egg-info/top_level.txt +1 -0
  51. handoffkit-0.2.0/pyproject.toml +66 -0
  52. handoffkit-0.2.0/setup.cfg +4 -0
  53. handoffkit-0.2.0/tests/test_agent.py +19 -0
  54. handoffkit-0.2.0/tests/test_cli.py +30 -0
  55. handoffkit-0.2.0/tests/test_coding_team.py +37 -0
  56. handoffkit-0.2.0/tests/test_contract_validation.py +58 -0
  57. handoffkit-0.2.0/tests/test_handoff.py +32 -0
  58. handoffkit-0.2.0/tests/test_imports.py +7 -0
  59. handoffkit-0.2.0/tests/test_ollama_provider_mock.py +53 -0
  60. handoffkit-0.2.0/tests/test_openai_model_selection.py +82 -0
  61. handoffkit-0.2.0/tests/test_openai_provider_mock.py +88 -0
  62. handoffkit-0.2.0/tests/test_protocols.py +90 -0
  63. handoffkit-0.2.0/tests/test_real_task_demo.py +58 -0
  64. handoffkit-0.2.0/tests/test_shell_safety.py +16 -0
  65. handoffkit-0.2.0/tests/test_team.py +30 -0
  66. handoffkit-0.2.0/tests/test_tool.py +70 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DaosPath
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,8 @@
1
+ include README.md
2
+ include LICENSE
3
+ graft examples
4
+ graft tests
5
+ global-exclude __pycache__
6
+ global-exclude __pycache__/*
7
+ global-exclude *.py[cod]
8
+ global-exclude *.pyc.*
@@ -0,0 +1,317 @@
1
+ Metadata-Version: 2.4
2
+ Name: handoffkit
3
+ Version: 0.2.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
+ # HandoffKit
31
+
32
+ [![Tests](https://github.com/DaosPath/handoffkit/actions/workflows/ci.yml/badge.svg)](https://github.com/DaosPath/handoffkit/actions/workflows/ci.yml)
33
+ ![Python versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)
34
+ ![Package version](https://img.shields.io/badge/version-0.2.0-blue)
35
+ ![License](https://img.shields.io/badge/license-MIT-green)
36
+
37
+ HandoffKit helps developers build reliable multi-agent AI workflows by letting agents transfer structured state instead of messy free-text context.
38
+
39
+ ## What Problem It Solves
40
+
41
+ Multi-agent systems often lose useful context at the exact moment one agent hands work to another. A prose summary may omit files, decisions, constraints, errors, and next steps. That makes workflows hard to test, replay, inspect, and improve.
42
+
43
+ HandoffKit gives you a small Python API for making those handoffs explicit:
44
+
45
+ - agents run with pluggable providers,
46
+ - tools expose metadata and JSON-schema-style parameter schemas,
47
+ - handoffs move through `HandoffState`,
48
+ - protocols choose how much state to preserve,
49
+ - team workflows can be tested locally with no API key.
50
+
51
+ ## Why HandoffKit Exists
52
+
53
+ Most agent demos pass free text between roles. Real workflows need a clearer contract. HandoffKit is intentionally lightweight: it does not try to be a full orchestration platform, but it gives developers reliable primitives for state transfer, tool description, and sequential agent collaboration.
54
+
55
+ The default `EchoProvider` makes examples and tests deterministic. You can later swap in providers such as Ollama or OpenAI.
56
+
57
+ ## Installation
58
+
59
+ From PyPI after publication:
60
+
61
+ ```bash
62
+ pip install handoffkit
63
+ ```
64
+
65
+ For local development:
66
+
67
+ ```bash
68
+ pip install -e ".[dev]"
69
+ ```
70
+
71
+ ## Quickstart
72
+
73
+ ```python
74
+ from handoffkit import Agent
75
+
76
+ agent = Agent(
77
+ name="Planner",
78
+ role="Create concise implementation plans."
79
+ )
80
+
81
+ print(agent.run("Create a plan for a Python CLI app with tests."))
82
+ ```
83
+
84
+ No provider is required for local demos. If none is configured, HandoffKit uses `EchoProvider`.
85
+
86
+ ## Tool Schema Example
87
+
88
+ ```python
89
+ from handoffkit import tool
90
+
91
+
92
+ @tool
93
+ def add(a: int, b: int) -> int:
94
+ """Add two numbers."""
95
+ return a + b
96
+
97
+
98
+ print(add.to_schema())
99
+ print(add.run(a=2, b=3))
100
+ ```
101
+
102
+ Schema output:
103
+
104
+ ```python
105
+ {
106
+ "name": "add",
107
+ "description": "Add two numbers.",
108
+ "parameters": {
109
+ "type": "object",
110
+ "properties": {
111
+ "a": {"type": "integer"},
112
+ "b": {"type": "integer"},
113
+ },
114
+ "required": ["a", "b"],
115
+ },
116
+ }
117
+ ```
118
+
119
+ Supported schema types include `str`, `int`, `float`, `bool`, `list`, and `dict`.
120
+
121
+ ## HandoffState Example
122
+
123
+ ```python
124
+ from handoffkit import HandoffState
125
+
126
+ state = HandoffState(
127
+ task="Prepare a Python package for release.",
128
+ from_agent="Architect",
129
+ to_agent="Coder",
130
+ summary="Package needs tests, CI, and metadata validation.",
131
+ decisions=["Keep runtime dependencies empty."],
132
+ important_files=["pyproject.toml", "README.md"],
133
+ errors=[],
134
+ next_steps=["Run pytest.", "Build wheel.", "Run twine check."],
135
+ metadata={"mode": "hybrid_state"},
136
+ )
137
+
138
+ state.validate()
139
+ print(state.to_json())
140
+ ```
141
+
142
+ `validate()` raises `HandoffValidationError` when required fields are empty or state fields have the wrong shape.
143
+
144
+ ## Protocol Comparison
145
+
146
+ HandoffKit ships four protocol modes:
147
+
148
+ | Mode | Shape | Use case |
149
+ |---|---|---|
150
+ | `natural` | Human-readable handoff summary | Debugging and simple collaboration |
151
+ | `compressed` | Short compact summary | Token-sensitive handoffs |
152
+ | `hybrid_min` | Task, summary, next steps | Minimal structured transfer |
153
+ | `hybrid_state` | Full state with decisions, files, errors, metadata | Workflows that need replayable state |
154
+
155
+ ```python
156
+ from handoffkit import Agent, HandoffProtocol
157
+
158
+ architect = Agent("Architect", "Create technical plans.")
159
+ coder = Agent("Coder", "Implement from handoff state.")
160
+
161
+ protocol = HandoffProtocol(mode="hybrid_state")
162
+ state = protocol.transfer(
163
+ from_agent=architect,
164
+ to_agent=coder,
165
+ task="Prepare a package release.",
166
+ summary="Use typed package metadata, tests, CI, and twine validation.",
167
+ decisions=["Keep package runtime dependency-free."],
168
+ important_files=["pyproject.toml", "README.md"],
169
+ next_steps=["Implement changes.", "Run pytest and twine check."],
170
+ )
171
+
172
+ print(state.to_json())
173
+ ```
174
+
175
+ ## Architect -> Coder -> Tester Example
176
+
177
+ Run the local example:
178
+
179
+ ```bash
180
+ python examples/coding_team.py
181
+ ```
182
+
183
+ The example shows:
184
+
185
+ 1. Architect receives a task.
186
+ 2. Architect produces decisions and next steps.
187
+ 3. Coder receives `HandoffState`.
188
+ 4. Coder produces simulated implementation output.
189
+ 5. Tester receives state from Coder.
190
+ 6. Tester produces a final result.
191
+
192
+ It runs without an API key using `EchoProvider`.
193
+
194
+ ## Real Task Demo
195
+
196
+ Run a reproducible multi-agent task that generates a tiny calculator CLI, tests it,
197
+ and writes Markdown and JSON evidence:
198
+
199
+ ```bash
200
+ python examples/real_task_calculator.py
201
+ ```
202
+
203
+ The demo creates:
204
+
205
+ - `examples/output/calculator_cli/calculator.py`
206
+ - `examples/output/calculator_cli/test_calculator.py`
207
+ - `examples/output/calculator_cli/README.md`
208
+ - `reports/real_task_calculator.md`
209
+ - `reports/real_task_calculator.json`
210
+
211
+ It uses `EchoProvider` by default, so it works without network access. If
212
+ `OPENAI_API_KEY` is configured, it tries an OpenAI-compatible provider through
213
+ `OPENAI_BASE_URL` and prefers `gpt-5.4` before falling back to `gpt-4o-mini`.
214
+
215
+ ## Providers
216
+
217
+ Built-in providers:
218
+
219
+ - `EchoProvider`: deterministic local responses for tests and examples.
220
+ - `OllamaProvider`: calls a local Ollama server.
221
+ - `OpenAIProvider`: calls the OpenAI API when configured.
222
+
223
+ Ollama example:
224
+
225
+ ```bash
226
+ ollama pull llama3.1
227
+ ollama serve
228
+ python examples/ollama_agent.py --model llama3.1
229
+ ```
230
+
231
+ OpenAI usage requires `OPENAI_API_KEY` in your environment.
232
+
233
+ ## OpenAI-compatible Providers
234
+
235
+ `OpenAIProvider` can call OpenAI-compatible chat-completions APIs by setting a custom base URL and model.
236
+
237
+ PowerShell example:
238
+
239
+ ```powershell
240
+ $env:OPENAI_API_KEY="..."
241
+ $env:OPENAI_BASE_URL="https://api.freemodel.dev/v1"
242
+ $env:OPENAI_MODEL="gpt-4o-mini"
243
+ python examples/freemodel_openai_compatible.py
244
+ ```
245
+
246
+ Optional real API tests are skipped unless explicitly enabled:
247
+
248
+ ```powershell
249
+ $env:HANDOFFKIT_RUN_API_TESTS="1"
250
+ $env:OPENAI_API_KEY="..."
251
+ $env:OPENAI_BASE_URL="https://api.freemodel.dev/v1"
252
+ $env:OPENAI_MODEL="gpt-4o-mini"
253
+ pytest tests_api -q
254
+ ```
255
+
256
+ Use a temporary or scoped token for provider experiments. Do not commit API keys.
257
+
258
+ ## Development
259
+
260
+ Install development dependencies:
261
+
262
+ ```bash
263
+ pip install -e ".[dev]"
264
+ ```
265
+
266
+ Run checks:
267
+
268
+ ```bash
269
+ ruff check .
270
+ pytest -q
271
+ python -m build
272
+ python -m twine check dist/*
273
+ ```
274
+
275
+ Useful CLI commands:
276
+
277
+ ```bash
278
+ handoffkit --version
279
+ handoffkit demo
280
+ ```
281
+
282
+ ## Publishing
283
+
284
+ Validate before publishing:
285
+
286
+ ```bash
287
+ pytest -q
288
+ python -m build
289
+ python -m twine check dist/*
290
+ ```
291
+
292
+ Publish only after validating the target repository and token:
293
+
294
+ ```bash
295
+ python -m twine upload dist/*
296
+ ```
297
+
298
+ ## Inspiration
299
+
300
+ This package is inspired by the research and reproducibility repository [`DaosPath/state-transfer-protocols`](https://github.com/DaosPath/state-transfer-protocols), especially its comparison of `natural`, `compressed`, `hybrid_min`, and `hybrid_state` handoff protocols for multilingual multi-agent workflows.
301
+
302
+ HandoffKit is a developer library, not a copy of that repository.
303
+
304
+ ## Roadmap
305
+
306
+ - richer contract validators,
307
+ - better tool schema coverage,
308
+ - provider adapters,
309
+ - structured tool calling loops,
310
+ - handoff quality metrics,
311
+ - memory integrations,
312
+ - benchmark-inspired examples,
313
+ - multi-agent workflow templates.
314
+
315
+ ## License
316
+
317
+ MIT.
@@ -0,0 +1,288 @@
1
+ # HandoffKit
2
+
3
+ [![Tests](https://github.com/DaosPath/handoffkit/actions/workflows/ci.yml/badge.svg)](https://github.com/DaosPath/handoffkit/actions/workflows/ci.yml)
4
+ ![Python versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)
5
+ ![Package version](https://img.shields.io/badge/version-0.2.0-blue)
6
+ ![License](https://img.shields.io/badge/license-MIT-green)
7
+
8
+ HandoffKit helps developers build reliable multi-agent AI workflows by letting agents transfer structured state instead of messy free-text context.
9
+
10
+ ## What Problem It Solves
11
+
12
+ Multi-agent systems often lose useful context at the exact moment one agent hands work to another. A prose summary may omit files, decisions, constraints, errors, and next steps. That makes workflows hard to test, replay, inspect, and improve.
13
+
14
+ HandoffKit gives you a small Python API for making those handoffs explicit:
15
+
16
+ - agents run with pluggable providers,
17
+ - tools expose metadata and JSON-schema-style parameter schemas,
18
+ - handoffs move through `HandoffState`,
19
+ - protocols choose how much state to preserve,
20
+ - team workflows can be tested locally with no API key.
21
+
22
+ ## Why HandoffKit Exists
23
+
24
+ Most agent demos pass free text between roles. Real workflows need a clearer contract. HandoffKit is intentionally lightweight: it does not try to be a full orchestration platform, but it gives developers reliable primitives for state transfer, tool description, and sequential agent collaboration.
25
+
26
+ The default `EchoProvider` makes examples and tests deterministic. You can later swap in providers such as Ollama or OpenAI.
27
+
28
+ ## Installation
29
+
30
+ From PyPI after publication:
31
+
32
+ ```bash
33
+ pip install handoffkit
34
+ ```
35
+
36
+ For local development:
37
+
38
+ ```bash
39
+ pip install -e ".[dev]"
40
+ ```
41
+
42
+ ## Quickstart
43
+
44
+ ```python
45
+ from handoffkit import Agent
46
+
47
+ agent = Agent(
48
+ name="Planner",
49
+ role="Create concise implementation plans."
50
+ )
51
+
52
+ print(agent.run("Create a plan for a Python CLI app with tests."))
53
+ ```
54
+
55
+ No provider is required for local demos. If none is configured, HandoffKit uses `EchoProvider`.
56
+
57
+ ## Tool Schema Example
58
+
59
+ ```python
60
+ from handoffkit import tool
61
+
62
+
63
+ @tool
64
+ def add(a: int, b: int) -> int:
65
+ """Add two numbers."""
66
+ return a + b
67
+
68
+
69
+ print(add.to_schema())
70
+ print(add.run(a=2, b=3))
71
+ ```
72
+
73
+ Schema output:
74
+
75
+ ```python
76
+ {
77
+ "name": "add",
78
+ "description": "Add two numbers.",
79
+ "parameters": {
80
+ "type": "object",
81
+ "properties": {
82
+ "a": {"type": "integer"},
83
+ "b": {"type": "integer"},
84
+ },
85
+ "required": ["a", "b"],
86
+ },
87
+ }
88
+ ```
89
+
90
+ Supported schema types include `str`, `int`, `float`, `bool`, `list`, and `dict`.
91
+
92
+ ## HandoffState Example
93
+
94
+ ```python
95
+ from handoffkit import HandoffState
96
+
97
+ state = HandoffState(
98
+ task="Prepare a Python package for release.",
99
+ from_agent="Architect",
100
+ to_agent="Coder",
101
+ summary="Package needs tests, CI, and metadata validation.",
102
+ decisions=["Keep runtime dependencies empty."],
103
+ important_files=["pyproject.toml", "README.md"],
104
+ errors=[],
105
+ next_steps=["Run pytest.", "Build wheel.", "Run twine check."],
106
+ metadata={"mode": "hybrid_state"},
107
+ )
108
+
109
+ state.validate()
110
+ print(state.to_json())
111
+ ```
112
+
113
+ `validate()` raises `HandoffValidationError` when required fields are empty or state fields have the wrong shape.
114
+
115
+ ## Protocol Comparison
116
+
117
+ HandoffKit ships four protocol modes:
118
+
119
+ | Mode | Shape | Use case |
120
+ |---|---|---|
121
+ | `natural` | Human-readable handoff summary | Debugging and simple collaboration |
122
+ | `compressed` | Short compact summary | Token-sensitive handoffs |
123
+ | `hybrid_min` | Task, summary, next steps | Minimal structured transfer |
124
+ | `hybrid_state` | Full state with decisions, files, errors, metadata | Workflows that need replayable state |
125
+
126
+ ```python
127
+ from handoffkit import Agent, HandoffProtocol
128
+
129
+ architect = Agent("Architect", "Create technical plans.")
130
+ coder = Agent("Coder", "Implement from handoff state.")
131
+
132
+ protocol = HandoffProtocol(mode="hybrid_state")
133
+ state = protocol.transfer(
134
+ from_agent=architect,
135
+ to_agent=coder,
136
+ task="Prepare a package release.",
137
+ summary="Use typed package metadata, tests, CI, and twine validation.",
138
+ decisions=["Keep package runtime dependency-free."],
139
+ important_files=["pyproject.toml", "README.md"],
140
+ next_steps=["Implement changes.", "Run pytest and twine check."],
141
+ )
142
+
143
+ print(state.to_json())
144
+ ```
145
+
146
+ ## Architect -> Coder -> Tester Example
147
+
148
+ Run the local example:
149
+
150
+ ```bash
151
+ python examples/coding_team.py
152
+ ```
153
+
154
+ The example shows:
155
+
156
+ 1. Architect receives a task.
157
+ 2. Architect produces decisions and next steps.
158
+ 3. Coder receives `HandoffState`.
159
+ 4. Coder produces simulated implementation output.
160
+ 5. Tester receives state from Coder.
161
+ 6. Tester produces a final result.
162
+
163
+ It runs without an API key using `EchoProvider`.
164
+
165
+ ## Real Task Demo
166
+
167
+ Run a reproducible multi-agent task that generates a tiny calculator CLI, tests it,
168
+ and writes Markdown and JSON evidence:
169
+
170
+ ```bash
171
+ python examples/real_task_calculator.py
172
+ ```
173
+
174
+ The demo creates:
175
+
176
+ - `examples/output/calculator_cli/calculator.py`
177
+ - `examples/output/calculator_cli/test_calculator.py`
178
+ - `examples/output/calculator_cli/README.md`
179
+ - `reports/real_task_calculator.md`
180
+ - `reports/real_task_calculator.json`
181
+
182
+ It uses `EchoProvider` by default, so it works without network access. If
183
+ `OPENAI_API_KEY` is configured, it tries an OpenAI-compatible provider through
184
+ `OPENAI_BASE_URL` and prefers `gpt-5.4` before falling back to `gpt-4o-mini`.
185
+
186
+ ## Providers
187
+
188
+ Built-in providers:
189
+
190
+ - `EchoProvider`: deterministic local responses for tests and examples.
191
+ - `OllamaProvider`: calls a local Ollama server.
192
+ - `OpenAIProvider`: calls the OpenAI API when configured.
193
+
194
+ Ollama example:
195
+
196
+ ```bash
197
+ ollama pull llama3.1
198
+ ollama serve
199
+ python examples/ollama_agent.py --model llama3.1
200
+ ```
201
+
202
+ OpenAI usage requires `OPENAI_API_KEY` in your environment.
203
+
204
+ ## OpenAI-compatible Providers
205
+
206
+ `OpenAIProvider` can call OpenAI-compatible chat-completions APIs by setting a custom base URL and model.
207
+
208
+ PowerShell example:
209
+
210
+ ```powershell
211
+ $env:OPENAI_API_KEY="..."
212
+ $env:OPENAI_BASE_URL="https://api.freemodel.dev/v1"
213
+ $env:OPENAI_MODEL="gpt-4o-mini"
214
+ python examples/freemodel_openai_compatible.py
215
+ ```
216
+
217
+ Optional real API tests are skipped unless explicitly enabled:
218
+
219
+ ```powershell
220
+ $env:HANDOFFKIT_RUN_API_TESTS="1"
221
+ $env:OPENAI_API_KEY="..."
222
+ $env:OPENAI_BASE_URL="https://api.freemodel.dev/v1"
223
+ $env:OPENAI_MODEL="gpt-4o-mini"
224
+ pytest tests_api -q
225
+ ```
226
+
227
+ Use a temporary or scoped token for provider experiments. Do not commit API keys.
228
+
229
+ ## Development
230
+
231
+ Install development dependencies:
232
+
233
+ ```bash
234
+ pip install -e ".[dev]"
235
+ ```
236
+
237
+ Run checks:
238
+
239
+ ```bash
240
+ ruff check .
241
+ pytest -q
242
+ python -m build
243
+ python -m twine check dist/*
244
+ ```
245
+
246
+ Useful CLI commands:
247
+
248
+ ```bash
249
+ handoffkit --version
250
+ handoffkit demo
251
+ ```
252
+
253
+ ## Publishing
254
+
255
+ Validate before publishing:
256
+
257
+ ```bash
258
+ pytest -q
259
+ python -m build
260
+ python -m twine check dist/*
261
+ ```
262
+
263
+ Publish only after validating the target repository and token:
264
+
265
+ ```bash
266
+ python -m twine upload dist/*
267
+ ```
268
+
269
+ ## Inspiration
270
+
271
+ This package is inspired by the research and reproducibility repository [`DaosPath/state-transfer-protocols`](https://github.com/DaosPath/state-transfer-protocols), especially its comparison of `natural`, `compressed`, `hybrid_min`, and `hybrid_state` handoff protocols for multilingual multi-agent workflows.
272
+
273
+ HandoffKit is a developer library, not a copy of that repository.
274
+
275
+ ## Roadmap
276
+
277
+ - richer contract validators,
278
+ - better tool schema coverage,
279
+ - provider adapters,
280
+ - structured tool calling loops,
281
+ - handoff quality metrics,
282
+ - memory integrations,
283
+ - benchmark-inspired examples,
284
+ - multi-agent workflow templates.
285
+
286
+ ## License
287
+
288
+ MIT.
@@ -0,0 +1,57 @@
1
+ """Architect -> Coder -> Tester structured handoff demo.
2
+
3
+ This example runs fully locally with EchoProvider. It shows the state passed
4
+ between agents instead of hiding the handoff behind a free-text prompt.
5
+ """
6
+
7
+ from handoffkit import Agent, HandoffProtocol
8
+
9
+
10
+ def main() -> None:
11
+ """Run a visible three-agent handoff chain."""
12
+ task = "Create a small Python CLI calculator with tests."
13
+ protocol = HandoffProtocol(mode="hybrid_state")
14
+
15
+ architect = Agent("Architect", "Create implementation plans.")
16
+ coder = Agent("Coder", "Implement code based on structured state.")
17
+ tester = Agent("Tester", "Review implementation and report test gaps.")
18
+
19
+ print("1. Architect receives task")
20
+ print(task)
21
+
22
+ print("\n2. Architect produces decisions and next steps")
23
+ architect_output = architect.run(task)
24
+ coder_state = protocol.transfer(
25
+ from_agent=architect,
26
+ to_agent=coder,
27
+ task=task,
28
+ summary=architect_output,
29
+ decisions=["Expose calculator operations through a small CLI."],
30
+ important_files=["pyproject.toml", "calculator.py", "tests/test_calculator.py"],
31
+ next_steps=["Implement CLI parser.", "Add pytest coverage for add/subtract."],
32
+ ).validate()
33
+ print(coder_state.to_json())
34
+
35
+ print("\n3. Coder receives HandoffState")
36
+ coder_output = coder.run(task, handoff_state=coder_state)
37
+ print(coder_output)
38
+
39
+ print("\n4. Coder produces simulated implementation state for Tester")
40
+ tester_state = protocol.transfer(
41
+ from_agent=coder,
42
+ to_agent=tester,
43
+ task=task,
44
+ summary=coder_output,
45
+ decisions=coder_state.decisions + ["Keep CLI behavior deterministic."],
46
+ important_files=coder_state.important_files,
47
+ next_steps=["Run pytest.", "Report missing edge cases."],
48
+ ).validate()
49
+ print(tester_state.to_json())
50
+
51
+ print("\n5. Tester receives Coder state and produces final result")
52
+ tester_output = tester.run(task, handoff_state=tester_state)
53
+ print(tester_output)
54
+
55
+
56
+ if __name__ == "__main__":
57
+ main()