agent-tokenops 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_tokenops-0.1.0/LICENSE.txt +21 -0
- agent_tokenops-0.1.0/PKG-INFO +305 -0
- agent_tokenops-0.1.0/README.md +263 -0
- agent_tokenops-0.1.0/pyproject.toml +85 -0
- agent_tokenops-0.1.0/setup.cfg +4 -0
- agent_tokenops-0.1.0/src/agent_tokenops.egg-info/PKG-INFO +305 -0
- agent_tokenops-0.1.0/src/agent_tokenops.egg-info/SOURCES.txt +97 -0
- agent_tokenops-0.1.0/src/agent_tokenops.egg-info/dependency_links.txt +1 -0
- agent_tokenops-0.1.0/src/agent_tokenops.egg-info/requires.txt +20 -0
- agent_tokenops-0.1.0/src/agent_tokenops.egg-info/top_level.txt +1 -0
- agent_tokenops-0.1.0/src/tokenops/__init__.py +12 -0
- agent_tokenops-0.1.0/src/tokenops/config/__init__.py +3 -0
- agent_tokenops-0.1.0/src/tokenops/config/default.yaml +37 -0
- agent_tokenops-0.1.0/src/tokenops/config/loader.py +30 -0
- agent_tokenops-0.1.0/src/tokenops/control/__init__.py +111 -0
- agent_tokenops-0.1.0/src/tokenops/control/attribution.py +185 -0
- agent_tokenops-0.1.0/src/tokenops/control/boundary.py +145 -0
- agent_tokenops-0.1.0/src/tokenops/control/client.py +146 -0
- agent_tokenops-0.1.0/src/tokenops/control/config.py +162 -0
- agent_tokenops-0.1.0/src/tokenops/control/context.py +136 -0
- agent_tokenops-0.1.0/src/tokenops/control/core.py +329 -0
- agent_tokenops-0.1.0/src/tokenops/control/crossing.py +99 -0
- agent_tokenops-0.1.0/src/tokenops/control/engine.py +293 -0
- agent_tokenops-0.1.0/src/tokenops/control/http.py +126 -0
- agent_tokenops-0.1.0/src/tokenops/control/integration.py +375 -0
- agent_tokenops-0.1.0/src/tokenops/control/ledger.py +297 -0
- agent_tokenops-0.1.0/src/tokenops/control/models.py +117 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/__init__.py +33 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/_util.py +89 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/concurrency_cap.py +80 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/context_compaction.py +78 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/cost_budget.py +68 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/cost_guard.py +98 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/output_runaway.py +94 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/pre_call_worst_case.py +103 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/progress_guard.py +105 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/step_cap.py +57 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/tool_fix.py +100 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/tool_output_cap.py +88 -0
- agent_tokenops-0.1.0/src/tokenops/control/policies/trajectory_hint.py +254 -0
- agent_tokenops-0.1.0/src/tokenops/control/pricing.py +68 -0
- agent_tokenops-0.1.0/src/tokenops/control/propagate.py +46 -0
- agent_tokenops-0.1.0/src/tokenops/control/store.py +717 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/__init__.py +15 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/compress.py +43 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/enqueue.py +64 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/gates.py +35 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/hint.py +75 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/scope.py +69 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/serialize.py +66 -0
- agent_tokenops-0.1.0/src/tokenops/control/trajectory/worker.py +29 -0
- agent_tokenops-0.1.0/src/tokenops/env.py +22 -0
- agent_tokenops-0.1.0/src/tokenops/providers/__init__.py +4 -0
- agent_tokenops-0.1.0/src/tokenops/providers/anthropic.py +28 -0
- agent_tokenops-0.1.0/src/tokenops/providers/factory.py +39 -0
- agent_tokenops-0.1.0/src/tokenops/providers/openai.py +54 -0
- agent_tokenops-0.1.0/src/tokenops/providers/types.py +10 -0
- agent_tokenops-0.1.0/src/tokenops/server/__init__.py +5 -0
- agent_tokenops-0.1.0/src/tokenops/server/__main__.py +26 -0
- agent_tokenops-0.1.0/src/tokenops/server/app.py +38 -0
- agent_tokenops-0.1.0/src/tokenops/ui/__init__.py +0 -0
- agent_tokenops-0.1.0/src/tokenops/ui/app.py +28 -0
- agent_tokenops-0.1.0/src/tokenops/ui/run_detail.py +120 -0
- agent_tokenops-0.1.0/src/tokenops/ui/store_client.py +25 -0
- agent_tokenops-0.1.0/src/tokenops/ui/theme.py +145 -0
- agent_tokenops-0.1.0/src/tokenops/ui/views/__init__.py +0 -0
- agent_tokenops-0.1.0/src/tokenops/ui/views/admin.py +260 -0
- agent_tokenops-0.1.0/src/tokenops/ui/views/dashboard.py +146 -0
- agent_tokenops-0.1.0/tests/test_actuators.py +234 -0
- agent_tokenops-0.1.0/tests/test_apply.py +137 -0
- agent_tokenops-0.1.0/tests/test_attribution.py +112 -0
- agent_tokenops-0.1.0/tests/test_attribution_ledger_policies_e2e.py +92 -0
- agent_tokenops-0.1.0/tests/test_boundary.py +58 -0
- agent_tokenops-0.1.0/tests/test_chronicle_boundary.py +108 -0
- agent_tokenops-0.1.0/tests/test_concurrency_cap.py +34 -0
- agent_tokenops-0.1.0/tests/test_config.py +57 -0
- agent_tokenops-0.1.0/tests/test_context_compaction.py +37 -0
- agent_tokenops-0.1.0/tests/test_control_plane_app.py +95 -0
- agent_tokenops-0.1.0/tests/test_control_plane_client.py +76 -0
- agent_tokenops-0.1.0/tests/test_cost_budget.py +55 -0
- agent_tokenops-0.1.0/tests/test_cost_guard.py +36 -0
- agent_tokenops-0.1.0/tests/test_cross_process_budget_gating.py +96 -0
- agent_tokenops-0.1.0/tests/test_crossing_hook.py +105 -0
- agent_tokenops-0.1.0/tests/test_governance_per_agent.py +67 -0
- agent_tokenops-0.1.0/tests/test_integration.py +49 -0
- agent_tokenops-0.1.0/tests/test_ledger.py +93 -0
- agent_tokenops-0.1.0/tests/test_output_runaway.py +39 -0
- agent_tokenops-0.1.0/tests/test_pre_call_worst_case.py +75 -0
- agent_tokenops-0.1.0/tests/test_preview_mode.py +113 -0
- agent_tokenops-0.1.0/tests/test_pricing.py +35 -0
- agent_tokenops-0.1.0/tests/test_progress_guard.py +44 -0
- agent_tokenops-0.1.0/tests/test_propagate.py +41 -0
- agent_tokenops-0.1.0/tests/test_server_enforcement.py +51 -0
- agent_tokenops-0.1.0/tests/test_step_cap.py +43 -0
- agent_tokenops-0.1.0/tests/test_store.py +136 -0
- agent_tokenops-0.1.0/tests/test_tool_fix.py +39 -0
- agent_tokenops-0.1.0/tests/test_tool_output_cap.py +35 -0
- agent_tokenops-0.1.0/tests/test_trajectory_hint.py +244 -0
- agent_tokenops-0.1.0/tests/test_trajectory_hint_e2e.py +208 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tisha Chawla and Susheem Koul
|
|
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,305 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-tokenops
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: TokenOps control plane and SDK for run-aware agent token governance
|
|
5
|
+
Author: Susheem Koul, Tisha Chawla
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/theagentplane/tokenops
|
|
8
|
+
Project-URL: Repository, https://github.com/theagentplane/tokenops
|
|
9
|
+
Project-URL: Issues, https://github.com/theagentplane/tokenops/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/theagentplane/tokenops/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: llm,agents,governance,token-budget,multi-agent,control-plane,cost-control
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: System :: Systems Administration
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE.txt
|
|
23
|
+
Requires-Dist: agent-chronicle>=0.1.1
|
|
24
|
+
Requires-Dist: openai>=1.0
|
|
25
|
+
Requires-Dist: anthropic>=0.40
|
|
26
|
+
Requires-Dist: pyyaml>=6.0
|
|
27
|
+
Requires-Dist: python-dotenv>=1.0
|
|
28
|
+
Requires-Dist: streamlit>=1.30
|
|
29
|
+
Requires-Dist: httpx>=0.27
|
|
30
|
+
Requires-Dist: fastapi>=0.115
|
|
31
|
+
Requires-Dist: uvicorn>=0.32
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
34
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
35
|
+
Requires-Dist: twine>=6.0; extra == "dev"
|
|
36
|
+
Provides-Extra: examples
|
|
37
|
+
Requires-Dist: ddgs>=9.0; extra == "examples"
|
|
38
|
+
Requires-Dist: langchain-core>=0.3; extra == "examples"
|
|
39
|
+
Requires-Dist: langchain-openai>=0.2; extra == "examples"
|
|
40
|
+
Requires-Dist: langchain-anthropic>=0.2; extra == "examples"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
<div align="center">
|
|
44
|
+
|
|
45
|
+
# TokenOps
|
|
46
|
+
|
|
47
|
+
**Run-aware token governance for multi-agent systems.**<br>
|
|
48
|
+
Cap spend and steer behavior across a whole agent workflow — not per request — with a shared ledger and in-path enforcement.
|
|
49
|
+
|
|
50
|
+
[](https://github.com/theagentplane/tokenops/actions/workflows/test.yml)
|
|
51
|
+
[](https://pypi.org/project/agent-tokenops/)
|
|
52
|
+
[](https://github.com/theagentplane/tokenops)
|
|
53
|
+
[](LICENSE.txt)
|
|
54
|
+
[](https://semver.org/)
|
|
55
|
+
[](https://github.com/theagentplane/tokenops/stargazers)
|
|
56
|
+
|
|
57
|
+
<br>
|
|
58
|
+
|
|
59
|
+
<img src="https://raw.githubusercontent.com/theagentplane/tokenops/main/examples/demo-assets/videos/02_governance_on_budget_cap.png" alt="TokenOps Dashboard: governance halt when worst-case cost exceeds remaining run budget" width="720" />
|
|
60
|
+
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<br>
|
|
64
|
+
|
|
65
|
+
TokenOps is a **control plane + SDK** for agent stacks. Entry agents register a run; every LLM and tool crossing shares one `run_id` and one ledger. Policies can halt, mutate, or inject before the next call executes — so a research → summarize → review pipeline stays inside a single budget even across processes.
|
|
66
|
+
|
|
67
|
+
**[Why](#why-tokenops) · [Architecture](#architecture) · [Install](#install) · [Quick start](#quick-start) · [Demos](#demos) · [Comparison](#how-tokenops-compares) · [Make targets](#make-targets) · [Roadmap](#roadmap)**
|
|
68
|
+
|
|
69
|
+
## Why TokenOps
|
|
70
|
+
|
|
71
|
+
- **Govern the run, not the request.** One `run_id` spans every model, tool, and A2A hop in a workflow.
|
|
72
|
+
- **Shared ledger across processes.** Spend, inflight, and halt live in SQLite so multi-agent stacks cannot each burn the full cap locally.
|
|
73
|
+
- **In-path enforcement.** `wrap_complete` runs detect → decide → apply *before* the next LLM call; Chronicle `@boundary` + a crossing hook ingest tool spend.
|
|
74
|
+
- **Steer or stop.** Actuators: `HALT` · `MUTATE` · `INJECT` · reject/queue — not just post-hoc analytics.
|
|
75
|
+
- **Batteries included.** Control plane (`:7700`), Admin + Dashboard UI, ten seeded policies, and runnable A2A benches (two-agent, triad, LangChain brief).
|
|
76
|
+
|
|
77
|
+
## Architecture
|
|
78
|
+
|
|
79
|
+
TokenOps is two layers that share one artifact, the **run**: a control plane that registers runs and stores budgets/policies, and an in-process SDK that enforces at every boundary crossing.
|
|
80
|
+
|
|
81
|
+
```mermaid
|
|
82
|
+
flowchart LR
|
|
83
|
+
subgraph PLANE["Control plane (:7700)"]
|
|
84
|
+
R["POST /v1/runs"] --> DB[("SQLite TOKENOPS_DB<br/>registrations · budgets · policies · ledger")]
|
|
85
|
+
UI["Admin + Dashboard"] --> DB
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
subgraph AGENTS["Agent processes (SDK)"]
|
|
89
|
+
E["Entry agent<br/>entry_task_run_scope"] -->|"register_run"| R
|
|
90
|
+
E -->|"X-TokenOps-Run-Id"| D["Downstream agents"]
|
|
91
|
+
E & D -->|"wrap_complete"| G["Governor<br/>pre_call → detect → decide → apply"]
|
|
92
|
+
E & D -->|"@boundary + crossing hook"| G
|
|
93
|
+
G --> L["Shared ledger<br/>(same run_id)"]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
L --> DB
|
|
97
|
+
DB -->|"governance_config_for"| G
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
| Piece | Owns | Does not own |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| **Control plane** (`python -m tokenops.server`) | `POST /v1/runs`, shared SQLite, Admin/Dashboard | Agent loops, LLM calls, tools |
|
|
103
|
+
| **SDK (in agents)** | `wrap_complete`, ledger/policies, Chronicle crossing hook, run propagation | Ad-hoc run IDs; mounting `/v1/runs` when `TOKENOPS_URL` is set |
|
|
104
|
+
|
|
105
|
+
Chronicle records decision boundaries; TokenOps attaches as the cost/governance observer on live crossings. See [Chronicle](https://github.com/theagentplane/chronicle) for record-and-replay.
|
|
106
|
+
|
|
107
|
+
## Install
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install agent-tokenops
|
|
111
|
+
|
|
112
|
+
# With example / bench extras (LangChain, ddgs):
|
|
113
|
+
pip install "agent-tokenops[examples]"
|
|
114
|
+
|
|
115
|
+
# From source (development):
|
|
116
|
+
pip install -e ".[dev,examples]"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Requires Python 3.10+. PyPI name is `agent-tokenops`; import is still `tokenops`
|
|
120
|
+
(same pattern as Chronicle). See [`RELEASING.md`](RELEASING.md) for releases.
|
|
121
|
+
|
|
122
|
+
## Quick start
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
make install
|
|
126
|
+
cp .env.example .env # optional API keys for demos / your agents
|
|
127
|
+
|
|
128
|
+
make db-reset # optional: clean SQLite + seed governance from default.yaml
|
|
129
|
+
make run # control plane :7700 + Admin/Dashboard :8501
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Wire governance into an agent: register the run at the **entry**, wrap the LLM, and install the Chronicle crossing hook for tools.
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from tokenops import ControlPlaneClient
|
|
136
|
+
from tokenops.control import (
|
|
137
|
+
wrap_complete,
|
|
138
|
+
entry_task_run_scope,
|
|
139
|
+
governance_scope,
|
|
140
|
+
install_crossing_hook,
|
|
141
|
+
)
|
|
142
|
+
from tokenops.providers import complete
|
|
143
|
+
|
|
144
|
+
install_crossing_hook() # once per process; Chronicle on_crossing → Governor.observe
|
|
145
|
+
|
|
146
|
+
client = ControlPlaneClient.from_env() # TOKENOPS_URL or embedded Store
|
|
147
|
+
|
|
148
|
+
# Entry agent: UI omits run_id; entry opens the run on the plane
|
|
149
|
+
with entry_task_run_scope(store, headers=headers, payload=payload, service="planner"):
|
|
150
|
+
with governance_scope(governor, attr, provider=..., model=...):
|
|
151
|
+
governed = wrap_complete(
|
|
152
|
+
governor, controls, attr,
|
|
153
|
+
provider=provider, model=model,
|
|
154
|
+
dispatch=complete, service="planner",
|
|
155
|
+
)
|
|
156
|
+
run_agent(..., complete_fn=governed)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Point agents at the plane and share one DB:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
export TOKENOPS_URL=http://localhost:7700
|
|
163
|
+
export TOKENOPS_DB=tokenops.db # plane + all agents
|
|
164
|
+
make control-plane # :7700
|
|
165
|
+
make ui # Admin + Dashboard :8501
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Full integration checklist: [`.cursor/skills/integrate-tokenops/SKILL.md`](.cursor/skills/integrate-tokenops/SKILL.md) · field guide: [`docs/guides/field-guide-add-tokenops.md`](docs/guides/field-guide-add-tokenops.md).
|
|
169
|
+
|
|
170
|
+
## Demos
|
|
171
|
+
|
|
172
|
+
Each bench is a multi-agent stack with a shared run ledger. Start the plane, agents, and Admin UI with one make target.
|
|
173
|
+
|
|
174
|
+
| Demo | Agents | Run |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| Two-agent | Research → Summarize | `make demo` |
|
|
177
|
+
| Triad | Planner → Researcher → Writer | `make demo-triad` |
|
|
178
|
+
| Brief | Scout → Analyst → Editor (LangChain) | `make demo-brief` |
|
|
179
|
+
| Bench UI | Chat + Simulator only | `make bench-ui` |
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
make demo # plane + research/summarize + Admin UI
|
|
183
|
+
make demo-triad # plane + planner/researcher/writer
|
|
184
|
+
make demo-brief # plane + scout/analyst/editor
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Docker:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
docker compose up --build
|
|
191
|
+
# optional UI: docker compose --profile ui up --build
|
|
192
|
+
# two-agent stack:
|
|
193
|
+
docker compose -f docker-compose.examples.yml up --build
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
See [`examples/README.md`](examples/README.md) and [`docs/control-plane-deploy.md`](docs/control-plane-deploy.md).
|
|
197
|
+
|
|
198
|
+
## How TokenOps compares
|
|
199
|
+
|
|
200
|
+
TokenOps is not a gateway or a tracing dashboard. It governs the **run** — a full agent workflow — and sits alongside the tools you already use for routing and observability.
|
|
201
|
+
|
|
202
|
+
| | TokenOps | LiteLLM / Portkey / AI Gateway | Langfuse |
|
|
203
|
+
|---|:---:|:---:|:---:|
|
|
204
|
+
| Primary focus | Run (stateful) | Request | Trace (observe) |
|
|
205
|
+
| Multi-agent workflow as one unit | Yes | No | Manual stitch |
|
|
206
|
+
| Budget enforcement in-path | Yes (run-aware) | Yes (key/team) | No (analytics) |
|
|
207
|
+
| Steer next call (mutate / inject) | Yes | Routing / fallbacks | No |
|
|
208
|
+
| Shared ledger across agent processes | Yes | N/A | N/A |
|
|
209
|
+
|
|
210
|
+
What this does **not** do: replace your LLM gateway, replace Chronicle-style record-and-replay, or host a SaaS control plane for you. Fail-closed integrity (refuse on missing registration) is optional and upcoming.
|
|
211
|
+
|
|
212
|
+
Longer table with logos: [`docs/product/comparison.md`](docs/product/comparison.md).
|
|
213
|
+
|
|
214
|
+
## Make targets
|
|
215
|
+
|
|
216
|
+
<details>
|
|
217
|
+
<summary>Command reference</summary>
|
|
218
|
+
|
|
219
|
+
| Target | Role |
|
|
220
|
+
|--------|------|
|
|
221
|
+
| `make install` | Editable install with dev + examples extras |
|
|
222
|
+
| `make dist` / `check-dist` | Build sdist+wheel / `twine check` |
|
|
223
|
+
| `make control-plane` | Standalone plane (`python -m tokenops.server`) on `:7700` |
|
|
224
|
+
| `make ui` | Admin + Dashboard on `:8501` |
|
|
225
|
+
| `make run` | Plane + Admin/Dashboard |
|
|
226
|
+
| `make demo` / `demo-triad` / `demo-brief` | Runnable A2A stacks |
|
|
227
|
+
| `make bench-ui` | Chat + Simulator |
|
|
228
|
+
| `make db-reset` | Clear SQLite + reseed from `TOKENOPS_CONFIG` |
|
|
229
|
+
| `make stop` | Kill listeners on `:7700` / `:8501` |
|
|
230
|
+
|
|
231
|
+
</details>
|
|
232
|
+
|
|
233
|
+
## Environment variables
|
|
234
|
+
|
|
235
|
+
| Variable | Purpose |
|
|
236
|
+
|---|---|
|
|
237
|
+
| `TOKENOPS_URL` | Remote plane base URL (e.g. `http://localhost:7700`) → HTTP `register_run` |
|
|
238
|
+
| `TOKENOPS_EMBEDDED` | Set to `1` to force in-process `Store` (tests / single-process) |
|
|
239
|
+
| `TOKENOPS_DB` | SQLite path shared by plane + agents |
|
|
240
|
+
| `TOKENOPS_CONFIG` | YAML for governance seed (core: `src/tokenops/config/default.yaml`) |
|
|
241
|
+
|
|
242
|
+
Production / multi-process: set `TOKENOPS_URL`; agents must **not** mount `/v1/runs`. Tests: `TOKENOPS_EMBEDDED=1` (or omit URL).
|
|
243
|
+
|
|
244
|
+
## Project structure
|
|
245
|
+
|
|
246
|
+
Only `src/tokenops/` is the installable package. Demos and benches stay under `examples/`.
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
src/tokenops/ # installable package
|
|
250
|
+
├── server/ # control plane (:7700, POST /v1/runs)
|
|
251
|
+
├── control/ # SDK: ledger, policies, wrap_complete, crossing hook
|
|
252
|
+
├── providers/ # OpenAI / Anthropic complete dispatch
|
|
253
|
+
├── config/ # default.yaml governance seed
|
|
254
|
+
└── ui/ # Admin + Dashboard (Streamlit)
|
|
255
|
+
examples/ # A2A benches (two-agent, triad, brief) + Chat/Simulator
|
|
256
|
+
benchmarking/ # MetaGPT / browser-use live harness
|
|
257
|
+
docs/ # architecture, policies, guides, product
|
|
258
|
+
tests/ # unit + e2e
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Roadmap
|
|
262
|
+
|
|
263
|
+
TokenOps is early (0.x). Near-term:
|
|
264
|
+
|
|
265
|
+
- User/tag segment-scoped budgets (machinery exists; seed is run-only today).
|
|
266
|
+
- Optional fail-closed mode on missing registration or exceeded budget.
|
|
267
|
+
- Remote observe / decide (fatter plane) for multi-host stacks.
|
|
268
|
+
- Documentation site.
|
|
269
|
+
|
|
270
|
+
Status of each control-plane job: [`CONTROL_PLANE.md`](CONTROL_PLANE.md). Ideas welcome via GitHub issues.
|
|
271
|
+
|
|
272
|
+
## Documentation
|
|
273
|
+
|
|
274
|
+
- [Control plane status](CONTROL_PLANE.md)
|
|
275
|
+
- [Architecture](docs/architecture.md)
|
|
276
|
+
- [Run attribution](docs/run-attribution.md)
|
|
277
|
+
- [Control plane deploy](docs/control-plane-deploy.md)
|
|
278
|
+
- [Field guide](docs/guides/field-guide-add-tokenops.md)
|
|
279
|
+
- [Examples](examples/README.md)
|
|
280
|
+
- [Product: comparison](docs/product/comparison.md) · [shared ledger](docs/product/shared-ledger.md)
|
|
281
|
+
|
|
282
|
+
## Contributing
|
|
283
|
+
|
|
284
|
+
Issues and PRs are welcome. Dev setup:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
make install
|
|
288
|
+
python -m pytest -q
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Contributors
|
|
292
|
+
|
|
293
|
+
Thanks to everyone who has contributed.
|
|
294
|
+
|
|
295
|
+
[](https://github.com/theagentplane/tokenops/graphs/contributors)
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
If TokenOps saves you a runaway agent bill, please [⭐ star the repo](https://github.com/theagentplane/tokenops) so more people can find it.
|
|
300
|
+
|
|
301
|
+
<div align="center">
|
|
302
|
+
|
|
303
|
+
Built by Susheem Koul and Tisha Chawla
|
|
304
|
+
|
|
305
|
+
</div>
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# TokenOps
|
|
4
|
+
|
|
5
|
+
**Run-aware token governance for multi-agent systems.**<br>
|
|
6
|
+
Cap spend and steer behavior across a whole agent workflow — not per request — with a shared ledger and in-path enforcement.
|
|
7
|
+
|
|
8
|
+
[](https://github.com/theagentplane/tokenops/actions/workflows/test.yml)
|
|
9
|
+
[](https://pypi.org/project/agent-tokenops/)
|
|
10
|
+
[](https://github.com/theagentplane/tokenops)
|
|
11
|
+
[](LICENSE.txt)
|
|
12
|
+
[](https://semver.org/)
|
|
13
|
+
[](https://github.com/theagentplane/tokenops/stargazers)
|
|
14
|
+
|
|
15
|
+
<br>
|
|
16
|
+
|
|
17
|
+
<img src="https://raw.githubusercontent.com/theagentplane/tokenops/main/examples/demo-assets/videos/02_governance_on_budget_cap.png" alt="TokenOps Dashboard: governance halt when worst-case cost exceeds remaining run budget" width="720" />
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<br>
|
|
22
|
+
|
|
23
|
+
TokenOps is a **control plane + SDK** for agent stacks. Entry agents register a run; every LLM and tool crossing shares one `run_id` and one ledger. Policies can halt, mutate, or inject before the next call executes — so a research → summarize → review pipeline stays inside a single budget even across processes.
|
|
24
|
+
|
|
25
|
+
**[Why](#why-tokenops) · [Architecture](#architecture) · [Install](#install) · [Quick start](#quick-start) · [Demos](#demos) · [Comparison](#how-tokenops-compares) · [Make targets](#make-targets) · [Roadmap](#roadmap)**
|
|
26
|
+
|
|
27
|
+
## Why TokenOps
|
|
28
|
+
|
|
29
|
+
- **Govern the run, not the request.** One `run_id` spans every model, tool, and A2A hop in a workflow.
|
|
30
|
+
- **Shared ledger across processes.** Spend, inflight, and halt live in SQLite so multi-agent stacks cannot each burn the full cap locally.
|
|
31
|
+
- **In-path enforcement.** `wrap_complete` runs detect → decide → apply *before* the next LLM call; Chronicle `@boundary` + a crossing hook ingest tool spend.
|
|
32
|
+
- **Steer or stop.** Actuators: `HALT` · `MUTATE` · `INJECT` · reject/queue — not just post-hoc analytics.
|
|
33
|
+
- **Batteries included.** Control plane (`:7700`), Admin + Dashboard UI, ten seeded policies, and runnable A2A benches (two-agent, triad, LangChain brief).
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
TokenOps is two layers that share one artifact, the **run**: a control plane that registers runs and stores budgets/policies, and an in-process SDK that enforces at every boundary crossing.
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart LR
|
|
41
|
+
subgraph PLANE["Control plane (:7700)"]
|
|
42
|
+
R["POST /v1/runs"] --> DB[("SQLite TOKENOPS_DB<br/>registrations · budgets · policies · ledger")]
|
|
43
|
+
UI["Admin + Dashboard"] --> DB
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
subgraph AGENTS["Agent processes (SDK)"]
|
|
47
|
+
E["Entry agent<br/>entry_task_run_scope"] -->|"register_run"| R
|
|
48
|
+
E -->|"X-TokenOps-Run-Id"| D["Downstream agents"]
|
|
49
|
+
E & D -->|"wrap_complete"| G["Governor<br/>pre_call → detect → decide → apply"]
|
|
50
|
+
E & D -->|"@boundary + crossing hook"| G
|
|
51
|
+
G --> L["Shared ledger<br/>(same run_id)"]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
L --> DB
|
|
55
|
+
DB -->|"governance_config_for"| G
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
| Piece | Owns | Does not own |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| **Control plane** (`python -m tokenops.server`) | `POST /v1/runs`, shared SQLite, Admin/Dashboard | Agent loops, LLM calls, tools |
|
|
61
|
+
| **SDK (in agents)** | `wrap_complete`, ledger/policies, Chronicle crossing hook, run propagation | Ad-hoc run IDs; mounting `/v1/runs` when `TOKENOPS_URL` is set |
|
|
62
|
+
|
|
63
|
+
Chronicle records decision boundaries; TokenOps attaches as the cost/governance observer on live crossings. See [Chronicle](https://github.com/theagentplane/chronicle) for record-and-replay.
|
|
64
|
+
|
|
65
|
+
## Install
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install agent-tokenops
|
|
69
|
+
|
|
70
|
+
# With example / bench extras (LangChain, ddgs):
|
|
71
|
+
pip install "agent-tokenops[examples]"
|
|
72
|
+
|
|
73
|
+
# From source (development):
|
|
74
|
+
pip install -e ".[dev,examples]"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Requires Python 3.10+. PyPI name is `agent-tokenops`; import is still `tokenops`
|
|
78
|
+
(same pattern as Chronicle). See [`RELEASING.md`](RELEASING.md) for releases.
|
|
79
|
+
|
|
80
|
+
## Quick start
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
make install
|
|
84
|
+
cp .env.example .env # optional API keys for demos / your agents
|
|
85
|
+
|
|
86
|
+
make db-reset # optional: clean SQLite + seed governance from default.yaml
|
|
87
|
+
make run # control plane :7700 + Admin/Dashboard :8501
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Wire governance into an agent: register the run at the **entry**, wrap the LLM, and install the Chronicle crossing hook for tools.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from tokenops import ControlPlaneClient
|
|
94
|
+
from tokenops.control import (
|
|
95
|
+
wrap_complete,
|
|
96
|
+
entry_task_run_scope,
|
|
97
|
+
governance_scope,
|
|
98
|
+
install_crossing_hook,
|
|
99
|
+
)
|
|
100
|
+
from tokenops.providers import complete
|
|
101
|
+
|
|
102
|
+
install_crossing_hook() # once per process; Chronicle on_crossing → Governor.observe
|
|
103
|
+
|
|
104
|
+
client = ControlPlaneClient.from_env() # TOKENOPS_URL or embedded Store
|
|
105
|
+
|
|
106
|
+
# Entry agent: UI omits run_id; entry opens the run on the plane
|
|
107
|
+
with entry_task_run_scope(store, headers=headers, payload=payload, service="planner"):
|
|
108
|
+
with governance_scope(governor, attr, provider=..., model=...):
|
|
109
|
+
governed = wrap_complete(
|
|
110
|
+
governor, controls, attr,
|
|
111
|
+
provider=provider, model=model,
|
|
112
|
+
dispatch=complete, service="planner",
|
|
113
|
+
)
|
|
114
|
+
run_agent(..., complete_fn=governed)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Point agents at the plane and share one DB:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
export TOKENOPS_URL=http://localhost:7700
|
|
121
|
+
export TOKENOPS_DB=tokenops.db # plane + all agents
|
|
122
|
+
make control-plane # :7700
|
|
123
|
+
make ui # Admin + Dashboard :8501
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Full integration checklist: [`.cursor/skills/integrate-tokenops/SKILL.md`](.cursor/skills/integrate-tokenops/SKILL.md) · field guide: [`docs/guides/field-guide-add-tokenops.md`](docs/guides/field-guide-add-tokenops.md).
|
|
127
|
+
|
|
128
|
+
## Demos
|
|
129
|
+
|
|
130
|
+
Each bench is a multi-agent stack with a shared run ledger. Start the plane, agents, and Admin UI with one make target.
|
|
131
|
+
|
|
132
|
+
| Demo | Agents | Run |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| Two-agent | Research → Summarize | `make demo` |
|
|
135
|
+
| Triad | Planner → Researcher → Writer | `make demo-triad` |
|
|
136
|
+
| Brief | Scout → Analyst → Editor (LangChain) | `make demo-brief` |
|
|
137
|
+
| Bench UI | Chat + Simulator only | `make bench-ui` |
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
make demo # plane + research/summarize + Admin UI
|
|
141
|
+
make demo-triad # plane + planner/researcher/writer
|
|
142
|
+
make demo-brief # plane + scout/analyst/editor
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Docker:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
docker compose up --build
|
|
149
|
+
# optional UI: docker compose --profile ui up --build
|
|
150
|
+
# two-agent stack:
|
|
151
|
+
docker compose -f docker-compose.examples.yml up --build
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
See [`examples/README.md`](examples/README.md) and [`docs/control-plane-deploy.md`](docs/control-plane-deploy.md).
|
|
155
|
+
|
|
156
|
+
## How TokenOps compares
|
|
157
|
+
|
|
158
|
+
TokenOps is not a gateway or a tracing dashboard. It governs the **run** — a full agent workflow — and sits alongside the tools you already use for routing and observability.
|
|
159
|
+
|
|
160
|
+
| | TokenOps | LiteLLM / Portkey / AI Gateway | Langfuse |
|
|
161
|
+
|---|:---:|:---:|:---:|
|
|
162
|
+
| Primary focus | Run (stateful) | Request | Trace (observe) |
|
|
163
|
+
| Multi-agent workflow as one unit | Yes | No | Manual stitch |
|
|
164
|
+
| Budget enforcement in-path | Yes (run-aware) | Yes (key/team) | No (analytics) |
|
|
165
|
+
| Steer next call (mutate / inject) | Yes | Routing / fallbacks | No |
|
|
166
|
+
| Shared ledger across agent processes | Yes | N/A | N/A |
|
|
167
|
+
|
|
168
|
+
What this does **not** do: replace your LLM gateway, replace Chronicle-style record-and-replay, or host a SaaS control plane for you. Fail-closed integrity (refuse on missing registration) is optional and upcoming.
|
|
169
|
+
|
|
170
|
+
Longer table with logos: [`docs/product/comparison.md`](docs/product/comparison.md).
|
|
171
|
+
|
|
172
|
+
## Make targets
|
|
173
|
+
|
|
174
|
+
<details>
|
|
175
|
+
<summary>Command reference</summary>
|
|
176
|
+
|
|
177
|
+
| Target | Role |
|
|
178
|
+
|--------|------|
|
|
179
|
+
| `make install` | Editable install with dev + examples extras |
|
|
180
|
+
| `make dist` / `check-dist` | Build sdist+wheel / `twine check` |
|
|
181
|
+
| `make control-plane` | Standalone plane (`python -m tokenops.server`) on `:7700` |
|
|
182
|
+
| `make ui` | Admin + Dashboard on `:8501` |
|
|
183
|
+
| `make run` | Plane + Admin/Dashboard |
|
|
184
|
+
| `make demo` / `demo-triad` / `demo-brief` | Runnable A2A stacks |
|
|
185
|
+
| `make bench-ui` | Chat + Simulator |
|
|
186
|
+
| `make db-reset` | Clear SQLite + reseed from `TOKENOPS_CONFIG` |
|
|
187
|
+
| `make stop` | Kill listeners on `:7700` / `:8501` |
|
|
188
|
+
|
|
189
|
+
</details>
|
|
190
|
+
|
|
191
|
+
## Environment variables
|
|
192
|
+
|
|
193
|
+
| Variable | Purpose |
|
|
194
|
+
|---|---|
|
|
195
|
+
| `TOKENOPS_URL` | Remote plane base URL (e.g. `http://localhost:7700`) → HTTP `register_run` |
|
|
196
|
+
| `TOKENOPS_EMBEDDED` | Set to `1` to force in-process `Store` (tests / single-process) |
|
|
197
|
+
| `TOKENOPS_DB` | SQLite path shared by plane + agents |
|
|
198
|
+
| `TOKENOPS_CONFIG` | YAML for governance seed (core: `src/tokenops/config/default.yaml`) |
|
|
199
|
+
|
|
200
|
+
Production / multi-process: set `TOKENOPS_URL`; agents must **not** mount `/v1/runs`. Tests: `TOKENOPS_EMBEDDED=1` (or omit URL).
|
|
201
|
+
|
|
202
|
+
## Project structure
|
|
203
|
+
|
|
204
|
+
Only `src/tokenops/` is the installable package. Demos and benches stay under `examples/`.
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
src/tokenops/ # installable package
|
|
208
|
+
├── server/ # control plane (:7700, POST /v1/runs)
|
|
209
|
+
├── control/ # SDK: ledger, policies, wrap_complete, crossing hook
|
|
210
|
+
├── providers/ # OpenAI / Anthropic complete dispatch
|
|
211
|
+
├── config/ # default.yaml governance seed
|
|
212
|
+
└── ui/ # Admin + Dashboard (Streamlit)
|
|
213
|
+
examples/ # A2A benches (two-agent, triad, brief) + Chat/Simulator
|
|
214
|
+
benchmarking/ # MetaGPT / browser-use live harness
|
|
215
|
+
docs/ # architecture, policies, guides, product
|
|
216
|
+
tests/ # unit + e2e
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Roadmap
|
|
220
|
+
|
|
221
|
+
TokenOps is early (0.x). Near-term:
|
|
222
|
+
|
|
223
|
+
- User/tag segment-scoped budgets (machinery exists; seed is run-only today).
|
|
224
|
+
- Optional fail-closed mode on missing registration or exceeded budget.
|
|
225
|
+
- Remote observe / decide (fatter plane) for multi-host stacks.
|
|
226
|
+
- Documentation site.
|
|
227
|
+
|
|
228
|
+
Status of each control-plane job: [`CONTROL_PLANE.md`](CONTROL_PLANE.md). Ideas welcome via GitHub issues.
|
|
229
|
+
|
|
230
|
+
## Documentation
|
|
231
|
+
|
|
232
|
+
- [Control plane status](CONTROL_PLANE.md)
|
|
233
|
+
- [Architecture](docs/architecture.md)
|
|
234
|
+
- [Run attribution](docs/run-attribution.md)
|
|
235
|
+
- [Control plane deploy](docs/control-plane-deploy.md)
|
|
236
|
+
- [Field guide](docs/guides/field-guide-add-tokenops.md)
|
|
237
|
+
- [Examples](examples/README.md)
|
|
238
|
+
- [Product: comparison](docs/product/comparison.md) · [shared ledger](docs/product/shared-ledger.md)
|
|
239
|
+
|
|
240
|
+
## Contributing
|
|
241
|
+
|
|
242
|
+
Issues and PRs are welcome. Dev setup:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
make install
|
|
246
|
+
python -m pytest -q
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Contributors
|
|
250
|
+
|
|
251
|
+
Thanks to everyone who has contributed.
|
|
252
|
+
|
|
253
|
+
[](https://github.com/theagentplane/tokenops/graphs/contributors)
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
If TokenOps saves you a runaway agent bill, please [⭐ star the repo](https://github.com/theagentplane/tokenops) so more people can find it.
|
|
258
|
+
|
|
259
|
+
<div align="center">
|
|
260
|
+
|
|
261
|
+
Built by Susheem Koul and Tisha Chawla
|
|
262
|
+
|
|
263
|
+
</div>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agent-tokenops"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "TokenOps control plane and SDK for run-aware agent token governance"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE.txt"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Susheem Koul" },
|
|
15
|
+
{ name = "Tisha Chawla" },
|
|
16
|
+
]
|
|
17
|
+
keywords = [
|
|
18
|
+
"llm",
|
|
19
|
+
"agents",
|
|
20
|
+
"governance",
|
|
21
|
+
"token-budget",
|
|
22
|
+
"multi-agent",
|
|
23
|
+
"control-plane",
|
|
24
|
+
"cost-control",
|
|
25
|
+
]
|
|
26
|
+
classifiers = [
|
|
27
|
+
"Development Status :: 3 - Alpha",
|
|
28
|
+
"Intended Audience :: Developers",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
34
|
+
"Topic :: System :: Systems Administration",
|
|
35
|
+
]
|
|
36
|
+
dependencies = [
|
|
37
|
+
"agent-chronicle>=0.1.1",
|
|
38
|
+
"openai>=1.0",
|
|
39
|
+
"anthropic>=0.40",
|
|
40
|
+
"pyyaml>=6.0",
|
|
41
|
+
"python-dotenv>=1.0",
|
|
42
|
+
"streamlit>=1.30",
|
|
43
|
+
"httpx>=0.27",
|
|
44
|
+
"fastapi>=0.115",
|
|
45
|
+
"uvicorn>=0.32",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest>=8.0",
|
|
51
|
+
"build>=1.2",
|
|
52
|
+
"twine>=6.0",
|
|
53
|
+
]
|
|
54
|
+
examples = [
|
|
55
|
+
"ddgs>=9.0",
|
|
56
|
+
"langchain-core>=0.3",
|
|
57
|
+
"langchain-openai>=0.2",
|
|
58
|
+
"langchain-anthropic>=0.2",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[project.urls]
|
|
62
|
+
Homepage = "https://github.com/theagentplane/tokenops"
|
|
63
|
+
Repository = "https://github.com/theagentplane/tokenops"
|
|
64
|
+
Issues = "https://github.com/theagentplane/tokenops/issues"
|
|
65
|
+
Changelog = "https://github.com/theagentplane/tokenops/blob/main/CHANGELOG.md"
|
|
66
|
+
|
|
67
|
+
[tool.pytest.ini_options]
|
|
68
|
+
testpaths = ["tests"]
|
|
69
|
+
pythonpath = ["src", "."]
|
|
70
|
+
markers = [
|
|
71
|
+
"e2e: example / bench end-to-end tests (not run in default CI)",
|
|
72
|
+
"live: requires API keys or vendored frameworks",
|
|
73
|
+
]
|
|
74
|
+
addopts = "-m 'not e2e and not live'"
|
|
75
|
+
|
|
76
|
+
[tool.setuptools.package-dir]
|
|
77
|
+
"" = "src"
|
|
78
|
+
|
|
79
|
+
[tool.setuptools.packages.find]
|
|
80
|
+
where = ["src"]
|
|
81
|
+
include = ["tokenops*"]
|
|
82
|
+
|
|
83
|
+
# Ship the default governance YAML with the wheel (loader resolves via Path(__file__)).
|
|
84
|
+
[tool.setuptools.package-data]
|
|
85
|
+
tokenops = ["config/*.yaml"]
|