| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Can we rebase and base this pr off of next |
Sorry, something went wrong.
|
Checked this against the harness work now on next (#412–#438) since it's been rebased — looks well-integrated, low regression risk:
All harness conformance suites (langgraph/codex/claude_code + conformance) pass. LGTM from a compatibility standpoint. |
Sorry, something went wrong.
Captures ResponseCompletedEvent usage in the streaming model (was zeroed) and response.usage in both tracing wrappers, writing span.output.usage for billing. Also implements stream_response on the tracing wrappers, which were abstract and raised TypeError on instantiation.
…spans Streaming calls now default stream_options.include_usage=True, the usage-only final chunk is collected, and both auto_send variants attach completion usage to span output. concat_completion_chunks no longer drops choices when a chunk has none.
TurnSpan.record_usage writes the billable aggregate to span.data (usage + cost_usd), encapsulating the contract so agents cannot re-introduce the double-count bug. Documents the usage/cost span contract in the tracing tutorial.
test_claude_agents_* now remove their placeholder packages after loading, which previously blocked real imports of the temporal plugin tree in later-collected tests. Formats touched files with ruff and narrows span.output types in new tests for pyright.
The wrappers never implemented abstract stream_response, so TemporalTracingModelProvider.get_model() raised TypeError on every call since introduction; no working callers can exist. The streaming provider plus run.py hooks are the live tracing path.
…sage helpers TurnSpan.record_usage now takes the TurnUsage every harness turn adapter reports (cost_usd lifted to data automatically) or a plain dict, replacing the individual-count kwargs and the lib/core/tracing/usage.py helpers that duplicated what next's harness provides.
| Back | FazBrowse Home | New Git URL |
Makes every SDK tracing adapter emit real token usage for tracking: the OpenAI Agents SDK temporal models, the LangGraph handler, and litellm streaming/auto_send previously dropped usage and billed zero. Adds adk.tracing.turn_span() so agents record the per-turn aggregate (data["usage"] + cost_usd) instead of hand-rolling the contract that caused double-counting. Also fixes three bugs found along the way (uninstantiable tracing wrapper models, chunk concat wiping choices on empty-choices chunks, sys.modules leakage in the claude_agents tests); 30 new tests, tests/lib at 260 passing, ruff and pyright clean.
Greptile Summary
This PR fixes all three tracing adapters (litellm, OpenAI Agents SDK, LangGraph) so they emit real token usage onto spans for SGP billing, and introduces adk.tracing.turn_span() to record the per-turn rollup (data["usage"] + data["cost_usd"]) in the shape the backend bills from, preventing the double-counting bug that arose from hand-rolling that contract.
Confidence Score: 5/5
Safe to merge — all three adapters now emit real usage, the zip_longest fix is correct and well-tested, and the sys.modules cleanup is a targeted fix with no collateral effects.
The changes are well-contained billing instrumentation: new read paths (usage extraction) rather than modifications to request or message logic. The zip_longest fix is provably correct, the TurnSpan API cleanly prevents double-counting by routing aggregate usage to span.data instead of output, and 30 new tests cover every code path including edge cases.
No files require special attention.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Agent participant TurnSpan participant TracingModule participant LiteLLMService participant Span Agent->>TracingModule: turn_span(trace_id, name, ...) TracingModule->>Span: start_span() TracingModule-->>Agent: yield TurnSpan(span) Agent->>LiteLLMService: chat_completion_stream_auto_send(...) Note over LiteLLMService: _stream_kwargs_with_usage() adds include_usage=True LiteLLMService->>Span: "span.output = {task_message, usage}" LiteLLMService-->>Agent: TaskMessage Agent->>TurnSpan: record_usage(result.usage, cost_usd) Note over TurnSpan: Aggregate to span.data["usage"] + cost_usd TurnSpan->>Span: "span.data = {usage, cost_usd}" Agent->>TracingModule: exit turn_span TracingModule->>Span: end_span()%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Agent participant TurnSpan participant TracingModule participant LiteLLMService participant Span Agent->>TracingModule: turn_span(trace_id, name, ...) TracingModule->>Span: start_span() TracingModule-->>Agent: yield TurnSpan(span) Agent->>LiteLLMService: chat_completion_stream_auto_send(...) Note over LiteLLMService: _stream_kwargs_with_usage() adds include_usage=True LiteLLMService->>Span: "span.output = {task_message, usage}" LiteLLMService-->>Agent: TaskMessage Agent->>TurnSpan: record_usage(result.usage, cost_usd) Note over TurnSpan: Aggregate to span.data["usage"] + cost_usd TurnSpan->>Span: "span.data = {usage, cost_usd}" Agent->>TracingModule: exit turn_span TracingModule->>Span: end_span()Comments Outside Diff (1)
src/agentex/lib/adk/_modules/_langgraph_tracing.py, line 89-91 (link)
_extract_usage is called inside the inner for generation in generation_list loop, so output["usage"] gets overwritten on each iteration. For n=1 calls (the common case) this is harmless, but if a caller ever requests n > 1 completions only the last generation's usage_metadata contributes to the billing blob — earlier generations are silently dropped. The llm_output fallback is safe because it reads the response-level aggregate and returns the same dict every iteration, but the usage_metadata path is per-generation and should accumulate.
Prompt To Fix With AIReviews (5): Last reviewed commit: "refactor(adk): record_usage accepts harn..." | Re-trigger Greptile