tether-sdk 0.0.2__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.
- tether/__init__.py +35 -0
- tether/cli.py +235 -0
- tether/context.py +170 -0
- tether/decorator.py +280 -0
- tether/harness.py +435 -0
- tether/multiplexer.py +124 -0
- tether/providers/__init__.py +66 -0
- tether/providers/anthropic.py +135 -0
- tether/providers/base.py +136 -0
- tether/providers/ollama.py +112 -0
- tether/providers/openai.py +89 -0
- tether/sandbox.py +342 -0
- tether/skills.py +157 -0
- tether/store.py +660 -0
- tether/tools/__init__.py +22 -0
- tether/tools/agent.py +190 -0
- tether/tools/bash.py +29 -0
- tether/tools/done.py +33 -0
- tether/tools/edit.py +107 -0
- tether/tools/mem.py +93 -0
- tether/tools/web.py +222 -0
- tether_sdk-0.0.2.dist-info/METADATA +346 -0
- tether_sdk-0.0.2.dist-info/RECORD +26 -0
- tether_sdk-0.0.2.dist-info/WHEEL +4 -0
- tether_sdk-0.0.2.dist-info/entry_points.txt +2 -0
- tether_sdk-0.0.2.dist-info/licenses/LICENSE +20 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tether-sdk
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: General-purpose, headless-first LLM-Native micro-harness for small language models
|
|
5
|
+
Project-URL: Homepage, https://github.com/igormcsouza/tether
|
|
6
|
+
Project-URL: Repository, https://github.com/igormcsouza/tether
|
|
7
|
+
Project-URL: Documentation, https://igormcsouza.github.io/tether/
|
|
8
|
+
Author-email: Igor Souza <igormcsouza@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,cli,harness,llm,slm,sqlite
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Requires-Dist: httpx>=0.27.0
|
|
17
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# πͺ’ Tether
|
|
21
|
+
|
|
22
|
+
**A general-purpose, headless-first LLM-Native micro-harness engineered for small context windows and high-signal business logic.**
|
|
23
|
+
|
|
24
|
+
[](https://pypi.org/project/tether-sdk/)
|
|
25
|
+
[](https://igormcsouza.github.io/tether/)
|
|
26
|
+
[-6366f1)](#theoretical-foundation)
|
|
27
|
+
[%20%7C%20Claude%20%7C%20GPT-10b981)](#multi-model-zero-bloat-adapters)
|
|
28
|
+
[](#quickstart)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Why Tether?
|
|
33
|
+
|
|
34
|
+
Modern agent frameworks treat context windows as infinite dumping grounds. Before your application processes a single line of business logic, typical harnesses inject **3,000β8,000+ tokens** of verbose JSON tool schemas, sprawling system prompts, and unpruned execution traces.
|
|
35
|
+
|
|
36
|
+
On frontier cloud models, that waste is expensive. On local and small models like **`qwen3.5:9b`**, it is fatal:
|
|
37
|
+
1. **Attention Dilution:** Flooding the prompt with dozens of unused tool schemas degrades reasoning accuracy on the actual domain task.
|
|
38
|
+
2. **Structured-Output Fragility:** Small models frequently hallucinate escaping or nested JSON structures when forced to choose among 20+ complex function-calling schemas.
|
|
39
|
+
3. **KV-Cache Thrashing:** Dynamically mutating the `tools` array between turns invalidates prefix caches in local inference servers (`Ollama`, `llama.cpp`, `vLLM`), tanking latency.
|
|
40
|
+
|
|
41
|
+
**Tether** keeps your LLM, tools, skills, and sub-agents tied together with near-zero overheadβstarting with **zero tools loaded by default** and reserving **>90% of the active context window** for your domain problem.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Theoretical Foundation
|
|
46
|
+
|
|
47
|
+
Tether is not just another wrapper around chat completions; every design choice is grounded in recent systems and software-architecture research on why LLM agents succeed or fail:
|
|
48
|
+
|
|
49
|
+
1. **Probabilistic Core, Deterministic Envelope ([Maia et al., 2026](#references)):**
|
|
50
|
+
Rather than trusting the model to enforce its own guardrails or manage state in raw text, Tether separates the **probabilistic reasoning kernel** (the LLM) from a **strictly deterministic envelope** (CLI argument parsing, path canonicalization, OS kernel sandboxing, SQLite ACID state transitions, and explicit `done` termination gates).
|
|
51
|
+
2. **Why a Single `act(cmd, stdin)` Primitive Beats 30 JSON Schemas ([Wang et al., ICML 2024 β *CodeAct*](#references)):**
|
|
52
|
+
Across 17 evaluated models, Wang et al. demonstrated that forcing an LLM to choose among dozens of rigid JSON function-calling schemas degrades reasoning and wastes thousands of prompt tokens. Consolidating actions into a **single unified executable action channel** improves task success rates by **up to 20%** while cutting required turns by **~30%**βan effect that is especially pronounced on smaller open-weight models (`7B`β`9B`).
|
|
53
|
+
3. **Why a Virtual CLI + Progressive `--help` + Observation Folding ([Yang et al., NeurIPS 2024 β *SWE-agent*](#references)):**
|
|
54
|
+
Just as humans need ergonomic UIs, LLMs need purpose-built **Agent-Computer Interfaces (ACIs)**. Following Yang et al., Tether replaces raw shell dumps and upfront schema walls with a compact POSIX-style command bus, windowed line-numbered file editing (`edit view`/`replace`), immediate self-healing usage hints (`--help`) when a command is malformed, and **ephemeral observation folding** so old tool outputs don't crowd out active reasoning.
|
|
55
|
+
4. **Context as L1 Cache Backed by SQLite L2 Storage ([Packer et al., 2023 β *MemGPT*](#references)):**
|
|
56
|
+
Instead of treating the prompt as an unbounded append-only transcript, Tether treats the active context window like an **OS L1 working cache** (static prefix + `mem pin` scratchpad + the last $K$ raw observations) backed by **L2 disk storage** (`.tether/tether.db` in WAL mode with an automatic FTS5 BM25 index), allowing agents to page relevant knowledge in and out on demand via `mem search`, `mem recall`, and `agent query`.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Core Pillars of Tether `v0`
|
|
61
|
+
|
|
62
|
+
### 1. Virtual CLI Multiplexer + Progressive `--help`
|
|
63
|
+
Instead of registering dozens of JSON schemas with the model provider, Tether exposes **only one static JSON tool** (`act(cmd: str, stdin: str | None = None)`) and routes all capabilities through a virtual POSIX-style command bus:
|
|
64
|
+
- **Zero Tools by Default:** Start completely bare (`done` only), or opt-in to specific tools via CLI (`--tools web,bash` or `--tools all`), Python SDK (`tools=["web"]`), or Skill frontmatter.
|
|
65
|
+
- **1-Line Toolbox Index:** Active tools appear as a compact 1-line summary in the static prompt prefix (~10 tokens per tool).
|
|
66
|
+
- **JIT Schema Disclosure (`--help`):** Full flags and docstrings are disclosed only when the model runs `<cmd> --help` or makes an argument error (self-healing usage hint).
|
|
67
|
+
- **Explicit Termination (`act("done", stdin="...")`):** Small models often think out loud mid-task. Rather than prematurely ending the session on an un-tooled text reply, Tether requires an explicit `act("done", stdin="final report")` call to lock in the final deliverable.
|
|
68
|
+
|
|
69
|
+
```mermaid
|
|
70
|
+
flowchart LR
|
|
71
|
+
subgraph Client["CLI or Python SDK"]
|
|
72
|
+
Headless["tether run --headless\ntether send / status / read"]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
subgraph DB["SQLite State & FTS5 RAG Store (.tether/tether.db WAL)"]
|
|
76
|
+
Sessions["sessions | inbox | turns | observations | chunks_fts (BM25)"]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
subgraph Worker["Detached Session Worker"]
|
|
80
|
+
Loop["Bounded Agent Loop"]
|
|
81
|
+
Mux["Virtual CLI Multiplexer\nact(cmd, stdin?)"]
|
|
82
|
+
Sandbox["Deterministic Sandbox\n(bwrap/unshare + workspace jail)"]
|
|
83
|
+
Folder["Ephemeral Output Folder\n& FTS5 Chunk Indexer"]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
subgraph Tools["Opt-In Capabilities"]
|
|
87
|
+
Builtins["bash | web | edit | mem | skill | agent | done"]
|
|
88
|
+
Custom["@tether.tool\nSDK & Skill Python Tools"]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
Headless <--> DB
|
|
92
|
+
DB <--> Loop
|
|
93
|
+
Loop --> Mux
|
|
94
|
+
Mux --> Sandbox
|
|
95
|
+
Sandbox --> Builtins
|
|
96
|
+
Sandbox --> Custom
|
|
97
|
+
Builtins --> Folder
|
|
98
|
+
Custom --> Folder
|
|
99
|
+
Folder --> DB
|
|
100
|
+
Folder --> Loop
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 2. Headless-First Sessions & Live SQLite Inbox
|
|
104
|
+
Every Tether execution is a stateful session persisted in `.tether/tether.db` (SQLite WAL mode). You can run sessions inline or spawn detached background workers (`--headless`):
|
|
105
|
+
- **Live Inbox & Auto-Resume:** Calling `tether send <session_id> "new instruction"` checks the session state in SQLite:
|
|
106
|
+
- If **`RUNNING`**: queues the message into the session's SQLite inbox, which the worker injects before the next reasoning step.
|
|
107
|
+
- If **`COMPLETED` / `IDLE`**: appends the message and automatically spawns a worker to resume the session with its pinned memory and folded context intact.
|
|
108
|
+
|
|
109
|
+
### 3. Progressive Skills (`skills/`)
|
|
110
|
+
Skills are portable capability bundles stored in `./skills/<name>/SKILL.md` (or `./skills/<name>.md`) with YAML frontmatter and an optional sibling `tools.py`:
|
|
111
|
+
```markdown
|
|
112
|
+
---
|
|
113
|
+
name: researcher
|
|
114
|
+
description: Deep web research and synthesis specialist
|
|
115
|
+
model: ollama/qwen3.5:9b
|
|
116
|
+
tools: [web, mem, done]
|
|
117
|
+
---
|
|
118
|
+
You are a focused research agent. Search multiple sources via `web search`,
|
|
119
|
+
fetch key articles with `web fetch`, pin verified facts with `mem pin`,
|
|
120
|
+
and conclude with `act("done", stdin="<markdown report>")`.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 4. Async Multi-Agent Orchestration & Zero-Bloat SQLite FTS5 RAG
|
|
124
|
+
Because every Tether session is headless-capable, a parent agent can delegate context-heavy subtasks to child agents with isolated context windowsβ**without drowning when reading their results back**:
|
|
125
|
+
- `agent spawn --skill researcher "Summarize AI news"` $\rightarrow$ immediately returns `ses_9a2f1c` (non-blocking).
|
|
126
|
+
- `agent wait ses_9a2f1c ses_4b8e0d` $\rightarrow$ returns a **compact ~50-token digest** (status, chunk count, preview) rather than dumping thousands of tokens into the parent's prompt.
|
|
127
|
+
- `agent query ses_9a2f1c "open-weight benchmarks" --top 3` $\rightarrow$ uses **SQLite FTS5 (BM25 ranking)** over the sub-agent's chunked final deliverable *and* raw scraped observations to retrieve only the top-K relevant snippets (~250 tokens). Pass `--all` to search across all child sessions at once!
|
|
128
|
+
- `mem search "rate limits"` $\rightarrow$ uses the same FTS5 index inside a single session to pull specific chunks from folded observations without recalling the entire raw output.
|
|
129
|
+
|
|
130
|
+
### 5. Deterministic Security Sandbox (Never Relying on the LLM)
|
|
131
|
+
In line with Maia et al. (2026), safety boundaries are enforced **deterministically by the harness and OS kernel**, never by prompting the model to "be careful":
|
|
132
|
+
- **Default `workspace-write` Jail:** Every `edit` and `bash` path is canonicalized (`realpath`) and confined to the workspace root. Sensitive paths (`.env*`, `.git/config`, `.git/hooks`, `~/.ssh`, `.tether/`) are deterministically blocked from mutation or exfiltration.
|
|
133
|
+
- **OS-Level Kernel Sandbox for `bash`:** On Linux, Tether automatically wraps shell commands in **`bwrap` (Bubblewrap) / `unshare`** when availableβmounting `/` read-only, hiding `$HOME` with an empty tmpfs, binding only the workspace directory, and setting `PR_SET_NO_NEW_PRIVS`. When kernel sandboxing is unavailable, Tether enforces a strict deterministic binary allowlist/denylist.
|
|
134
|
+
- **Secret Environment Scrubbing & Resource Caps:** Subprocesses run with a scrubbed environment (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GITHUB_TOKEN`, `AWS_*` stripped), hard process-group timeouts (`SIGKILL`), and output byte caps.
|
|
135
|
+
- **Privilege Attenuation:** Child sub-agents spawned via `agent spawn` strictly inherit (or narrow) their parent session's sandbox profile and can never escalate permissions.
|
|
136
|
+
|
|
137
|
+
### 6. Multi-Model, Zero-Bloat Adapters
|
|
138
|
+
Tether supports any local or cloud model through **3 ultra-thin `httpx` adapters** (<200 LOC total, zero heavy SDK dependencies):
|
|
139
|
+
- **`ollama/<model>`** β Native Ollama `/api/chat` adapter with `num_ctx` and `keep_alive` control (e.g., `ollama/qwen3.5:9b`).
|
|
140
|
+
- **`openai/<model>`** β OpenAI-compatible `/v1/chat/completions` adapter (OpenAI, OpenRouter, vLLM, llama.cpp, Groq, DeepSeek).
|
|
141
|
+
- **`anthropic/<model>`** β Native Anthropic `/v1/messages` adapter for Claude models.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Real-World Benchmark: Autonomous YouTube Short Production
|
|
146
|
+
|
|
147
|
+
To measure how harness architecture impacts token consumption, latency, and local-model viability, we ran a head-to-head benchmark across **three configurations** (2 trials each) on a multi-stage media task:
|
|
148
|
+
|
|
149
|
+
> **Task:** *"Create a 30-to-40 second vertical YouTube Short (1080x1920 `.mp4`) explaining 'What is an AI Harness, the Context Bloat Problem, and Micro-Harnesses', complete with 4 animated **Manim** vector diagrams, **EdgeTTS** neural voiceover (`en-US-ChristopherNeural`), synchronized subtitles, and **FFmpeg** muxing."*
|
|
150
|
+
|
|
151
|
+
### Results Summary (2-Trial Averages)
|
|
152
|
+
|
|
153
|
+
| Configuration | Harness | Model | Avg Steps | Avg Total Tokens | Peak Context | Avg Wall Time | Token Reduction vs. Claude Code |
|
|
154
|
+
| :--- | :--- | :--- | :---: | :---: | :---: | :---: | :---: |
|
|
155
|
+
| **Tether + Local 8B** | **Tether `v0`** | `ollama/gemma4:e4b` | **2.0** | **3,073** | **1,854** | **53.1s** | **68.8Γ fewer tokens** (\$0 local) |
|
|
156
|
+
| **Tether + Claude** | **Tether `v0`** | `anthropic/claude-sonnet-5-5` | **2.0** | **5,318** | **3,118** | **48.7s** | **39.7Γ fewer tokens** (2.0Γ faster) |
|
|
157
|
+
| **Claude Code CLI** | Claude Code | `claude-sonnet-5-5` | 5.0 | 211,355 | 42,091 | 97.4s | 1.0Γ (baseline) |
|
|
158
|
+
|
|
159
|
+
```mermaid
|
|
160
|
+
xychart-beta
|
|
161
|
+
title "Total Tokens Consumed per Video (Lower is Better)"
|
|
162
|
+
x-axis ["Tether + gemma4:e4b (Local)", "Tether + Claude Sonnet", "Claude Code CLI (Sonnet)"]
|
|
163
|
+
y-axis "Total Tokens (Prompt + Output)" 0 --> 220000
|
|
164
|
+
bar [3073, 5318, 211355]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```mermaid
|
|
168
|
+
xychart-beta
|
|
169
|
+
title "End-to-End Wall-Clock Time in Seconds (Lower is Better)"
|
|
170
|
+
x-axis ["Tether + Claude Sonnet", "Tether + gemma4:e4b (Local)", "Claude Code CLI (Sonnet)"]
|
|
171
|
+
y-axis "Seconds (incl. Manim + EdgeTTS + FFmpeg)" 0 --> 110
|
|
172
|
+
bar [48.7, 53.1, 97.4]
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Why the 40Γβ69Γ Token Difference?
|
|
176
|
+
1. **Zero Tool Schema Bloat:** Claude Code injects **~41,000+ tokens** of system instructions and JSON tool schemas on *every single reasoning turn* (consuming `164kβ257k` cumulative tokens across 4β6 turns of file exploration and shell execution). Tether's static prefix + `shorts-maker` skill framing is **< 400 tokens**, allowing both `claude-sonnet-5-5` and a local `8B` model (`gemma4:e4b`) to one-shot the entire 4-scene YAML specification via `act("render-short ...", stdin="...")` on Turn 1 and call `done` on Turn 2.
|
|
177
|
+
2. **Identical Frontier Model, 39.7Γ Less Context:** Running the *exact same* `claude-sonnet-5-5` model inside Tether instead of Claude Code cut token consumption from **211,355 $\rightarrow$ 5,318 tokens** and halved execution time (**97.4s $\rightarrow$ 48.7s**), because nearly 100% of wall-clock time went to actual Manim + EdgeTTS rendering (~43s) rather than re-processing massive prompt prefixes.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Quickstart
|
|
182
|
+
|
|
183
|
+
### Installation (PyPI)
|
|
184
|
+
|
|
185
|
+
Tether is published on PyPI as **[`tether-sdk`](https://pypi.org/project/tether-sdk/)** (requires Python `3.12+`). Installing `tether-sdk` provides both the **`tether` CLI entrypoint** and the **`tether` Python package** (`from tether import Harness, tool`):
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Install with pip
|
|
189
|
+
pip install tether-sdk
|
|
190
|
+
|
|
191
|
+
# Or add to a project with uv
|
|
192
|
+
uv add tether-sdk
|
|
193
|
+
|
|
194
|
+
# Or install the `tether` CLI globally as an isolated tool
|
|
195
|
+
uv tool install tether-sdk
|
|
196
|
+
|
|
197
|
+
# Or run the CLI directly without installing
|
|
198
|
+
uvx --from tether-sdk tether "Explain the CAP theorem in 3 bullet points"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Full documentation, tutorials, and API reference: **[https://igormcsouza.github.io/tether/](https://igormcsouza.github.io/tether/)**
|
|
202
|
+
|
|
203
|
+
### Headless CLI Usage
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# 1. Start a headless background session with the 'researcher' skill
|
|
207
|
+
$ tether run --headless --skill researcher "What are the latest news about AI?"
|
|
208
|
+
ses_8f92a1
|
|
209
|
+
|
|
210
|
+
# 2. Or start with explicit opt-in tools and any model
|
|
211
|
+
$ tether run --headless --model ollama/qwen3.5:9b --tools web,mem "Compare vLLM vs Ollama"
|
|
212
|
+
ses_3c71b9
|
|
213
|
+
|
|
214
|
+
# 3. Check live session status, step count, and token budget
|
|
215
|
+
$ tether status ses_8f92a1
|
|
216
|
+
ID STATUS MODEL STEP CTX_TOKENS LAST_CMD
|
|
217
|
+
ses_8f92a1 RUNNING ollama/qwen3.5:9b 3/15 580/8192 web search "AI news 2026"
|
|
218
|
+
|
|
219
|
+
# 4. Read the final report (or --steps to inspect the work log)
|
|
220
|
+
$ tether read ses_8f92a1
|
|
221
|
+
|
|
222
|
+
# 5. Send a follow-up (queues into live inbox if RUNNING, or auto-resumes if COMPLETED)
|
|
223
|
+
$ tether send ses_8f92a1 --headless "Now spawn a sub-agent to fact-check the top 2 announcements."
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Python SDK Usage
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
import asyncio
|
|
230
|
+
from tether import Harness, tool
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@tool(name="crm", description="Query or update customer subscription tiers")
|
|
234
|
+
async def crm(customer_id: int, tier: str = "pro") -> str:
|
|
235
|
+
"""Update customer tier. Allowed tiers: free, pro, enterprise."""
|
|
236
|
+
return f"Customer #{customer_id} updated to {tier}."
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
async def main():
|
|
240
|
+
# Minimal by default: only loads `done` + explicitly requested tools
|
|
241
|
+
harness = Harness(
|
|
242
|
+
model="ollama/qwen3.5:9b",
|
|
243
|
+
tools=["mem", crm],
|
|
244
|
+
fold_observations_after=2,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
session = await harness.run(
|
|
248
|
+
"Upgrade customer 1042 to enterprise, pin the audit note, and finish."
|
|
249
|
+
)
|
|
250
|
+
print(f"Session {session.id} [{session.status}]:\n{session.result}")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
if __name__ == "__main__":
|
|
254
|
+
asyncio.run(main())
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Custom SDK Provider Routing (`register_provider` / `provider=...`)
|
|
258
|
+
|
|
259
|
+
Want to route Tether through a custom transportβsuch as an internal corporate gateway, a custom local inference server, or a mock/replay harness for testing? Implement the 1-method `ModelProvider` protocol or register a custom URL prefix with `register_provider`:
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
import httpx
|
|
263
|
+
from tether import (
|
|
264
|
+
Harness,
|
|
265
|
+
ModelResponse,
|
|
266
|
+
extract_fallback_action,
|
|
267
|
+
register_provider,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class CustomGatewayProvider:
|
|
272
|
+
"""Routes Tether turns through a custom internal LLM gateway."""
|
|
273
|
+
|
|
274
|
+
def __init__(self, model_name: str) -> None:
|
|
275
|
+
self.model_name = model_name
|
|
276
|
+
|
|
277
|
+
async def generate(self, messages: list[dict], tools: list[dict]) -> ModelResponse:
|
|
278
|
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
279
|
+
resp = await client.post(
|
|
280
|
+
"https://llm-gateway.internal/v1/generate",
|
|
281
|
+
json={"model": self.model_name, "messages": messages, "tools": tools},
|
|
282
|
+
)
|
|
283
|
+
data = resp.json()
|
|
284
|
+
text = str(data.get("text") or "").strip()
|
|
285
|
+
return ModelResponse(
|
|
286
|
+
content=text,
|
|
287
|
+
action=extract_fallback_action(text),
|
|
288
|
+
prompt_tokens=int(data.get("total_tokens") or 0),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
# Register as a custom `<prefix>/<model>` for Harness, Skills, and Sub-Agents:
|
|
293
|
+
register_provider("gateway", CustomGatewayProvider)
|
|
294
|
+
|
|
295
|
+
harness = Harness(model="gateway/qwen-enterprise-32b", tools=["web", "mem"])
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Built-In Virtual CLI Toolbox (Opt-In)
|
|
301
|
+
|
|
302
|
+
| Namespace | Subcommands | Description |
|
|
303
|
+
| :--- | :--- | :--- |
|
|
304
|
+
| **`done`** *(always on)* | `done [summary]` *(or via `stdin`)* | Explicitly complete the current task and record + FTS5-index the final deliverable |
|
|
305
|
+
| **`web`** | `web search <query>` \| `web fetch <url>` | Zero-config DuckDuckGo Lite search (auto-upgrades to Brave/Tavily/SearXNG) + clean reader |
|
|
306
|
+
| **`bash`** | `bash <command>` *(or script via `stdin`)* | Kernel-sandboxed (`bwrap`/`unshare`), env-scrubbed, workspace-bounded shell execution |
|
|
307
|
+
| **`edit`** | `edit view <path>` \| `edit write <path>` \| `edit replace <path>` | Workspace-jailed, line-numbered file viewing and `stdin`-based creation/replacement |
|
|
308
|
+
| **`mem`** | `mem pin <k> <v>` \| `mem search <query>` \| `mem recall <obs_id>` | Pinned working memory + BM25 RAG search & retrieval over folded observations |
|
|
309
|
+
| **`skill`** | `skill list` \| `skill load <name>` | Progressive discovery and JIT loading of skill instructions & tools |
|
|
310
|
+
| **`agent`** | `agent spawn` \| `agent wait` \| `agent query` \| `agent read` \| `agent send` | Async sub-agent spawning, compact wait digests, and BM25 RAG queries over child sessions |
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Project Structure
|
|
315
|
+
|
|
316
|
+
```text
|
|
317
|
+
tether/
|
|
318
|
+
βββ README.md
|
|
319
|
+
βββ AGENTS.md # Authoritative blueprint for coding agents & contributors
|
|
320
|
+
βββ mkdocs.yml # MkDocs Material documentation configuration
|
|
321
|
+
βββ pyproject.toml # Managed with uv (httpx, pyyaml, standard library)
|
|
322
|
+
βββ docs/ # Full documentation, tutorials & API reference
|
|
323
|
+
βββ skills/ # Built-in & workspace progressive skills
|
|
324
|
+
βββ tether/
|
|
325
|
+
β βββ __init__.py # SDK exports: Harness, Session, Skill, SandboxPolicy, tool
|
|
326
|
+
β βββ cli.py # `tether` CLI entrypoint (run, status, read, send, list)
|
|
327
|
+
β βββ harness.py # Control Plane: bounded agent loop, inbox polling, worker spawn
|
|
328
|
+
β βββ store.py # State & RAG Plane: SQLite WAL + FTS5 BM25 chunk store
|
|
329
|
+
β βββ sandbox.py # Security Plane: bwrap/unshare kernel sandbox & workspace jail
|
|
330
|
+
β βββ multiplexer.py # Action Plane: `act(cmd, stdin)` parser, router & JIT --help
|
|
331
|
+
β βββ decorator.py # `@tool` introspection -> POSIX CLI parser & compact usage
|
|
332
|
+
β βββ context.py # State Plane: ContextAssembler & Ephemeral Observation Folder
|
|
333
|
+
β βββ skills.py # Markdown + YAML frontmatter + companion `tools.py` loader
|
|
334
|
+
β βββ providers/ # Thin httpx adapters: ollama.py, openai.py, anthropic.py
|
|
335
|
+
β βββ tools/ # Opt-in built-ins: bash.py, web.py, edit.py, mem.py, agent.py
|
|
336
|
+
βββ tests/ # Per-module unit tests + integration suite (100% coverage)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## References
|
|
342
|
+
|
|
343
|
+
1. **Maia, P. H. M., et al. (2026).** *LLM-Native Applications as a Paradigm for AI-Driven Software Architecture*.
|
|
344
|
+
2. **Wang, X., Chen, Y., Yuan, L., Zhang, Y., Li, Y., Peng, H., & Ji, H. (2024).** *Executable Code Actions Elicit Better LLM Agents (CodeAct)*. In **Proceedings of the 41st International Conference on Machine Learning (ICML 2024)**. [arXiv:2402.01030](https://arxiv.org/abs/2402.01030)
|
|
345
|
+
3. **Yang, J., Jimenez, C. E., Wettig, A., Lieret, K., Yao, S., Narasimhan, K., & Press, O. (2024).** *SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering*. In **Advances in Neural Information Processing Systems (NeurIPS 2024)**. [arXiv:2405.15793](https://arxiv.org/abs/2405.15793)
|
|
346
|
+
4. **Packer, C., Wooders, S., Lin, K., Fang, V., Patil, S. G., Stoica, I., & Gonzalez, J. E. (2023).** *MemGPT: Towards LLMs as Operating Systems*. [arXiv:2310.08560](https://arxiv.org/abs/2310.08560)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
tether/__init__.py,sha256=vNHYR4lny94u5G0pus3EguPbHJOtrCS8Kzx8iMZ87Us,807
|
|
2
|
+
tether/cli.py,sha256=SN0Pwn40Xl8rHSWGgp_PApiQ1ST8-kwlhDa709jE0Gg,8516
|
|
3
|
+
tether/context.py,sha256=zUDR4dOZNw2UVM_ii2IAGE9hIbzQkh8jZt-vOJ543fg,6278
|
|
4
|
+
tether/decorator.py,sha256=Wuj4W0TTwFVLFCclPDLAc5A8CckHy3sITPjwapZ4DrA,9788
|
|
5
|
+
tether/harness.py,sha256=ivqmu-x61y5qm7zIW6XNmi8DIXK7L7i5Ck-B8418V0U,17015
|
|
6
|
+
tether/multiplexer.py,sha256=YjyZZRY5lEVJFQ_UgmNGAcE0JnRfrxJ99jtC07IPoHA,4378
|
|
7
|
+
tether/sandbox.py,sha256=gM2LKTow7gN8ZNzDU4MR3SYKsbB-Uy2CfhcAyYJ0GB0,12126
|
|
8
|
+
tether/skills.py,sha256=O_R5trxmzeIIVOWDuLgkkcMpPHwffCtuyXwWLGsRRcY,5516
|
|
9
|
+
tether/store.py,sha256=ngB5pjkpqOz1AECQ0yqdXtuhG_BQL0cbRRiZgGE4HhE,23811
|
|
10
|
+
tether/providers/__init__.py,sha256=bPB7jF-BBzZwblK5OcTPjrxBvyQ9u_aE6XokcVifOe4,2125
|
|
11
|
+
tether/providers/anthropic.py,sha256=rMaUjcOd2GkNUpCD6Rcfq1COU1drrBN6_B6EbDqsCjw,4706
|
|
12
|
+
tether/providers/base.py,sha256=ez84Wf1-YESXEnNLTdOfTKmNYy3MnSrdWQgmSDnElOk,4420
|
|
13
|
+
tether/providers/ollama.py,sha256=9svEw_qOFVuyQykbVbwmgZUeoVqgUqqfU1iK_wU465k,4114
|
|
14
|
+
tether/providers/openai.py,sha256=HBdMx6tQVFY4p2aUCGrDpB9lSpGceuq1-74ZR3VFDFU,2848
|
|
15
|
+
tether/tools/__init__.py,sha256=-JxvSi3VrNFdeFqsiLu_bSwoeDSy2ALcFm4V6JpHn24,592
|
|
16
|
+
tether/tools/agent.py,sha256=exKWfpU2HwpWTaomrAvmJjU4XqSftapcoNe6kxwhigg,7290
|
|
17
|
+
tether/tools/bash.py,sha256=JrnukfSguuJuIMSZwGE85P4fzONScEY-OcC-N5np1Vo,921
|
|
18
|
+
tether/tools/done.py,sha256=Yl3fbJz8WYTLXpM9yUOWf5EBeeeXTkmoohvG_reuVow,1064
|
|
19
|
+
tether/tools/edit.py,sha256=KuAPyRagbzL_v1jjmVdBTkjkiNbH6UA8dKYJOx9C9L0,4521
|
|
20
|
+
tether/tools/mem.py,sha256=04lSS8eJ0upxm3hB9Ncy0gtxRbEczN-bMcnYRRGOuDU,3529
|
|
21
|
+
tether/tools/web.py,sha256=5KER8xu70E19IF4QuHnepeD_qo2W4DXHbLeRRh03Pm8,8232
|
|
22
|
+
tether_sdk-0.0.2.dist-info/METADATA,sha256=uz3qTbj1-6iFv1cVE1uAWyqEBfQHE_uFsIBUonA-mco,21730
|
|
23
|
+
tether_sdk-0.0.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
24
|
+
tether_sdk-0.0.2.dist-info/entry_points.txt,sha256=rq-dLvpEyTXMgXXryhjScYVL0oHwiBc4oB1-iq7Z9OA,43
|
|
25
|
+
tether_sdk-0.0.2.dist-info/licenses/LICENSE,sha256=L9cZQaeH9X8zVeLFBQApFaA6qWvtTVQTPRQyn_khLIM,1054
|
|
26
|
+
tether_sdk-0.0.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2026 Igor Souza
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|