agent-tokenops 1.0.1__tar.gz → 2.0.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-1.0.1/src/agent_tokenops.egg-info → agent_tokenops-2.0.0}/PKG-INFO +6 -3
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/README.md +5 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/pyproject.toml +25 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0/src/agent_tokenops.egg-info}/PKG-INFO +6 -3
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/agent_tokenops.egg-info/SOURCES.txt +44 -34
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/__init__.py +18 -18
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/_version.py +1 -1
- agent_tokenops-2.0.0/src/tokenops/capabilities/__init__.py +32 -0
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/capabilities}/chronicle_trace_utils.py +1 -1
- agent_tokenops-2.0.0/src/tokenops/capabilities/complete_wrapper.py +131 -0
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/capabilities}/crossing.py +6 -6
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/capabilities}/ledger_writers.py +5 -5
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/capabilities}/run.py +14 -19
- agent_tokenops-2.0.0/src/tokenops/capabilities/step_observation.py +107 -0
- agent_tokenops-2.0.0/src/tokenops/capabilities/stream_wrapper.py +174 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/config/default.yaml +1 -1
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/demo.py +4 -3
- agent_tokenops-2.0.0/src/tokenops/framework/__init__.py +114 -0
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/attribution.py +4 -9
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/boundary.py +9 -30
- agent_tokenops-2.0.0/src/tokenops/framework/budget.py +112 -0
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/config.py +13 -13
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/context.py +3 -13
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/core.py +18 -9
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/engine.py +7 -5
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/ledger.py +42 -141
- agent_tokenops-2.0.0/src/tokenops/framework/ledger_backend.py +40 -0
- agent_tokenops-2.0.0/src/tokenops/framework/ledger_events.py +37 -0
- agent_tokenops-2.0.0/src/tokenops/framework/message_steering.py +87 -0
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/models.py +0 -5
- agent_tokenops-2.0.0/src/tokenops/framework/observation_utils.py +34 -0
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/__init__.py +1 -1
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/_util.py +2 -1
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/concurrency_cap.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/context_compaction.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/cost_budget.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/cost_guard.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/output_runaway.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/pre_call_worst_case.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/progress_guard.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/step_cap.py +1 -1
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/time_budget.py +1 -1
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/tool_fix.py +14 -5
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policies/tool_output_cap.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/policy_labels.py +1 -1
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/pricing.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/request_context.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/framework}/usage.py +1 -1
- agent_tokenops-2.0.0/src/tokenops/interfaces/__init__.py +6 -0
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/interfaces}/http.py +2 -2
- {agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/interfaces}/instrument.py +4 -4
- agent_tokenops-2.0.0/src/tokenops/repositories/control_plane_types.py +23 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_actuators.py +8 -7
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_apply.py +6 -14
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_async_ledger.py +3 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_attribution.py +4 -4
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_attribution_ledger_policies_e2e.py +9 -6
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_boundary.py +6 -4
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_chronicle_boundary.py +6 -4
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_compaction_metadata.py +7 -5
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_concurrency_cap.py +2 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_config.py +2 -1
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_context_compaction.py +10 -10
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_cost_budget.py +4 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_cost_guard.py +3 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_cross_process_budget_gating.py +3 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_crossing_hook.py +6 -9
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_demo.py +2 -1
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_governance_event_names.py +17 -12
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_integration.py +6 -3
- agent_tokenops-2.0.0/tests/test_layering.py +58 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_ledger.py +8 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_llm_boundary_precall.py +7 -4
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_output_runaway.py +2 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_policies_wrap_integration.py +8 -15
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_policy_coordination.py +2 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_policy_names.py +7 -7
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_pre_call_worst_case.py +4 -11
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_preview_mode.py +9 -12
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_pricing.py +2 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_progress_guard.py +2 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_provider_usage.py +8 -8
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_reason_encoding.py +1 -1
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_step_cap.py +4 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_thread_safety.py +2 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_time_budget.py +4 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_tokenops_run.py +3 -3
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_tool_fix.py +2 -2
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_tool_output_cap.py +3 -3
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_wrap_adapters.py +7 -10
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_wrap_complete_chronicle.py +7 -10
- agent_tokenops-1.0.1/src/tokenops/control/__init__.py +0 -162
- agent_tokenops-1.0.1/src/tokenops/control/integration.py +0 -463
- agent_tokenops-1.0.1/tests/test_deprecated_names.py +0 -21
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/LICENSE.txt +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/setup.cfg +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/agent_tokenops.egg-info/dependency_links.txt +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/agent_tokenops.egg-info/requires.txt +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/agent_tokenops.egg-info/top_level.txt +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/adapters/__init__.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/adapters/langchain.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/config/__init__.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/config/loader.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/env.py +0 -0
- /agent_tokenops-1.0.1/src/tokenops/repositories/control_plane_types.py → /agent_tokenops-2.0.0/src/tokenops/framework/ledger_types.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/providers/__init__.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/providers/anthropic.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/providers/factory.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/providers/openai.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/providers/types.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/py.typed +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/repositories/__init__.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/repositories/control_plane_client.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/repositories/control_plane_errors.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/src/tokenops/repositories/ledger_event_writer.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_a2a_health.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_a2a_server_errors.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_httpx_instrumentation.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_repositories_control_plane_client.py +0 -0
- {agent_tokenops-1.0.1 → agent_tokenops-2.0.0}/tests/test_repositories_ledger_event_writer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-tokenops
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Run-aware token governance for agents: budgets, policies and halts on Chronicle and the AgentPlane control plane
|
|
5
5
|
Author: Susheem Koul, Tisha Chawla
|
|
6
6
|
License-Expression: MIT
|
|
@@ -124,7 +124,8 @@ Wrap your model call once, then hand the wrapped version to your agent.
|
|
|
124
124
|
|
|
125
125
|
```python
|
|
126
126
|
from tokenops import tokenops_run
|
|
127
|
-
from tokenops.
|
|
127
|
+
from tokenops.capabilities import wrap_complete
|
|
128
|
+
from tokenops.framework import Halt
|
|
128
129
|
from tokenops.providers import complete
|
|
129
130
|
|
|
130
131
|
GOVERNANCE = {"governance": {
|
|
@@ -286,7 +287,9 @@ Only `src/tokenops/` is the installable package. Demos and benches stay under `e
|
|
|
286
287
|
|
|
287
288
|
```
|
|
288
289
|
src/tokenops/ # installable package
|
|
289
|
-
├──
|
|
290
|
+
├── framework/ # in-process machinery: ledger, policies, pricing, governor (no network)
|
|
291
|
+
├── capabilities/ # tokenops_run, wrap_complete, the Chronicle hook
|
|
292
|
+
├── interfaces/ # instrument_app, HTTP error mapping
|
|
290
293
|
├── repositories/ # the control-plane client and the background ledger writer
|
|
291
294
|
├── providers/ # OpenAI / Anthropic complete dispatch
|
|
292
295
|
└── config/ # packaged default governance
|
|
@@ -83,7 +83,8 @@ Wrap your model call once, then hand the wrapped version to your agent.
|
|
|
83
83
|
|
|
84
84
|
```python
|
|
85
85
|
from tokenops import tokenops_run
|
|
86
|
-
from tokenops.
|
|
86
|
+
from tokenops.capabilities import wrap_complete
|
|
87
|
+
from tokenops.framework import Halt
|
|
87
88
|
from tokenops.providers import complete
|
|
88
89
|
|
|
89
90
|
GOVERNANCE = {"governance": {
|
|
@@ -245,7 +246,9 @@ Only `src/tokenops/` is the installable package. Demos and benches stay under `e
|
|
|
245
246
|
|
|
246
247
|
```
|
|
247
248
|
src/tokenops/ # installable package
|
|
248
|
-
├──
|
|
249
|
+
├── framework/ # in-process machinery: ledger, policies, pricing, governor (no network)
|
|
250
|
+
├── capabilities/ # tokenops_run, wrap_complete, the Chronicle hook
|
|
251
|
+
├── interfaces/ # instrument_app, HTTP error mapping
|
|
249
252
|
├── repositories/ # the control-plane client and the background ledger writer
|
|
250
253
|
├── providers/ # OpenAI / Anthropic complete dispatch
|
|
251
254
|
└── config/ # packaged default governance
|
|
@@ -116,6 +116,7 @@ mypy_path = "src"
|
|
|
116
116
|
packages = ["tokenops"]
|
|
117
117
|
ignore_missing_imports = true
|
|
118
118
|
warn_unused_configs = true
|
|
119
|
+
warn_redundant_casts = true
|
|
119
120
|
# Gradual typing: adapters are LangChain-heavy; tighten later.
|
|
120
121
|
exclude = "(?x)(tokenops/adapters/)"
|
|
121
122
|
|
|
@@ -128,6 +129,30 @@ module = [
|
|
|
128
129
|
]
|
|
129
130
|
follow_imports = "skip"
|
|
130
131
|
|
|
132
|
+
# The layered packages are held to `mypy --strict`.
|
|
133
|
+
[[tool.mypy.overrides]]
|
|
134
|
+
module = [
|
|
135
|
+
"tokenops.framework",
|
|
136
|
+
"tokenops.framework.*",
|
|
137
|
+
"tokenops.capabilities",
|
|
138
|
+
"tokenops.capabilities.*",
|
|
139
|
+
"tokenops.interfaces",
|
|
140
|
+
"tokenops.interfaces.*",
|
|
141
|
+
"tokenops.repositories",
|
|
142
|
+
"tokenops.repositories.*",
|
|
143
|
+
]
|
|
144
|
+
# `strict = true` is not accepted per module, so the --strict flags are listed.
|
|
145
|
+
disallow_untyped_defs = true
|
|
146
|
+
disallow_incomplete_defs = true
|
|
147
|
+
disallow_untyped_calls = true
|
|
148
|
+
disallow_untyped_decorators = true
|
|
149
|
+
disallow_any_generics = true
|
|
150
|
+
check_untyped_defs = true
|
|
151
|
+
no_implicit_optional = true
|
|
152
|
+
warn_return_any = true
|
|
153
|
+
warn_unused_ignores = true
|
|
154
|
+
strict_equality = true
|
|
155
|
+
|
|
131
156
|
[tool.setuptools.package-dir]
|
|
132
157
|
"" = "src"
|
|
133
158
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-tokenops
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Run-aware token governance for agents: budgets, policies and halts on Chronicle and the AgentPlane control plane
|
|
5
5
|
Author: Susheem Koul, Tisha Chawla
|
|
6
6
|
License-Expression: MIT
|
|
@@ -124,7 +124,8 @@ Wrap your model call once, then hand the wrapped version to your agent.
|
|
|
124
124
|
|
|
125
125
|
```python
|
|
126
126
|
from tokenops import tokenops_run
|
|
127
|
-
from tokenops.
|
|
127
|
+
from tokenops.capabilities import wrap_complete
|
|
128
|
+
from tokenops.framework import Halt
|
|
128
129
|
from tokenops.providers import complete
|
|
129
130
|
|
|
130
131
|
GOVERNANCE = {"governance": {
|
|
@@ -286,7 +287,9 @@ Only `src/tokenops/` is the installable package. Demos and benches stay under `e
|
|
|
286
287
|
|
|
287
288
|
```
|
|
288
289
|
src/tokenops/ # installable package
|
|
289
|
-
├──
|
|
290
|
+
├── framework/ # in-process machinery: ledger, policies, pricing, governor (no network)
|
|
291
|
+
├── capabilities/ # tokenops_run, wrap_complete, the Chronicle hook
|
|
292
|
+
├── interfaces/ # instrument_app, HTTP error mapping
|
|
290
293
|
├── repositories/ # the control-plane client and the background ledger writer
|
|
291
294
|
├── providers/ # OpenAI / Anthropic complete dispatch
|
|
292
295
|
└── config/ # packaged default governance
|
|
@@ -13,42 +13,52 @@ src/tokenops/env.py
|
|
|
13
13
|
src/tokenops/py.typed
|
|
14
14
|
src/tokenops/adapters/__init__.py
|
|
15
15
|
src/tokenops/adapters/langchain.py
|
|
16
|
+
src/tokenops/capabilities/__init__.py
|
|
17
|
+
src/tokenops/capabilities/chronicle_trace_utils.py
|
|
18
|
+
src/tokenops/capabilities/complete_wrapper.py
|
|
19
|
+
src/tokenops/capabilities/crossing.py
|
|
20
|
+
src/tokenops/capabilities/ledger_writers.py
|
|
21
|
+
src/tokenops/capabilities/run.py
|
|
22
|
+
src/tokenops/capabilities/step_observation.py
|
|
23
|
+
src/tokenops/capabilities/stream_wrapper.py
|
|
16
24
|
src/tokenops/config/__init__.py
|
|
17
25
|
src/tokenops/config/default.yaml
|
|
18
26
|
src/tokenops/config/loader.py
|
|
19
|
-
src/tokenops/
|
|
20
|
-
src/tokenops/
|
|
21
|
-
src/tokenops/
|
|
22
|
-
src/tokenops/
|
|
23
|
-
src/tokenops/
|
|
24
|
-
src/tokenops/
|
|
25
|
-
src/tokenops/
|
|
26
|
-
src/tokenops/
|
|
27
|
-
src/tokenops/
|
|
28
|
-
src/tokenops/
|
|
29
|
-
src/tokenops/
|
|
30
|
-
src/tokenops/
|
|
31
|
-
src/tokenops/
|
|
32
|
-
src/tokenops/
|
|
33
|
-
src/tokenops/
|
|
34
|
-
src/tokenops/
|
|
35
|
-
src/tokenops/
|
|
36
|
-
src/tokenops/
|
|
37
|
-
src/tokenops/
|
|
38
|
-
src/tokenops/
|
|
39
|
-
src/tokenops/
|
|
40
|
-
src/tokenops/
|
|
41
|
-
src/tokenops/
|
|
42
|
-
src/tokenops/
|
|
43
|
-
src/tokenops/
|
|
44
|
-
src/tokenops/
|
|
45
|
-
src/tokenops/
|
|
46
|
-
src/tokenops/
|
|
47
|
-
src/tokenops/
|
|
48
|
-
src/tokenops/
|
|
49
|
-
src/tokenops/
|
|
50
|
-
src/tokenops/
|
|
51
|
-
src/tokenops/
|
|
27
|
+
src/tokenops/framework/__init__.py
|
|
28
|
+
src/tokenops/framework/attribution.py
|
|
29
|
+
src/tokenops/framework/boundary.py
|
|
30
|
+
src/tokenops/framework/budget.py
|
|
31
|
+
src/tokenops/framework/config.py
|
|
32
|
+
src/tokenops/framework/context.py
|
|
33
|
+
src/tokenops/framework/core.py
|
|
34
|
+
src/tokenops/framework/engine.py
|
|
35
|
+
src/tokenops/framework/ledger.py
|
|
36
|
+
src/tokenops/framework/ledger_backend.py
|
|
37
|
+
src/tokenops/framework/ledger_events.py
|
|
38
|
+
src/tokenops/framework/ledger_types.py
|
|
39
|
+
src/tokenops/framework/message_steering.py
|
|
40
|
+
src/tokenops/framework/models.py
|
|
41
|
+
src/tokenops/framework/observation_utils.py
|
|
42
|
+
src/tokenops/framework/policy_labels.py
|
|
43
|
+
src/tokenops/framework/pricing.py
|
|
44
|
+
src/tokenops/framework/request_context.py
|
|
45
|
+
src/tokenops/framework/usage.py
|
|
46
|
+
src/tokenops/framework/policies/__init__.py
|
|
47
|
+
src/tokenops/framework/policies/_util.py
|
|
48
|
+
src/tokenops/framework/policies/concurrency_cap.py
|
|
49
|
+
src/tokenops/framework/policies/context_compaction.py
|
|
50
|
+
src/tokenops/framework/policies/cost_budget.py
|
|
51
|
+
src/tokenops/framework/policies/cost_guard.py
|
|
52
|
+
src/tokenops/framework/policies/output_runaway.py
|
|
53
|
+
src/tokenops/framework/policies/pre_call_worst_case.py
|
|
54
|
+
src/tokenops/framework/policies/progress_guard.py
|
|
55
|
+
src/tokenops/framework/policies/step_cap.py
|
|
56
|
+
src/tokenops/framework/policies/time_budget.py
|
|
57
|
+
src/tokenops/framework/policies/tool_fix.py
|
|
58
|
+
src/tokenops/framework/policies/tool_output_cap.py
|
|
59
|
+
src/tokenops/interfaces/__init__.py
|
|
60
|
+
src/tokenops/interfaces/http.py
|
|
61
|
+
src/tokenops/interfaces/instrument.py
|
|
52
62
|
src/tokenops/providers/__init__.py
|
|
53
63
|
src/tokenops/providers/anthropic.py
|
|
54
64
|
src/tokenops/providers/factory.py
|
|
@@ -77,10 +87,10 @@ tests/test_cost_guard.py
|
|
|
77
87
|
tests/test_cross_process_budget_gating.py
|
|
78
88
|
tests/test_crossing_hook.py
|
|
79
89
|
tests/test_demo.py
|
|
80
|
-
tests/test_deprecated_names.py
|
|
81
90
|
tests/test_governance_event_names.py
|
|
82
91
|
tests/test_httpx_instrumentation.py
|
|
83
92
|
tests/test_integration.py
|
|
93
|
+
tests/test_layering.py
|
|
84
94
|
tests/test_ledger.py
|
|
85
95
|
tests/test_llm_boundary_precall.py
|
|
86
96
|
tests/test_output_runaway.py
|
|
@@ -11,38 +11,38 @@ def init() -> None:
|
|
|
11
11
|
"""Process bootstrap: install the Chronicle crossing hook (idempotent).
|
|
12
12
|
|
|
13
13
|
Prefer calling this (or :meth:`ControlPlaneClient.from_env` /
|
|
14
|
-
:func:`~tokenops.
|
|
15
|
-
callers need not remember :func:`~tokenops.
|
|
14
|
+
:func:`~tokenops.interfaces.instrument.instrument_app`) on agent startup so
|
|
15
|
+
callers need not remember :func:`~tokenops.capabilities.crossing.install_crossing_hook`.
|
|
16
16
|
"""
|
|
17
|
-
from tokenops.
|
|
17
|
+
from tokenops.capabilities.crossing import install_crossing_hook
|
|
18
18
|
|
|
19
19
|
install_crossing_hook()
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
# First-class SDK surface for agents / UIs talking to the plane.
|
|
23
|
-
from tokenops.
|
|
24
|
-
from tokenops.
|
|
25
|
-
|
|
23
|
+
from tokenops.capabilities.ledger_writers import flush_ledger_writes as flush_ledger_writes
|
|
24
|
+
from tokenops.capabilities.run import (
|
|
25
|
+
TokenOpsBound as TokenOpsBound,
|
|
26
|
+
)
|
|
27
|
+
from tokenops.capabilities.run import (
|
|
28
|
+
agentplane_run_scope as agentplane_run_scope,
|
|
29
|
+
)
|
|
30
|
+
from tokenops.capabilities.run import (
|
|
31
|
+
tokenops_run as tokenops_run,
|
|
32
|
+
)
|
|
33
|
+
from tokenops.framework.request_context import (
|
|
26
34
|
RequestContext as RequestContext,
|
|
27
35
|
)
|
|
28
|
-
from tokenops.
|
|
36
|
+
from tokenops.framework.request_context import (
|
|
29
37
|
bind_request_context as bind_request_context,
|
|
30
38
|
)
|
|
31
|
-
from tokenops.
|
|
39
|
+
from tokenops.framework.request_context import (
|
|
32
40
|
clear_request_context as clear_request_context,
|
|
33
41
|
)
|
|
34
|
-
from tokenops.
|
|
42
|
+
from tokenops.framework.request_context import (
|
|
35
43
|
current_request_context as current_request_context,
|
|
36
44
|
)
|
|
37
|
-
from tokenops.
|
|
38
|
-
TokenOpsBound as TokenOpsBound,
|
|
39
|
-
)
|
|
40
|
-
from tokenops.control.run import (
|
|
41
|
-
agentplane_run_scope as agentplane_run_scope,
|
|
42
|
-
)
|
|
43
|
-
from tokenops.control.run import (
|
|
44
|
-
tokenops_run as tokenops_run,
|
|
45
|
-
)
|
|
45
|
+
from tokenops.interfaces.instrument import instrument_app as instrument_app
|
|
46
46
|
from tokenops.repositories import ControlPlaneClient as ControlPlaneClient
|
|
47
47
|
|
|
48
48
|
__all__ = [
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""The capabilities layer: governed-run workflows.
|
|
2
|
+
|
|
3
|
+
Opens runs (:func:`tokenops_run`), wraps model calls (:func:`wrap_complete`), and installs the
|
|
4
|
+
Chronicle crossing hook that feeds the governor. Importing this package registers the hook on
|
|
5
|
+
``chronicle.default_hooks`` for the whole process.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from tokenops.capabilities.complete_wrapper import wrap_complete
|
|
9
|
+
from tokenops.capabilities.crossing import install_crossing_hook, on_crossing
|
|
10
|
+
from tokenops.capabilities.ledger_writers import flush_ledger_writes
|
|
11
|
+
from tokenops.capabilities.run import TokenOpsBound, agentplane_run_scope, tokenops_run
|
|
12
|
+
from tokenops.capabilities.step_observation import make_on_step, step_to_observation
|
|
13
|
+
from tokenops.capabilities.stream_wrapper import wrap_stream
|
|
14
|
+
from tokenops.framework.message_steering import apply_carry_to_messages, consume_carry
|
|
15
|
+
|
|
16
|
+
# Process-wide: register the governor hook on chronicle.default_hooks (inherited by every session).
|
|
17
|
+
install_crossing_hook()
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"TokenOpsBound",
|
|
21
|
+
"agentplane_run_scope",
|
|
22
|
+
"apply_carry_to_messages",
|
|
23
|
+
"consume_carry",
|
|
24
|
+
"flush_ledger_writes",
|
|
25
|
+
"install_crossing_hook",
|
|
26
|
+
"make_on_step",
|
|
27
|
+
"on_crossing",
|
|
28
|
+
"step_to_observation",
|
|
29
|
+
"tokenops_run",
|
|
30
|
+
"wrap_complete",
|
|
31
|
+
"wrap_stream",
|
|
32
|
+
]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A run is a Chronicle trace: its only identifier is ``trace_id``. A hop arrives with the
|
|
4
4
|
caller's ``traceparent`` and joins that trace; the entry hop starts a new one. This module is
|
|
5
|
-
the single place that reads the active Chronicle span, so the rest of
|
|
5
|
+
the single place that reads the active Chronicle span, so the rest of TokenOps
|
|
6
6
|
never touches Chronicle's session.
|
|
7
7
|
|
|
8
8
|
``chronicle.current_session`` (Chronicle 1.1) reads the active session without opening one;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""``wrap_complete``: govern a ``complete(provider, model, messages)`` entry point.
|
|
2
|
+
|
|
3
|
+
Pre-call governance (MUTATE / HALT / RETRY) happens here; the dispatch itself goes through
|
|
4
|
+
Chronicle ``wrap_llm`` so the LIVE record and ``on_crossing`` fire. The TokenOps crossing hook
|
|
5
|
+
projects crossings into ``Governor.observe``: do not also ``emit_observation`` here, or the
|
|
6
|
+
call is billed twice.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from chronicle import wrap_llm
|
|
15
|
+
|
|
16
|
+
from tokenops.capabilities.crossing import (
|
|
17
|
+
install_crossing_hook,
|
|
18
|
+
reset_wrap_owns_precall,
|
|
19
|
+
wrap_owns_precall,
|
|
20
|
+
)
|
|
21
|
+
from tokenops.framework.core import Attribution, CallRequest
|
|
22
|
+
from tokenops.framework.engine import ApplyControls, Governor
|
|
23
|
+
from tokenops.framework.message_steering import (
|
|
24
|
+
compact_messages,
|
|
25
|
+
consume_carry,
|
|
26
|
+
estimate_input_tokens,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = ["DispatchFn", "policy_metadata", "tighten_cap", "wrap_complete"]
|
|
30
|
+
|
|
31
|
+
#: A dispatch callable: (provider, model, messages, max_output_tokens) -> response.
|
|
32
|
+
DispatchFn = Callable[..., object]
|
|
33
|
+
|
|
34
|
+
_RETRY_BASE_CAP = 512
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def tighten_cap(cap: int | None) -> int:
|
|
38
|
+
"""RETRY tightens the output cap each attempt (halve, floor 64)."""
|
|
39
|
+
return max(64, (cap or _RETRY_BASE_CAP) // 2)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def policy_metadata(controls: ApplyControls) -> Callable[[object], dict[str, int]]:
|
|
43
|
+
"""Envelope metadata for what a policy did to this call.
|
|
44
|
+
|
|
45
|
+
The plane stores no per-policy statistics (control-plane ADR 0009), so what a policy
|
|
46
|
+
achieved is recorded on the envelope instead: ``tokenops.compaction_tokens_before``,
|
|
47
|
+
``..._tokens_after`` and ``..._tokens_saved`` when ``context_compaction`` rewrote the
|
|
48
|
+
prompt. Read after the dispatch returns, so ``controls.call`` is this call's.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def extract(_result: object) -> dict[str, int]:
|
|
52
|
+
call = getattr(controls, "call", None)
|
|
53
|
+
compaction = getattr(call, "compaction", None) if call is not None else None
|
|
54
|
+
if not compaction:
|
|
55
|
+
return {}
|
|
56
|
+
return {f"tokenops.compaction_{key}": int(value) for key, value in compaction.items()}
|
|
57
|
+
|
|
58
|
+
return extract
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def wrap_complete(
|
|
62
|
+
governor: Governor,
|
|
63
|
+
controls: ApplyControls,
|
|
64
|
+
attr: Attribution,
|
|
65
|
+
*,
|
|
66
|
+
provider: str,
|
|
67
|
+
model: str,
|
|
68
|
+
dispatch: DispatchFn,
|
|
69
|
+
est_input_fn: Callable[[object], int] | None = None,
|
|
70
|
+
service: str = "",
|
|
71
|
+
max_call_retries: int = 3,
|
|
72
|
+
) -> Callable[[str, str, Any], object]:
|
|
73
|
+
"""Wrap a ``complete(provider, model, messages)`` entry point for **pre_call** governance
|
|
74
|
+
and the **RETRY** actuator.
|
|
75
|
+
|
|
76
|
+
Dispatch is traced via Chronicle ``wrap_llm`` (LIVE envelope + ``on_crossing``).
|
|
77
|
+
TokenOps observes through the crossing hook, not a second ``emit_observation``.
|
|
78
|
+
|
|
79
|
+
After each traced dispatch, ``output_runaway`` may set ``controls.retry``; the call is
|
|
80
|
+
re-issued with a tighter output cap and raised frequency/presence penalties, bounded
|
|
81
|
+
by ``max_call_retries`` and by the policy's own retry budget (INJECT once exhausted).
|
|
82
|
+
"""
|
|
83
|
+
install_crossing_hook()
|
|
84
|
+
estimate = est_input_fn or estimate_input_tokens
|
|
85
|
+
seg = f"trace:{attr.trace_id}"
|
|
86
|
+
boundary_id = f"{service or attr.agent}.chat"
|
|
87
|
+
traced = wrap_llm(
|
|
88
|
+
boundary_id, dispatch, provider=provider, extract_metadata=policy_metadata(controls)
|
|
89
|
+
)
|
|
90
|
+
controls.compaction_supported = True # wrap_complete IS the prompt-assembly hook
|
|
91
|
+
|
|
92
|
+
def governed(p: str, m: str, messages: Any) -> object:
|
|
93
|
+
owns = wrap_owns_precall(True)
|
|
94
|
+
try:
|
|
95
|
+
controls.begin_call()
|
|
96
|
+
request = CallRequest(
|
|
97
|
+
attr=attr,
|
|
98
|
+
provider=provider,
|
|
99
|
+
model=m,
|
|
100
|
+
estimated_input_tokens=estimate(messages),
|
|
101
|
+
max_output_tokens=controls.call.max_output_tokens,
|
|
102
|
+
)
|
|
103
|
+
governor.pre_call(request)
|
|
104
|
+
|
|
105
|
+
use_model = controls.call.model_override or m
|
|
106
|
+
messages = consume_carry(controls, messages)
|
|
107
|
+
if controls.call.compact: # deep prompt compaction
|
|
108
|
+
messages, compaction = compact_messages(messages, estimate=estimate)
|
|
109
|
+
controls.call.compaction = compaction
|
|
110
|
+
|
|
111
|
+
governor.ledger.admit(seg)
|
|
112
|
+
try:
|
|
113
|
+
cap = controls.call.max_output_tokens
|
|
114
|
+
penalties: dict[str, float] = {}
|
|
115
|
+
attempt = 0
|
|
116
|
+
while True:
|
|
117
|
+
controls.retry = False
|
|
118
|
+
# Chronicle records + on_crossing → Governor.observe (when bound)
|
|
119
|
+
response = traced(p, use_model, messages, max_output_tokens=cap, **penalties)
|
|
120
|
+
if controls.retry and attempt < max_call_retries:
|
|
121
|
+
attempt += 1
|
|
122
|
+
cap = tighten_cap(cap)
|
|
123
|
+
penalties = {"frequency_penalty": 1.0, "presence_penalty": 0.6}
|
|
124
|
+
continue
|
|
125
|
+
return response
|
|
126
|
+
finally:
|
|
127
|
+
governor.ledger.complete(seg)
|
|
128
|
+
finally:
|
|
129
|
+
reset_wrap_owns_precall(owns)
|
|
130
|
+
|
|
131
|
+
return governed
|
|
@@ -35,7 +35,7 @@ def reset_wrap_owns_precall(token: Any) -> None:
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def _service_name() -> str:
|
|
38
|
-
from tokenops.
|
|
38
|
+
from tokenops.framework.context import current_span
|
|
39
39
|
|
|
40
40
|
span = current_span()
|
|
41
41
|
return span.service if span else "unknown"
|
|
@@ -57,8 +57,8 @@ def on_enter(info: CallInfo) -> dict[str, Any] | None:
|
|
|
57
57
|
if _kind(info) != "llm" or _wrap_owns_precall.get():
|
|
58
58
|
return None
|
|
59
59
|
|
|
60
|
-
from tokenops.
|
|
61
|
-
from tokenops.
|
|
60
|
+
from tokenops.framework.context import current_governance, current_hop
|
|
61
|
+
from tokenops.framework.core import CallRequest
|
|
62
62
|
|
|
63
63
|
gov_ctx = current_governance()
|
|
64
64
|
if gov_ctx is None or current_hop() is None:
|
|
@@ -111,7 +111,7 @@ def on_enter(info: CallInfo) -> dict[str, Any] | None:
|
|
|
111
111
|
def on_leave(info: CallInfo) -> None:
|
|
112
112
|
"""Release inflight admit from :func:`on_enter` (success or failure)."""
|
|
113
113
|
del info
|
|
114
|
-
from tokenops.
|
|
114
|
+
from tokenops.framework.context import current_governance
|
|
115
115
|
|
|
116
116
|
seg = _inflight_seg.get()
|
|
117
117
|
if not seg:
|
|
@@ -126,8 +126,8 @@ def on_leave(info: CallInfo) -> None:
|
|
|
126
126
|
|
|
127
127
|
def on_crossing(info: CallInfo, result: Any) -> None:
|
|
128
128
|
"""Project crossing → Observation when a hop attribution + governance are bound."""
|
|
129
|
-
from tokenops.
|
|
130
|
-
from tokenops.
|
|
129
|
+
from tokenops.framework.boundary import emit_observation, observation_from_crossing
|
|
130
|
+
from tokenops.framework.context import current_governance, current_hop
|
|
131
131
|
|
|
132
132
|
if current_governance() is None or current_hop() is None:
|
|
133
133
|
return
|
|
@@ -15,20 +15,15 @@ from tokenops.repositories import ControlPlaneClient, LedgerEventWriter
|
|
|
15
15
|
_LOCK = threading.Lock()
|
|
16
16
|
# Keeps the client referenced so its id() cannot be reused while its writer is alive.
|
|
17
17
|
_WRITERS: dict[int, tuple[ControlPlaneClient, LedgerEventWriter]] = {}
|
|
18
|
-
_ATEXIT_REGISTERED = False
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
def writer_for(client: ControlPlaneClient) -> LedgerEventWriter:
|
|
22
21
|
"""The shared writer for ``client`` (created on first use)."""
|
|
23
|
-
global _ATEXIT_REGISTERED
|
|
24
22
|
with _LOCK:
|
|
25
23
|
entry = _WRITERS.get(id(client))
|
|
26
24
|
if entry is None:
|
|
27
25
|
entry = (client, LedgerEventWriter(client))
|
|
28
26
|
_WRITERS[id(client)] = entry
|
|
29
|
-
if not _ATEXIT_REGISTERED:
|
|
30
|
-
atexit.register(flush_ledger_writes)
|
|
31
|
-
_ATEXIT_REGISTERED = True
|
|
32
27
|
return entry[1]
|
|
33
28
|
|
|
34
29
|
|
|
@@ -37,3 +32,8 @@ def flush_ledger_writes(timeout: float = 5.0) -> bool:
|
|
|
37
32
|
with _LOCK:
|
|
38
33
|
writers = [w for _, w in _WRITERS.values()]
|
|
39
34
|
return all([w.flush(timeout) for w in writers])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Registered once at import; a no-op until a writer exists, so a short script does not lose
|
|
38
|
+
# its last spend.
|
|
39
|
+
atexit.register(flush_ledger_writes)
|
{agent_tokenops-1.0.1/src/tokenops/control → agent_tokenops-2.0.0/src/tokenops/capabilities}/run.py
RENAMED
|
@@ -24,27 +24,27 @@ from contextlib import contextmanager
|
|
|
24
24
|
from dataclasses import dataclass
|
|
25
25
|
from typing import Any
|
|
26
26
|
|
|
27
|
-
from tokenops.
|
|
28
|
-
from tokenops.
|
|
29
|
-
from tokenops.
|
|
30
|
-
from tokenops.
|
|
27
|
+
from tokenops.capabilities.chronicle_trace_utils import chronicle_span
|
|
28
|
+
from tokenops.capabilities.crossing import install_crossing_hook
|
|
29
|
+
from tokenops.capabilities.ledger_writers import writer_for
|
|
30
|
+
from tokenops.framework.attribution import _build_attribution, merge_hop_dims
|
|
31
|
+
from tokenops.framework.config import build_governance_stack, build_governor
|
|
32
|
+
from tokenops.framework.context import (
|
|
31
33
|
SpanContext,
|
|
32
34
|
_governance_scope,
|
|
33
35
|
bind_hop,
|
|
34
36
|
bind_span,
|
|
35
37
|
run_scope,
|
|
36
38
|
)
|
|
37
|
-
from tokenops.
|
|
39
|
+
from tokenops.framework.context import (
|
|
38
40
|
clear as clear_run_context,
|
|
39
41
|
)
|
|
40
|
-
from tokenops.
|
|
41
|
-
from tokenops.
|
|
42
|
-
from tokenops.
|
|
43
|
-
from tokenops.
|
|
44
|
-
from tokenops.
|
|
45
|
-
from tokenops.
|
|
46
|
-
from tokenops.control.pricing import build_price_book
|
|
47
|
-
from tokenops.control.request_context import current_request_context
|
|
42
|
+
from tokenops.framework.core import Attribution
|
|
43
|
+
from tokenops.framework.engine import ApplyControls, Governor, PreviewControls
|
|
44
|
+
from tokenops.framework.ledger import PriceFn
|
|
45
|
+
from tokenops.framework.models import GovernanceMode, HopAttribution, parse_governance_mode
|
|
46
|
+
from tokenops.framework.pricing import build_price_book
|
|
47
|
+
from tokenops.framework.request_context import current_request_context
|
|
48
48
|
from tokenops.repositories import ControlPlaneClient
|
|
49
49
|
|
|
50
50
|
logger = logging.getLogger("tokenops.run")
|
|
@@ -61,11 +61,6 @@ class TokenOpsBound:
|
|
|
61
61
|
controls: ApplyControls | PreviewControls
|
|
62
62
|
client: ControlPlaneClient | None
|
|
63
63
|
|
|
64
|
-
@property
|
|
65
|
-
def registration(self) -> HopAttribution:
|
|
66
|
-
"""Deprecated alias of ``hop``."""
|
|
67
|
-
return self.hop
|
|
68
|
-
|
|
69
64
|
|
|
70
65
|
def _resolve_ambient(
|
|
71
66
|
*,
|
|
@@ -162,7 +157,7 @@ def tokenops_run(
|
|
|
162
157
|
) -> Iterator[TokenOpsBound]:
|
|
163
158
|
"""One hop under a governed trace: join the trace, bind span + governance.
|
|
164
159
|
|
|
165
|
-
Happy path (with :func:`~tokenops.
|
|
160
|
+
Happy path (with :func:`~tokenops.interfaces.instrument.instrument_app`)::
|
|
166
161
|
|
|
167
162
|
with tokenops_run():
|
|
168
163
|
...
|