agent-budget-semantics 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_budget_semantics-0.1.0/.gitignore +16 -0
- agent_budget_semantics-0.1.0/DIMENSIONS.md +125 -0
- agent_budget_semantics-0.1.0/LICENSE +21 -0
- agent_budget_semantics-0.1.0/PKG-INFO +320 -0
- agent_budget_semantics-0.1.0/README.md +251 -0
- agent_budget_semantics-0.1.0/cli.py +163 -0
- agent_budget_semantics-0.1.0/cost_divergence.py +228 -0
- agent_budget_semantics-0.1.0/harness.py +236 -0
- agent_budget_semantics-0.1.0/mock-llm/__init__.py +0 -0
- agent_budget_semantics-0.1.0/mock-llm/server.py +187 -0
- agent_budget_semantics-0.1.0/otel_comparison.py +213 -0
- agent_budget_semantics-0.1.0/otel_span_capture.py +265 -0
- agent_budget_semantics-0.1.0/pyproject.toml +120 -0
- agent_budget_semantics-0.1.0/report_generator.py +286 -0
- agent_budget_semantics-0.1.0/runners/__init__.py +19 -0
- agent_budget_semantics-0.1.0/runners/anthropic_runner.py +206 -0
- agent_budget_semantics-0.1.0/runners/base.py +34 -0
- agent_budget_semantics-0.1.0/runners/crewai_runner.py +190 -0
- agent_budget_semantics-0.1.0/runners/langchain_runner.py +195 -0
- agent_budget_semantics-0.1.0/runners/runner_adk.py +120 -0
- agent_budget_semantics-0.1.0/runners/runner_agno.py +107 -0
- agent_budget_semantics-0.1.0/runners/runner_anthropic.py +126 -0
- agent_budget_semantics-0.1.0/runners/runner_autogen.py +111 -0
- agent_budget_semantics-0.1.0/runners/runner_crewai.py +118 -0
- agent_budget_semantics-0.1.0/runners/runner_langchain.py +111 -0
- agent_budget_semantics-0.1.0/runners/runner_langgraph.py +106 -0
- agent_budget_semantics-0.1.0/runners/runner_llamaindex.py +105 -0
- agent_budget_semantics-0.1.0/runners/runner_openai_agents.py +109 -0
- agent_budget_semantics-0.1.0/runners/runner_semantic_kernel.py +111 -0
- agent_budget_semantics-0.1.0/runners/runner_swarm.py +103 -0
- agent_budget_semantics-0.1.0/runners/semantic_kernel_runner.py +196 -0
- agent_budget_semantics-0.1.0/scenarios/S10-nested-delegation-chain.yaml +167 -0
- agent_budget_semantics-0.1.0/scenarios/S11-timeout-cancellation.yaml +137 -0
- agent_budget_semantics-0.1.0/scenarios/S12-dynamic-budget-modification.yaml +147 -0
- agent_budget_semantics-0.1.0/scenarios/S3-multi-agent-delegation.yaml +135 -0
- agent_budget_semantics-0.1.0/scenarios/S4-parallel-tools.yaml +90 -0
- agent_budget_semantics-0.1.0/scenarios/S5-error-retry.yaml +112 -0
- agent_budget_semantics-0.1.0/scenarios/S6-token-budget.yaml +132 -0
- agent_budget_semantics-0.1.0/scenarios/S7-streaming-chunks.yaml +111 -0
- agent_budget_semantics-0.1.0/scenarios/S8-tool-output-explosion.yaml +136 -0
- agent_budget_semantics-0.1.0/scenarios/S9-system-prompt-attribution.yaml +137 -0
- agent_budget_semantics-0.1.0/scenarios/__init__.py +0 -0
- agent_budget_semantics-0.1.0/scenarios/s1_simple_tool_loop.yaml +56 -0
- agent_budget_semantics-0.1.0/scenarios/s2_budget_exhaustion.yaml +147 -0
- agent_budget_semantics-0.1.0/tests/__init__.py +0 -0
- agent_budget_semantics-0.1.0/tests/test_mock_llm.py +123 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Budget Semantics Divergence Dimensions
|
|
2
|
+
|
|
3
|
+
24 dimensions of divergence discovered across 11 AI agent frameworks.
|
|
4
|
+
|
|
5
|
+
## Core Iteration Semantics (D1-D4)
|
|
6
|
+
|
|
7
|
+
| Dim | Name | Question | Scenarios |
|
|
8
|
+
|-----|------|----------|-----------|
|
|
9
|
+
| D1 | Iteration unit | What counts as one iteration? | S1, S2 |
|
|
10
|
+
| D2 | Token accounting | Which tokens are counted? | S2, S6 |
|
|
11
|
+
| D3 | Enforcement point | Pre-call or post-call budget check? | S2 |
|
|
12
|
+
| D4 | Exhaustion behavior | What happens when budget runs out? | S2 |
|
|
13
|
+
|
|
14
|
+
## Multi-Agent (D5-D6)
|
|
15
|
+
|
|
16
|
+
| Dim | Name | Question | Scenarios |
|
|
17
|
+
|-----|------|----------|-----------|
|
|
18
|
+
| D5 | Budget delegation | How is budget shared with sub-agents? | S3, S10 |
|
|
19
|
+
| D6 | Delegation cost | Does delegating itself consume budget? | S3, S10 |
|
|
20
|
+
|
|
21
|
+
## Parallel Execution (D7-D8)
|
|
22
|
+
|
|
23
|
+
| Dim | Name | Question | Scenarios |
|
|
24
|
+
|-----|------|----------|-----------|
|
|
25
|
+
| D7 | Parallel tool counting | N parallel tools = how many units? | S4 |
|
|
26
|
+
| D8 | Partial batch execution | If budget=2 and batch=3, run 2 or 0? | S4 |
|
|
27
|
+
|
|
28
|
+
## Error Handling (D9-D10)
|
|
29
|
+
|
|
30
|
+
| Dim | Name | Question | Scenarios |
|
|
31
|
+
|-----|------|----------|-----------|
|
|
32
|
+
| D9 | Error/retry counting | Failed + retry = 1 or 2 units? | S5 |
|
|
33
|
+
| D10 | Error propagation | How is the error communicated to LLM? | S5 |
|
|
34
|
+
|
|
35
|
+
## Token Budget (D11-D12)
|
|
36
|
+
|
|
37
|
+
| Dim | Name | Question | Scenarios |
|
|
38
|
+
|-----|------|----------|-----------|
|
|
39
|
+
| D11 | Token budget enforcement | Cumulative token tracking? | S6 |
|
|
40
|
+
| D12 | Token counting method | Total, completion-only, or prompt-only? | S6 |
|
|
41
|
+
|
|
42
|
+
## Streaming (D13-D14)
|
|
43
|
+
|
|
44
|
+
| Dim | Name | Question | Scenarios |
|
|
45
|
+
|-----|------|----------|-----------|
|
|
46
|
+
| D13 | Streaming chunk counting | Streamed response = 1 or N budget units? | S7 |
|
|
47
|
+
| D14 | Streaming token attribution | Single usage record or incremental? | S7 |
|
|
48
|
+
|
|
49
|
+
## Context Growth (D15-D16)
|
|
50
|
+
|
|
51
|
+
| Dim | Name | Question | Scenarios |
|
|
52
|
+
|-----|------|----------|-----------|
|
|
53
|
+
| D15 | Tool output token counting | Large tool output counts in budget? | S8 |
|
|
54
|
+
| D16 | Context growth attribution | Growing prompt attributed to which span? | S8 |
|
|
55
|
+
|
|
56
|
+
## System Prompt (D17-D18)
|
|
57
|
+
|
|
58
|
+
| Dim | Name | Question | Scenarios |
|
|
59
|
+
|-----|------|----------|-----------|
|
|
60
|
+
| D17 | System prompt attribution | Counted once, every turn, or never? | S9 |
|
|
61
|
+
| D18 | System prompt telemetry | How represented in OTel spans? | S9 |
|
|
62
|
+
|
|
63
|
+
## Deep Delegation (D19-D20)
|
|
64
|
+
|
|
65
|
+
| Dim | Name | Question | Scenarios |
|
|
66
|
+
|-----|------|----------|-----------|
|
|
67
|
+
| D19 | Nested inheritance | Budget across 3+ delegation levels? | S10 |
|
|
68
|
+
| D20 | Delegation cost visibility | Parent see child's consumption? | S10 |
|
|
69
|
+
|
|
70
|
+
## Fault Tolerance (D21-D22)
|
|
71
|
+
|
|
72
|
+
| Dim | Name | Question | Scenarios |
|
|
73
|
+
|-----|------|----------|-----------|
|
|
74
|
+
| D21 | Timeout budget impact | Timed-out call consumes budget? | S11 |
|
|
75
|
+
| D22 | Timeout token attribution | Tokens from failed request counted? | S11 |
|
|
76
|
+
|
|
77
|
+
## Dynamic Budget (D23-D24)
|
|
78
|
+
|
|
79
|
+
| Dim | Name | Question | Scenarios |
|
|
80
|
+
|-----|------|----------|-----------|
|
|
81
|
+
| D23 | Dynamic budget support | Can budget change mid-execution? | S12 |
|
|
82
|
+
| D24 | Budget modification telemetry | How to represent changes in OTel? | S12 |
|
|
83
|
+
|
|
84
|
+
## Framework Coverage Matrix
|
|
85
|
+
|
|
86
|
+
| Framework | D1 | D5 | D7 | D9 | D11 | D13 | D15 | D17 | D19 | D21 | D23 |
|
|
87
|
+
|-----------|----|----|----|----|-----|-----|-----|-----|-----|-----|-----|
|
|
88
|
+
| AutoGen | msg | shared | N | counts | callback | transparent | configurable | every-turn | shared-pool | counts | callback |
|
|
89
|
+
| OpenAI Agents | llm | shared | 1 | counts | none | transparent | no | every-turn | shared | counts | no |
|
|
90
|
+
| LangChain | cycle | n/a | 1 | configurable | none | transparent | no | every-turn | n/a | configurable | no |
|
|
91
|
+
| LangGraph | node | subtract | 1 | counts | none | transparent | indirect | every-turn | subtract | counts | no |
|
|
92
|
+
| CrewAI | cycle | independent | n/a | free | none | n/a | no | every-turn | independent | free | no |
|
|
93
|
+
| ADK | loop | remaining | 1 | counts | configurable | transparent | configurable | once | remaining | counts | no |
|
|
94
|
+
| Semantic Kernel | invoke | n/a | 1 | free | none | transparent | no | every-turn | n/a | counts | mutable |
|
|
95
|
+
| Anthropic | client | n/a | client | client | per-call | transparent | indirect | per-call | n/a | client | n/a |
|
|
96
|
+
| Swarm | msg | shared | 2N | counts | none | transparent | no | every-turn | shared | counts | mutable |
|
|
97
|
+
| LlamaIndex | step | n/a | separate | counts | none | transparent | no | every-turn | n/a | counts | no |
|
|
98
|
+
| Agno | cycle | team-pool | 1 | counts | output-only | transparent | no | every-turn | team-pool | counts | no |
|
|
99
|
+
|
|
100
|
+
## Key Finding
|
|
101
|
+
|
|
102
|
+
For `gen_ai.agent.iteration_budget.consumed` with the SAME execution
|
|
103
|
+
(4 LLM calls, 3 tool calls):
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
consumed = [3, 4, 7, 10]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
depending on which framework. 4 different values. Not edge cases or
|
|
110
|
+
implementation bugs. Fundamental design disagreements about what "one iteration"
|
|
111
|
+
means.
|
|
112
|
+
|
|
113
|
+
## Impact on OTel Semantic Conventions
|
|
114
|
+
|
|
115
|
+
Without mandatory counting semantics metadata, the budget attributes in
|
|
116
|
+
PR #439 are:
|
|
117
|
+
|
|
118
|
+
1. Not comparable across frameworks (the primary use case for OTel)
|
|
119
|
+
2. Meaningless for multi-framework dashboards
|
|
120
|
+
3. Incorrect for cost attribution and chargeback
|
|
121
|
+
4. Unstable for alert thresholds (same execution, different consumed values)
|
|
122
|
+
5. Misleading for capacity planning
|
|
123
|
+
|
|
124
|
+
Proposed fix: mandatory `gen_ai.agent.iteration_budget.counting_method` enum
|
|
125
|
+
that classifies the framework's counting approach.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elankumaran Srinivasan
|
|
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,320 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: agent-budget-semantics
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Differential testing of budget enforcement semantics across AI agent frameworks
|
|
5
|
+
Project-URL: Homepage, https://github.com/elang2/agent-budget-semantics
|
|
6
|
+
Project-URL: Repository, https://github.com/elang2/agent-budget-semantics
|
|
7
|
+
Project-URL: Issues, https://github.com/elang2/agent-budget-semantics/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/elang2/agent-budget-semantics#readme
|
|
9
|
+
Author: Elankumaran Srinivasan
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agent,anthropic,autogen,budget,conformance,crewai,differential-testing,genai,google-adk,langchain,langgraph,llm,openai-agents,opentelemetry,semantic-kernel,telemetry
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Testing
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Provides-Extra: adk
|
|
26
|
+
Requires-Dist: google-adk>=1.0; extra == 'adk'
|
|
27
|
+
Provides-Extra: agno
|
|
28
|
+
Requires-Dist: agno>=1.0; extra == 'agno'
|
|
29
|
+
Provides-Extra: all
|
|
30
|
+
Requires-Dist: agno>=1.0; extra == 'all'
|
|
31
|
+
Requires-Dist: anthropic>=0.34; extra == 'all'
|
|
32
|
+
Requires-Dist: autogen-agentchat>=0.4; extra == 'all'
|
|
33
|
+
Requires-Dist: autogen-ext>=0.4; extra == 'all'
|
|
34
|
+
Requires-Dist: crewai>=0.100; extra == 'all'
|
|
35
|
+
Requires-Dist: google-adk>=1.0; extra == 'all'
|
|
36
|
+
Requires-Dist: langchain-openai>=0.3; extra == 'all'
|
|
37
|
+
Requires-Dist: langchain>=0.3; extra == 'all'
|
|
38
|
+
Requires-Dist: langgraph>=0.3; extra == 'all'
|
|
39
|
+
Requires-Dist: llama-index-core>=0.11; extra == 'all'
|
|
40
|
+
Requires-Dist: llama-index-llms-openai>=0.3; extra == 'all'
|
|
41
|
+
Requires-Dist: openai-agents>=0.1; extra == 'all'
|
|
42
|
+
Requires-Dist: openai-swarm>=0.1; extra == 'all'
|
|
43
|
+
Requires-Dist: semantic-kernel>=1.0; extra == 'all'
|
|
44
|
+
Provides-Extra: anthropic
|
|
45
|
+
Requires-Dist: anthropic>=0.34; extra == 'anthropic'
|
|
46
|
+
Provides-Extra: autogen
|
|
47
|
+
Requires-Dist: autogen-agentchat>=0.4; extra == 'autogen'
|
|
48
|
+
Requires-Dist: autogen-ext>=0.4; extra == 'autogen'
|
|
49
|
+
Provides-Extra: crewai
|
|
50
|
+
Requires-Dist: crewai>=0.100; extra == 'crewai'
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
54
|
+
Provides-Extra: langchain
|
|
55
|
+
Requires-Dist: langchain-openai>=0.3; extra == 'langchain'
|
|
56
|
+
Requires-Dist: langchain>=0.3; extra == 'langchain'
|
|
57
|
+
Provides-Extra: langgraph
|
|
58
|
+
Requires-Dist: langgraph>=0.3; extra == 'langgraph'
|
|
59
|
+
Provides-Extra: llamaindex
|
|
60
|
+
Requires-Dist: llama-index-core>=0.11; extra == 'llamaindex'
|
|
61
|
+
Requires-Dist: llama-index-llms-openai>=0.3; extra == 'llamaindex'
|
|
62
|
+
Provides-Extra: openai-agents
|
|
63
|
+
Requires-Dist: openai-agents>=0.1; extra == 'openai-agents'
|
|
64
|
+
Provides-Extra: semantic-kernel
|
|
65
|
+
Requires-Dist: semantic-kernel>=1.0; extra == 'semantic-kernel'
|
|
66
|
+
Provides-Extra: swarm
|
|
67
|
+
Requires-Dist: openai-swarm>=0.1; extra == 'swarm'
|
|
68
|
+
Description-Content-Type: text/markdown
|
|
69
|
+
|
|
70
|
+
# agent-budget-semantics
|
|
71
|
+
|
|
72
|
+
Differential testing of budget enforcement semantics across 11 AI agent frameworks.
|
|
73
|
+
|
|
74
|
+
## The Problem
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
gen_ai.agent.iteration_budget.consumed = [3, 4, 7, 10]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Same work. Same LLM calls. Same tokens consumed. Four different telemetry values depending on which framework is instrumented. Setting `budget=3` means something fundamentally different across frameworks.
|
|
81
|
+
|
|
82
|
+
## The Evidence
|
|
83
|
+
|
|
84
|
+
| Framework | `budget=3` means | Parallel 3 tools | Error retry | Final answer |
|
|
85
|
+
|-----------|-----------------|------------------|-------------|--------------|
|
|
86
|
+
| AutoGen | 3 messages (LLM + tool mixed) | 3 budget units | Counts | Counts |
|
|
87
|
+
| OpenAI Agents | 3 LLM invocations | 1 budget unit | Counts | Counts |
|
|
88
|
+
| LangChain | 3 tool-call cycles | 1 budget unit | Configurable | Free |
|
|
89
|
+
| LangGraph | 3 node executions | 1 budget unit | Counts | Counts |
|
|
90
|
+
| CrewAI | 3 tool-use cycles | N/A | Free | Free extra call |
|
|
91
|
+
| Google ADK | 3 full agent loops | 1 budget unit | Counts | Part of last |
|
|
92
|
+
| Semantic Kernel | 3 auto-invoke attempts | 1 budget unit | Free | Not counted |
|
|
93
|
+
| Anthropic | Client-defined | Client decides | Client decides | Client decides |
|
|
94
|
+
| Swarm | Messages in history | 2N budget units | Counts | Counts |
|
|
95
|
+
| LlamaIndex | 3 ReAct steps | Separate budget | Counts | Free extra |
|
|
96
|
+
| Agno | 3 tool-use cycles | 1 budget unit | Counts | Part of flow |
|
|
97
|
+
|
|
98
|
+
## Install
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install agent-budget-semantics
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or with Docker (no dependencies):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
docker run --rm ghcr.io/elang2/agent-budget-semantics compare
|
|
108
|
+
docker run --rm ghcr.io/elang2/agent-budget-semantics cost
|
|
109
|
+
docker run --rm ghcr.io/elang2/agent-budget-semantics spans
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Quick Start
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Show the iteration divergence matrix
|
|
116
|
+
agent-budget-semantics compare
|
|
117
|
+
|
|
118
|
+
# Show cost divergence ($97K/year spread at scale)
|
|
119
|
+
agent-budget-semantics cost --daily-runs 1000
|
|
120
|
+
|
|
121
|
+
# Show OTel telemetry divergence (what your dashboard would show)
|
|
122
|
+
agent-budget-semantics spans
|
|
123
|
+
|
|
124
|
+
# Generate full report suite (markdown + JSON)
|
|
125
|
+
agent-budget-semantics report --output reports/
|
|
126
|
+
|
|
127
|
+
# Run differential tests against a specific framework
|
|
128
|
+
pip install "agent-budget-semantics[autogen]"
|
|
129
|
+
agent-budget-semantics run --scenario scenarios/s2_budget_exhaustion.yaml --frameworks autogen
|
|
130
|
+
|
|
131
|
+
# Run all frameworks
|
|
132
|
+
pip install "agent-budget-semantics[all]"
|
|
133
|
+
agent-budget-semantics run --all
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## What It Produces
|
|
137
|
+
|
|
138
|
+
### Iteration divergence (the headline finding)
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
Framework consumed utilization Counting method
|
|
142
|
+
--------------------------------------------------------------------------------
|
|
143
|
+
autogen 7 233% Each message (LLM response OR tool result)
|
|
144
|
+
openai_agents 4 133% Each full LLM invocation
|
|
145
|
+
langchain 3 100% Each tool-use cycle
|
|
146
|
+
langgraph 7 233% Each graph node execution
|
|
147
|
+
swarm 10 333% Messages added to history
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Cost divergence (makes it tangible)
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
Monthly Cost Projection (1000 runs/day)
|
|
154
|
+
----------------------------------------------------------------------
|
|
155
|
+
langchain $5,850/mo baseline
|
|
156
|
+
openai_agents $6,750/mo +$900 (+15%)
|
|
157
|
+
autogen $10,350/mo +$4,500 (+77%)
|
|
158
|
+
swarm $13,950/mo +$8,100 (+138%)
|
|
159
|
+
|
|
160
|
+
Annual spread: $97,200 — from iteration counting alone.
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### OTel span structure (what your dashboard shows)
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Framework Spans consumed util% Structure
|
|
167
|
+
------------------------------------------------------------------------------------------
|
|
168
|
+
autogen 8 7 233% root → 4 llm → 3 tool
|
|
169
|
+
langchain 6 3 100% root → 4 llm → 1 batch
|
|
170
|
+
swarm 8 10 333% root → 4 llm → 3 tool
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 12 Scenarios, 24 Dimensions
|
|
174
|
+
|
|
175
|
+
| Scenario | Tests | Dimensions |
|
|
176
|
+
|----------|-------|-----------|
|
|
177
|
+
| S1: Simple tool loop | Baseline behavior | D1-D4 |
|
|
178
|
+
| S2: Budget exhaustion | Enforcement boundaries | D1-D4 |
|
|
179
|
+
| S3: Multi-agent delegation | Budget sharing | D5-D6 |
|
|
180
|
+
| S4: Parallel tools | Batch counting | D7-D8 |
|
|
181
|
+
| S5: Error/retry | Retry budget impact | D9-D10 |
|
|
182
|
+
| S6: Token budget | Cumulative token tracking | D11-D12 |
|
|
183
|
+
| S7: Streaming | Chunk counting | D13-D14 |
|
|
184
|
+
| S8: Tool output explosion | Large response attribution | D15-D16 |
|
|
185
|
+
| S9: System prompt | Repeated prompt tokens | D17-D18 |
|
|
186
|
+
| S10: Nested delegation | 3-level inheritance | D19-D20 |
|
|
187
|
+
| S11: Timeout/cancellation | Failed call budget impact | D21-D22 |
|
|
188
|
+
| S12: Dynamic budget | Mid-run modification | D23-D24 |
|
|
189
|
+
|
|
190
|
+
See [DIMENSIONS.md](DIMENSIONS.md) for the full taxonomy with per-framework behavior.
|
|
191
|
+
|
|
192
|
+
## Use in CI
|
|
193
|
+
|
|
194
|
+
Drop into `.github/workflows/budget-conformance.yml`:
|
|
195
|
+
|
|
196
|
+
```yaml
|
|
197
|
+
name: Budget Semantics Check
|
|
198
|
+
on: [push, pull_request]
|
|
199
|
+
|
|
200
|
+
jobs:
|
|
201
|
+
check:
|
|
202
|
+
runs-on: ubuntu-latest
|
|
203
|
+
steps:
|
|
204
|
+
- uses: actions/checkout@v4
|
|
205
|
+
|
|
206
|
+
- uses: actions/setup-python@v5
|
|
207
|
+
with:
|
|
208
|
+
python-version: '3.12'
|
|
209
|
+
|
|
210
|
+
- name: Install
|
|
211
|
+
run: pip install agent-budget-semantics
|
|
212
|
+
|
|
213
|
+
- name: Run comparison
|
|
214
|
+
run: |
|
|
215
|
+
agent-budget-semantics compare
|
|
216
|
+
agent-budget-semantics cost
|
|
217
|
+
agent-budget-semantics report --output budget-report/
|
|
218
|
+
|
|
219
|
+
- name: Upload report
|
|
220
|
+
uses: actions/upload-artifact@v4
|
|
221
|
+
with:
|
|
222
|
+
name: budget-divergence-report
|
|
223
|
+
path: budget-report/
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Or with Docker (no Python setup needed):
|
|
227
|
+
|
|
228
|
+
```yaml
|
|
229
|
+
jobs:
|
|
230
|
+
check:
|
|
231
|
+
runs-on: ubuntu-latest
|
|
232
|
+
container:
|
|
233
|
+
image: ghcr.io/elang2/agent-budget-semantics:latest
|
|
234
|
+
steps:
|
|
235
|
+
- run: agent-budget-semantics compare
|
|
236
|
+
- run: agent-budget-semantics cost --daily-runs 500
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## How It Works
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
┌─────────────┐ ┌──────────────┐ ┌───────────────┐
|
|
243
|
+
│ Scenario │────▶│ Mock LLM │◀────│ Framework │
|
|
244
|
+
│ (YAML) │ │ (ledger) │ │ Runner │
|
|
245
|
+
└─────────────┘ └──────┬───────┘ └───────────────┘
|
|
246
|
+
│
|
|
247
|
+
▼
|
|
248
|
+
Ground Truth
|
|
249
|
+
(actual calls,
|
|
250
|
+
actual tokens)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
A deterministic mock LLM with a request ledger serves as ground truth. Scripted scenarios force tool-calling loops of known depth. Each framework runner executes the same scenario against the same mock. The harness compares what each framework reports vs. what actually happened.
|
|
254
|
+
|
|
255
|
+
No real LLM API keys needed. No flaky network calls. Fully reproducible.
|
|
256
|
+
|
|
257
|
+
## Three Architectural Models
|
|
258
|
+
|
|
259
|
+
Testing revealed three fundamentally different approaches to budget enforcement:
|
|
260
|
+
|
|
261
|
+
1. **Client-side only** (Anthropic) — No server-side budget concept. The client library decides when to stop. The API has no awareness of iteration limits.
|
|
262
|
+
|
|
263
|
+
2. **Framework-enforced** (9 frameworks) — The framework wraps the LLM API and applies its own budget logic. Each framework counts differently, producing the 4-value divergence.
|
|
264
|
+
|
|
265
|
+
3. **Server-side opaque** (AWS Bedrock) — The server enforces budget internally. The client cannot observe or control the counting mechanism.
|
|
266
|
+
|
|
267
|
+
## Relevance to OTel GenAI Conventions
|
|
268
|
+
|
|
269
|
+
This project provides empirical evidence for the budget governance discussion in the OpenTelemetry semantic conventions. Without mandatory counting semantics metadata, `gen_ai.agent.iteration_budget.consumed` is not comparable across frameworks.
|
|
270
|
+
|
|
271
|
+
Proposed fix: mandatory `counting_method` enum that classifies the framework's approach:
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
gen_ai.agent.iteration_budget.counting_method
|
|
275
|
+
Values: llm_calls | tool_cycles | graph_nodes | messages
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Related PRs/Issues:
|
|
279
|
+
- open-telemetry/semantic-conventions #439 (budget governance attributes)
|
|
280
|
+
- open-telemetry/semantic-conventions #451 (turn count)
|
|
281
|
+
- open-telemetry/semantic-conventions #447 (agent delegation)
|
|
282
|
+
- open-telemetry/semantic-conventions #4025 (retry counting)
|
|
283
|
+
|
|
284
|
+
## Project Structure
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
cli.py CLI entry point
|
|
288
|
+
harness.py Test orchestrator
|
|
289
|
+
otel_comparison.py Iteration divergence analysis
|
|
290
|
+
otel_span_capture.py OTel telemetry simulation
|
|
291
|
+
cost_divergence.py Cost impact calculator
|
|
292
|
+
report_generator.py Markdown/JSON report suite
|
|
293
|
+
DIMENSIONS.md 24-dimension taxonomy
|
|
294
|
+
|
|
295
|
+
mock-llm/ Deterministic mock LLM server
|
|
296
|
+
server.py OpenAI-compatible API with request ledger
|
|
297
|
+
|
|
298
|
+
runners/ Per-framework adapters (11 frameworks)
|
|
299
|
+
runner_autogen.py
|
|
300
|
+
runner_openai_agents.py
|
|
301
|
+
runner_langchain.py
|
|
302
|
+
runner_langgraph.py
|
|
303
|
+
runner_crewai.py
|
|
304
|
+
runner_adk.py
|
|
305
|
+
runner_semantic_kernel.py
|
|
306
|
+
runner_anthropic.py
|
|
307
|
+
runner_swarm.py
|
|
308
|
+
runner_llamaindex.py
|
|
309
|
+
runner_agno.py
|
|
310
|
+
|
|
311
|
+
scenarios/ YAML-defined test scenarios (12 scenarios)
|
|
312
|
+
S1-S12 Covering 24 divergence dimensions
|
|
313
|
+
|
|
314
|
+
tests/ Unit tests
|
|
315
|
+
reports/ Generated report artifacts
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## License
|
|
319
|
+
|
|
320
|
+
Apache-2.0
|