Skip to content

fix(blackbox): price MoA turns by physical model routes - #342

Merged
Kyzcreig merged 3 commits into
mainfrom
fix/moa-blackbox-attribution
Jul 14, 2026
Merged

Kyzcreig merged 3 commits into
mainfrom
fix/moa-blackbox-attribution

Conversation

@Kyzcreig

Copy link
Copy Markdown
Collaborator

Summary

  • preserve each MoA advisor's physical model/provider/token buckets for Blackbox pricing
  • add the acting aggregator as a physical pricing call while keeping one logical turn
  • show the virtual preset explicitly as moa/default instead of an ambiguous default model
  • ignore zero-token failed advisors when reconciling mixed-model cost, while retaining partial status for nonzero unknown calls

Root 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

  • RED first: 4 focused regressions failed on current main
  • 125 passed across tests/plugins/blackbox, tests/run_agent/test_moa_loop_mode.py, and the MoA attribution tests
  • Ruff: all changed files pass
  • py_compile: all changed production files pass
  • Historical two-row rehearsal: both guarded updates applied, PRAGMA quick_check=ok, rollup becomes moa/default · 2 turns · $0.02 · 0 unpriced

@Kyzcreig
Kyzcreig enabled auto-merge (squash) July 14, 2026 20:37
@Kyzcreig
Kyzcreig force-pushed the fix/moa-blackbox-attribution branch from 7bd43f1 to 67182f8 Compare July 14, 2026 20:44
@greptile-apps

greptile-apps Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

Greptile Summary

This PR fixes MoA (Mixture of Agents) pricing in the Blackbox telemetry plugin. Previously, a MoA turn was recorded with provider="moa" and model="default" — a virtual preset with no pricing entry — so every real-token MoA turn appeared as "unpriced" in tokens.ace.

  • moa_loop.py: adds base_url to _RefAccounting, tracks per-advisor physical routing in _pending_reference_pricing_calls, and exposes it via a new consume_reference_pricing_calls() method.
  • conversation_loop.py: introduces _build_moa_pricing_calls() that assembles advisor + aggregator physical calls, then attaches the list as pricing_calls on the logical turn dict — wrapped in the same fail-open try/except as all other telemetry mutations.
  • plugins/blackbox/cost.py: expands any nested pricing_calls list before pricing; zero-token failed advisors are filtered out so a single failed advisor cannot demote an otherwise fully-priced turn to "partial".
  • plugins/blackbox/__init__.py: renames model="default" → "moa/default" when provider="moa" so Spend-by-model shows an unambiguous identity instead of a bare "default" that looks like an unnamed real model.

Confidence Score: 5/5

The change is safe to merge; it touches only telemetry accounting and cannot affect live inference or conversation state.

Every new code path that touches the conversation loop is wrapped in the same fail-open try/except guard that protects all other telemetry mutations. The Blackbox cost logic correctly handles the three edge cases that could cause regressions (explicitly-empty pricing_calls, zero-token failed advisors, and cache-HIT iterations that produce no advisor entries). The PR ships focused regression tests that exercised each of those paths red-first before the fix, and the pre-existing consume-once semantics for _pending_reference_pricing_calls are symmetric with consume_reference_usage.

No files require special attention.

Important Files Changed

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)
Loading
%%{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)
Loading

Reviews (3): Last reviewed commit: "fix(blackbox): keep MoA telemetry failur..." | Re-trigger Greptile

Comment thread agent/conversation_loop.py Outdated
Comment thread plugins/blackbox/cost.py
@Kyzcreig
Kyzcreig force-pushed the fix/moa-blackbox-attribution branch from 422dcf7 to bdb89b0 Compare July 14, 2026 21:00
@Kyzcreig
Kyzcreig merged commit 86498df into main Jul 14, 2026
35 checks passed
@Kyzcreig
Kyzcreig deleted the fix/moa-blackbox-attribution branch July 14, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant