handoffkit 0.2.0__py3-none-any.whl
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/__init__.py +22 -0
- handoffkit/agent.py +91 -0
- handoffkit/cli.py +49 -0
- handoffkit/errors.py +33 -0
- handoffkit/handoff.py +86 -0
- handoffkit/memory.py +44 -0
- handoffkit/protocol.py +60 -0
- handoffkit/protocols/__init__.py +5 -0
- handoffkit/protocols/compressed.py +31 -0
- handoffkit/protocols/hybrid_min.py +17 -0
- handoffkit/protocols/hybrid_state.py +52 -0
- handoffkit/protocols/natural.py +22 -0
- handoffkit/providers/__init__.py +21 -0
- handoffkit/providers/base.py +16 -0
- handoffkit/providers/echo_provider.py +26 -0
- handoffkit/providers/ollama_provider.py +48 -0
- handoffkit/providers/openai_compatible.py +140 -0
- handoffkit/providers/openai_provider.py +80 -0
- handoffkit/py.typed +1 -0
- handoffkit/runner.py +51 -0
- handoffkit/schemas.py +45 -0
- handoffkit/tool.py +196 -0
- handoffkit/tools/__init__.py +15 -0
- handoffkit/tools/filesystem.py +34 -0
- handoffkit/tools/shell.py +53 -0
- handoffkit/tools/text.py +54 -0
- handoffkit-0.2.0.dist-info/METADATA +317 -0
- handoffkit-0.2.0.dist-info/RECORD +32 -0
- handoffkit-0.2.0.dist-info/WHEEL +5 -0
- handoffkit-0.2.0.dist-info/entry_points.txt +2 -0
- handoffkit-0.2.0.dist-info/licenses/LICENSE +21 -0
- handoffkit-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -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
|
+
[](https://github.com/DaosPath/handoffkit/actions/workflows/ci.yml)
|
|
33
|
+

|
|
34
|
+

|
|
35
|
+

|
|
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,32 @@
|
|
|
1
|
+
handoffkit/__init__.py,sha256=RDQ46rCRs_KPA1cQN_X19RENyXFNx9jdnAzT6hMxDfU,525
|
|
2
|
+
handoffkit/agent.py,sha256=7YVGjsxtpgATXHMfL4XHEZq9M9DQB1Q55Mp6uI0262Q,3369
|
|
3
|
+
handoffkit/cli.py,sha256=EsNg8AuhG2I6aWn2LTM8exLMJPWZ8ZOvn9PIz8ju9zk,1548
|
|
4
|
+
handoffkit/errors.py,sha256=wy87Ib-mE_CWeE25MYINlmb8NNh19kDyFRGzfqaJcAE,928
|
|
5
|
+
handoffkit/handoff.py,sha256=EOABD5YcM0LtgSdFnaO5O8IZxvGa_3rgEqVeVz8VyrM,3498
|
|
6
|
+
handoffkit/memory.py,sha256=Mz7r_26CGVNawg6ZBCSGHQJrwnDBX5eI-z8MOOz1i9c,1315
|
|
7
|
+
handoffkit/protocol.py,sha256=3ZnkiOnnACD92ccquAzgorIUaO6S6N9wKRLEthm7d9k,2245
|
|
8
|
+
handoffkit/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
9
|
+
handoffkit/runner.py,sha256=LfahWmNBTc-_wHqk82Rxi-1paB_nqbzEWfeVjctwr0w,1645
|
|
10
|
+
handoffkit/schemas.py,sha256=X1mQsOO7p6Z0A3cmJ66ZgUeOZmuAYZQoY0dRi6BZ_eY,1144
|
|
11
|
+
handoffkit/tool.py,sha256=VeBatxpt2tcarkAHXbdyw-CmRu4lq9G8S1hLeGCGX9c,6537
|
|
12
|
+
handoffkit/protocols/__init__.py,sha256=srXbb0Ubk88OLO_gUWvxRVj0hBGfJf58OuZk-VnTwTQ,178
|
|
13
|
+
handoffkit/protocols/compressed.py,sha256=cmTqjEtV4wOYQpgO6tkDNCruZCmUiZOP2pVhNbHxeBk,978
|
|
14
|
+
handoffkit/protocols/hybrid_min.py,sha256=AAPLHrwCy8YwwFqlr4yAGIFyWCpi6BGAzweBb3nB_i4,578
|
|
15
|
+
handoffkit/protocols/hybrid_state.py,sha256=CTxwQ2X_19qkJdrzftqbdSIYKAkNNO5SzxU99q-mMzk,1442
|
|
16
|
+
handoffkit/protocols/natural.py,sha256=ngr3re2-XhpJFev8LeLXPX0q93gOkvqOIenSGBhmlx4,732
|
|
17
|
+
handoffkit/providers/__init__.py,sha256=cgUgj5lBDh41A2_fNmLppPkw5OQQCwQ3bpV5DWnnWqM,639
|
|
18
|
+
handoffkit/providers/base.py,sha256=7nwjtx1NmpJHbCQ_MYGEkgV7B3MqkbOzRKCR0pmUgB8,345
|
|
19
|
+
handoffkit/providers/echo_provider.py,sha256=gOtD5iwSWCIm7ru94kM7CjpzvioGEKyyQG6ye2wfmB0,919
|
|
20
|
+
handoffkit/providers/ollama_provider.py,sha256=tFMiI6B8G7IUftElC81cAuN_uYnZeIDLGE9wDbSM5uY,1500
|
|
21
|
+
handoffkit/providers/openai_compatible.py,sha256=2Z1t7aGpTAE-YIjcTe_I2B6CjE771G2g6UxaN0v1sDE,5111
|
|
22
|
+
handoffkit/providers/openai_provider.py,sha256=VM8Y66tb3NsgbXmS4sz4abRNanPwJkc0ryG_Ofnzy_0,3089
|
|
23
|
+
handoffkit/tools/__init__.py,sha256=dsCfBwEdKUnR03S12v3Q_xn8UdGUCm_xx4mQ-5TVxB0,376
|
|
24
|
+
handoffkit/tools/filesystem.py,sha256=JP_NkKIznaUTfkRWpAJ71N8YFaTf-_BVC3NwZG3Z5nk,774
|
|
25
|
+
handoffkit/tools/shell.py,sha256=yAh35_atKBvaDFQnbLYeqgwrySWCy619RREQ1gLi61E,1689
|
|
26
|
+
handoffkit/tools/text.py,sha256=9I5Ld_lpDs_wlvRZN8bLob08g9wM-F_kuo0WMDEC1Mg,1027
|
|
27
|
+
handoffkit-0.2.0.dist-info/licenses/LICENSE,sha256=031GM9k6mO_YqtDVNdA0Qx3x8KPDjdXFOCXOaN-LASQ,1065
|
|
28
|
+
handoffkit-0.2.0.dist-info/METADATA,sha256=1jusdY6dlZSRdNWYBUWDjfe8kgVuoJrmKOSWlgwDubE,9118
|
|
29
|
+
handoffkit-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
30
|
+
handoffkit-0.2.0.dist-info/entry_points.txt,sha256=YOy2qo6DAGg9sQ0I4hVbb9FNNUiRZH0HwV8SxQYt6gQ,51
|
|
31
|
+
handoffkit-0.2.0.dist-info/top_level.txt,sha256=qYCNy1WtNJ3e1_XChaE3aCU6p3AlVO19-JWKVDUBnYk,11
|
|
32
|
+
handoffkit-0.2.0.dist-info/RECORD,,
|
|
@@ -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 @@
|
|
|
1
|
+
handoffkit
|