Repository navigation
fix(blackbox): price MoA turns by physical model routes - #342
Conversation
7bd43f1 to
67182f8
Compare
|
| Filename | Overview |
|---|---|
| agent/conversation_loop.py | Adds _build_moa_pricing_calls() helper and wires it into the MoA accounting block; the physical-call attachment is guarded with the same fail-open try/except as all other telemetry mutations. |
| agent/moa_loop.py | Extends _RefAccounting with base_url, accumulates per-advisor physical routing into _pending_reference_pricing_calls on cache-MISS, resets it on cache-HIT, and exposes it via consume_reference_pricing_calls(). |
| plugins/blackbox/cost.py | Adds nested pricing_calls expansion before the pricing loop; a call with an explicitly empty list correctly falls through to the outer virtual-preset call, and zero-token physical calls are filtered before reconciliation. |
| plugins/blackbox/init.py | Adds a narrow guard that rewrites model="default" to "moa/default" when provider="moa", applied after the composite-model recovery step and only at the Blackbox recording boundary. |
| tests/plugins/blackbox/test_cost_perclass.py | Adds two regression tests: one verifies that each physical MoA call is priced at its own route, the other ensures a zero-token failed advisor doesn't demote the turn to "partial". |
| tests/agent/test_moa_blackbox_attribution.py | New test file verifying that _build_moa_pricing_calls appends the aggregator after advisors and does not mutate the caller-owned advisor list. |
| tests/agent/test_moa_aggregator_cost_slot.py | Adds a test confirming that consume_reference_pricing_calls() returns per-advisor physical routing data and honours the consume-once semantics. |
| tests/plugins/blackbox/test_composite_model_recovery.py | Adds a test confirming the _build_record rename of model="default" → "moa/default" when provider is "moa". |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant CL as conversation_loop
participant MoA as MoAChatCompletions
participant BB as blackbox._build_record
participant Cost as blackbox/cost.py
CL->>MoA: create(messages)
MoA->>MoA: _run_references_parallel() cache MISS
MoA->>MoA: Accumulate _pending_reference_pricing_calls per advisor
MoA->>MoA: Aggregator call → _last_aggregator_slot
CL->>MoA: consume_reference_usage()
MoA-->>CL: (ref_usage, ref_cost)
CL->>MoA: consume_reference_pricing_calls()
MoA-->>CL: _moa_ref_pricing_calls (advisor physical calls)
CL->>CL: "aggregator_usage = canonical_usage pre-fold"
CL->>CL: "canonical_usage += ref_usage for display"
CL->>CL: _turn_call appended to _turn_calls
CL->>CL: _build_moa_pricing_calls(_moa_ref_pricing_calls, aggregator_usage, ...)
CL->>CL: "_turn_call[pricing_calls] = [adv1, adv2, aggregator]"
CL->>BB: "on_turn_end(turn_usage={calls: _turn_calls})"
BB->>BB: "model default → moa/default when provider==moa"
BB->>Cost: compute_turn_cost(moa/default, moa, ...)
Cost->>Cost: Expand pricing_calls from nested call[pricing_calls]
Cost->>Cost: Filter zero-token calls (failed advisors)
Cost->>Cost: Price each physical call at its own model/provider route
Cost-->>BB: (total_usd, status, perclass)
%%{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 CL as conversation_loop
participant MoA as MoAChatCompletions
participant BB as blackbox._build_record
participant Cost as blackbox/cost.py
CL->>MoA: create(messages)
MoA->>MoA: _run_references_parallel() cache MISS
MoA->>MoA: Accumulate _pending_reference_pricing_calls per advisor
MoA->>MoA: Aggregator call → _last_aggregator_slot
CL->>MoA: consume_reference_usage()
MoA-->>CL: (ref_usage, ref_cost)
CL->>MoA: consume_reference_pricing_calls()
MoA-->>CL: _moa_ref_pricing_calls (advisor physical calls)
CL->>CL: "aggregator_usage = canonical_usage pre-fold"
CL->>CL: "canonical_usage += ref_usage for display"
CL->>CL: _turn_call appended to _turn_calls
CL->>CL: _build_moa_pricing_calls(_moa_ref_pricing_calls, aggregator_usage, ...)
CL->>CL: "_turn_call[pricing_calls] = [adv1, adv2, aggregator]"
CL->>BB: "on_turn_end(turn_usage={calls: _turn_calls})"
BB->>BB: "model default → moa/default when provider==moa"
BB->>Cost: compute_turn_cost(moa/default, moa, ...)
Cost->>Cost: Expand pricing_calls from nested call[pricing_calls]
Cost->>Cost: Filter zero-token calls (failed advisors)
Cost->>Cost: Price each physical call at its own model/provider route
Cost-->>BB: (total_usd, status, perclass)
Reviews (3): Last reviewed commit: "fix(blackbox): keep MoA telemetry failur..." | Re-trigger Greptile
422dcf7 to
bdb89b0
Compare
Summary
moa/defaultinstead of an ambiguousdefaultmodelRoot cause
Session accounting already resolves the real MoA aggregator and prices advisor fan-out separately, but Blackbox only received the folded logical call and attempted to price
(provider=moa, model=default). That virtual preset has no pricing entry, so tokens.ace permanently showed two real-token turns as unpriced.Verification
125 passedacrosstests/plugins/blackbox,tests/run_agent/test_moa_loop_mode.py, and the MoA attribution testspy_compile: all changed production files passPRAGMA quick_check=ok, rollup becomesmoa/default · 2 turns · $0.02 · 0 unpriced