Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
76be330
fix(tests): update 3 tests stale after intentional orchestrator/free …
claude Sep 1, 2026
a065431
ci: pin available Linux runner
seonghobae Sep 1, 2026
a32c736
ci: pin fuzz Linux runner
seonghobae Sep 1, 2026
62479a9
ci: pin security Linux runner
seonghobae Sep 1, 2026
f3ef3dc
test: preserve mixed spend evidence semantics
seonghobae Sep 1, 2026
25ec482
test: isolate spend source from optional judge dependency
seonghobae Sep 1, 2026
fd9aac5
fix: reject non-empty all-zero served_usage as reported spend evidence
claude Sep 1, 2026
3c8373b
test(accounting): isolate provider usage capture
seonghobae Sep 1, 2026
903aa4f
test(judge): distinguish provider zero usage provenance
seonghobae Sep 1, 2026
1f97228
test(judge): probe usage provenance aliases and TOCTOU
seonghobae Sep 1, 2026
934fdb0
chore: apply one-shot usage provenance repair
seonghobae Sep 1, 2026
9556fc8
ci(repair): move usage provenance one-shot off saturated Linux queue
seonghobae Sep 1, 2026
1fac323
fix(judge): preserve provider usage provenance
claude Sep 1, 2026
c4d46b7
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
8b2ff71
ci(repair): make usage provenance writer single-flight
seonghobae Sep 1, 2026
9447030
fix(judge): preserve provider usage provenance
github-actions[bot] Sep 1, 2026
39736e7
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
917ce40
test(judge): cover Responses zero usage fields
seonghobae Sep 1, 2026
238a880
ci(repair): apply usage counter family fix once
seonghobae Sep 1, 2026
9ab8c59
ci(repair): move usage counter writer to Linux
seonghobae Sep 1, 2026
4351a04
ci(temp): repair Responses usage alias accounting
seonghobae Sep 1, 2026
82cb7ed
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
589210a
fix(repair): make usage alias writer executable
seonghobae Sep 1, 2026
6eafe23
fix(judge): accept Responses usage counters in both accounting helpers
claude Sep 1, 2026
dfc04d8
ci(repair): remove superseded usage counter writer
seonghobae Sep 1, 2026
06e6369
ci: remove temporary usage repair workflow
seonghobae Sep 1, 2026
e53e92f
ci(temp): execute bounded Responses usage repair
seonghobae Sep 1, 2026
c1bf375
ci(repair): apply Responses usage alias fix with locked test env
seonghobae Sep 1, 2026
bd8f8f8
ci: remove failed one-shot usage repair workflow
seonghobae Sep 1, 2026
2f5f84e
ci: remove queued one-shot usage repair workflow
seonghobae Sep 1, 2026
d9ceca4
ci(repair): retry Responses alias repair with minimal writer
seonghobae Sep 1, 2026
bcc7d18
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
ebb087b
chore: remove now-fulfilled usage alias repair retry workflow
claude Sep 1, 2026
c499516
ci(repair): trigger Responses alias repair on PR events
seonghobae Sep 1, 2026
8f9fd87
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
2253866
test(batch): add exact-head worker usage fixture repair driver
seonghobae Sep 2, 2026
cbf5860
ci(test): run exact-head batch usage fixture repair
seonghobae Sep 2, 2026
22f665c
chore(test): mark current-main convergence intent
seonghobae Sep 2, 2026
44dcb0a
chore(test): add exact current-main merge helper
seonghobae Sep 2, 2026
c8bff9a
chore(test): stage non-destructive current-main merge
seonghobae Sep 2, 2026
338464a
merge current main into PR 1002 without rewriting history
seonghobae Sep 2, 2026
61384c5
test(batch): isolate provider usage fixture from optional judge
Sep 2, 2026
2f325e8
docs(tests): close CodeRabbit's diff-scoped docstring coverage gap
claude Sep 2, 2026
cef6214
Merge remote-tracking branch 'origin/main' into pr1002-work
claude Sep 2, 2026
02b61e4
Merge remote-tracking branch 'origin/main' into pr1002-work
claude Sep 3, 2026
65f5a03
fix(tests): wait for provider embedding batch completion before asser…
claude Sep 3, 2026
91ef087
fix: capture judge usage provenance atomically, immune to pool races
claude Sep 3, 2026
27b6ba5
Merge branch 'main' into fix/orchestrated-responses-stream-and-spend-…
opencode-agent[bot] Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ concurrency:
jobs:
pytest:
name: Full unit and contract suite
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand All @@ -39,7 +39,7 @@ jobs:

nim_benchmark_quality:
name: NIM benchmark coverage, docstrings, and package smoke
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
# Always-on, cross-platform property tests. Fast, deterministic, no native deps.
property_tests:
name: Hypothesis property tests
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand All @@ -45,7 +45,7 @@ jobs:
# so CI stays cheap; schedule/dispatch runs use a longer budget.
coverage_guided:
name: Atheris coverage-guided
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
codeql_analysis:
name: CodeQL analysis
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
actions: read
contents: read
Expand All @@ -51,7 +51,7 @@ jobs:

python_supply_chain:
name: Python supply chain
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand Down
153 changes: 128 additions & 25 deletions contextual_orchestrator/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ class _FastMLSIJudgeAdapter:
served_agent_id: str | None = None
served_model: str | None = None
served_usage: dict[str, Any] | None = None
served_usage_source: str | None = None
served_output: str | None = None
mode: str = "auto"
allowed_agent_ids: set[str] | None = None
Expand All @@ -381,10 +382,27 @@ def client(self) -> ModelClient:
"""Expose the existing gateway client capability to fast-mlsirm."""
return self.orchestrator.client

@staticmethod
def _usage_source_for_agent(agent: ModelAgent, usage: Any) -> str | None:
"""Classify transport-boundary usage without guessing from token counts."""
if not isinstance(usage, dict):
return None
return (
"synthetic_mock"
if agent.base_url.startswith("mock://")
else "provider_reported"
)

def complete(self, messages: list[ChatMessage], mode: str | None = None) -> dict[str, Any]:
"""Return one judge completion through the constrained adapter."""
if mode is not None and (type(mode) is not str or mode not in {"auto", "route", "conduct"}):
raise ValueError("mode must be auto, route, or conduct")
served_agent_at_call: ModelAgent | None = None

def _capture_serving_agent(agent: ModelAgent) -> None:
nonlocal served_agent_at_call
served_agent_at_call = agent

output, served_id, served_model, usage = self.orchestrator._invoke(
self._agent(),
messages,
Expand All @@ -393,7 +411,36 @@ def complete(self, messages: list[ChatMessage], mode: str | None = None) -> dict
allowed_agent_ids=self.allowed_agent_ids,
eligibility_role="verifier",
excluded_agent_ids=self.excluded_agent_ids,
)
on_success=_capture_serving_agent,
)
# Prefer the exact ModelAgent _invoke's on_success callback captured
# atomically at the moment it served this call. A concurrent admin
# request can replace TaskOrchestrator.candidates (add/patch/remove
# candidate) with a different base_url under the same served_id in the
# gap between that provider call completing and this method resolving
# provenance; since ModelAgent is frozen and pool mutation always
# reassigns self.candidates rather than mutating it in place, the
# captured reference is immune to that race, unlike a fresh
# self.orchestrator._agent(served_id) lookup against the live mutable
# pool (Devin review on PR #1002).
#
# _invoke may also fail over to a candidate outside this orchestrator's
# own pool (e.g. a test double standing in for the served agent), and a
# custom _invoke test double may not accept/call on_success at all;
# unresolvable provenance must fail closed to unknown (None, treated as
# unmeasured downstream) rather than raise and drop this
# otherwise-successful call's accounting entirely.
if served_agent_at_call is not None:
self.served_usage_source = self._usage_source_for_agent(
served_agent_at_call, usage
)
else:
try:
served_agent = self.orchestrator._agent(served_id)
except KeyError:
self.served_usage_source = None
else:
self.served_usage_source = self._usage_source_for_agent(served_agent, usage)
return self._completion_payload(
output, served_id, served_model, usage, self.mode if mode is None else mode
)
Expand Down Expand Up @@ -434,8 +481,12 @@ def complete_structured(
# must survive validation failing on how to interpret its result.
self.served_agent_id = agent.id
self.served_model = agent.model
response_usage = response.get("usage")
self.served_usage = (
response.get("usage") if isinstance(response.get("usage"), dict) else None
dict(response_usage) if isinstance(response_usage, dict) else None
)
self.served_usage_source = self._usage_source_for_agent(
agent, self.served_usage
)
output = ModelClient._response_content(agent, response)
return self._completion_payload(
Expand All @@ -453,7 +504,8 @@ def _completion_payload(
"""Build the bounded adapter response shared by normal and structured calls."""
self.served_agent_id = served_id
self.served_model = served_model
self.served_usage = usage
usage_snapshot = dict(usage) if isinstance(usage, dict) else None
self.served_usage = usage_snapshot
self.served_output = output
trace = [
{
Expand All @@ -464,8 +516,8 @@ def _completion_payload(
"output": output,
}
]
if usage is not None:
trace[0]["usage"] = usage
if usage_snapshot is not None:
trace[0]["usage"] = dict(usage_snapshot)
Comment thread
seonghobae marked this conversation as resolved.
return {
"answer": output,
"mode": mode,
Expand Down Expand Up @@ -7670,6 +7722,7 @@ def _invoke(
allowed_agent_ids: set[str] | None = None,
eligibility_role: str | None = None,
excluded_agent_ids: set[str] | None = None,
on_success: Callable[[ModelAgent], None] | None = None,
) -> tuple[str, str, str, dict[str, Any] | None]:
"""Call an agent with bounded, safety-aware tool retry and failover.

Expand All @@ -7680,6 +7733,21 @@ def _invoke(

``eligibility_role`` keeps operator exclusions tied to the role used to
select the primary when the call's effort profile has a distinct name.

``on_success``, when given, receives the exact ``ModelAgent`` that served
the winning call before this method returns. ``ModelAgent`` is a frozen
dataclass and ``candidates``/``race_members`` here are call-local lists
snapshotted before any provider transport; a pool-mutation API
(add/patch/remove candidate) only ever reassigns ``self.candidates`` to a
new list object and never mutates an existing one in place (see
``_agent``), so this reference stays valid even if a concurrent request
replaces the same agent id in the live pool while this call is still in
flight or between this method returning and a caller's own follow-up
lookup. Callers that need serving-transport provenance (e.g. classifying
usage as provider-reported vs. synthetic) must prefer this over a
post-hoc ``self._agent(served_id)`` lookup, which reads the live mutable
pool and can silently resolve to a different agent (Devin review on
PR #1002).
"""
required_tags = ("vision",) if self._source_image_parts(messages) else ()
prompt_context = self._prompt_interaction(messages)
Expand Down Expand Up @@ -7762,6 +7830,11 @@ def call(agent: ModelAgent) -> tuple[str, str, str, dict[str, Any] | None]:
outcome.completion_ms / 1000,
output_tokens=output_tokens,
)
if on_success is not None:
for candidate in race_members:
if candidate.id == outcome.winner_endpoint_id:
on_success(candidate)
break
return outcome.value
retry_limit = min(self.tool_retry_attempts, MAX_TOOL_RETRY_ATTEMPTS)
bounded_provider_response_failures = 0
Expand Down Expand Up @@ -7881,6 +7954,8 @@ def call(agent: ModelAgent) -> tuple[str, str, str, dict[str, Any] | None]:
total_tokens=total_tokens,
)
self._record_success(agent.id)
if on_success is not None:
on_success(agent)
return output, agent.id, agent.model, usage
if (
last_provider_response_error is not None
Expand Down Expand Up @@ -8168,18 +8243,14 @@ def _model_judge_verification(
"judge": "model",
}
verification.update(self._judge_adapter_accounting_fields(judge_adapter))
# The adapter's provider-boundary capture is authoritative for
# usage. fast-mlsirm aggregates a missing trace usage into a
# non-empty zero-token mapping, which must not turn an unmeasured
# call into provider-reported zero spend here.
result_usage_has_positive_evidence = isinstance(result.usage, Mapping) and any(
type(result.usage.get(key)) is int and result.usage[key] > 0
for key in ("prompt_tokens", "completion_tokens", "total_tokens")
)
if result.usage and (
judge_adapter.served_usage is not None or result_usage_has_positive_evidence
# Prefer the adapter's transport-boundary snapshot, including an
# authoritative all-zero provider report. Only fall back to a
# positive fast-mlsirm aggregate when no boundary usage survived.
if (
"judge_usage" not in verification
and self._usage_has_positive_evidence(result.usage)
):
verification["judge_usage"] = result.usage
verification["judge_usage"] = dict(result.usage)
verification["judge_orchestration_mode"] = result.orchestration_mode
# The provider call has already completed by this point (result
# is a real response, with judge_agent_id/judge_model/judge_usage
Expand Down Expand Up @@ -8246,6 +8317,35 @@ def _model_judge_verification(
**self._judge_adapter_accounting_fields(judge_adapter),
}

@staticmethod
def _usage_has_positive_evidence(usage: Any) -> bool:
"""Return whether Chat or Responses usage reports a positive token count.

This remains the compatibility rule for aggregate usage whose origin
is unknown. A provider-boundary zero measurement is handled separately
by ``_usage_is_reported_token_mapping`` plus explicit provenance.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"""
if not isinstance(usage, Mapping):
return False
counts = (
usage.get("prompt_tokens", usage.get("input_tokens")),
usage.get("completion_tokens", usage.get("output_tokens")),
usage.get("total_tokens"),
)
return any(type(value) is int and value > 0 for value in counts)

@staticmethod
def _usage_is_reported_token_mapping(usage: Any) -> bool:
"""Validate complete non-negative Chat or Responses token counters."""
if not isinstance(usage, Mapping):
return False
counts = (
usage.get("prompt_tokens", usage.get("input_tokens")),
usage.get("completion_tokens", usage.get("output_tokens")),
usage.get("total_tokens"),
)
return all(type(value) is int and value >= 0 for value in counts)

@staticmethod
def _judge_adapter_accounting_fields(
judge_adapter: "_FastMLSIJudgeAdapter | None",
Expand All @@ -8270,15 +8370,18 @@ def _judge_adapter_accounting_fields(
fields["judge_agent_id"] = judge_adapter.served_agent_id
if judge_adapter.served_model is not None:
fields["judge_model"] = judge_adapter.served_model
if judge_adapter.served_usage:
# A falsy served_usage (missing/invalid response usage) is left
# genuinely absent rather than fabricated as reported-zero
# (Devin review on #961, on this same fix): judge_agent_id/
# judge_model above already keep a completed-but-unmeasured call
# attributable, and downstream budget/spend consumers derive an
# honest estimated fallback from the judge's own served_output
# text instead of trusting a fabricated "reported" usage dict.
fields["judge_usage"] = judge_adapter.served_usage
if TaskOrchestrator._usage_has_positive_evidence(
judge_adapter.served_usage
) or (
judge_adapter.served_usage_source == "provider_reported"
and TaskOrchestrator._usage_is_reported_token_mapping(
judge_adapter.served_usage
)
):
# Positive aggregate usage remains backward-compatible. Exact
# provider-boundary zero usage is accepted only with explicit
# provenance; synthetic mock/fast-mlsirm zero remains unmeasured.
fields["judge_usage"] = dict(judge_adapter.served_usage)
if judge_adapter.served_output is not None:
# The judge's own generated text, not the verifier_output text
# it was judging (Devin review on #961, on this same fallback
Expand Down
9 changes: 8 additions & 1 deletion tests/test_batch_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,16 @@ def _orch(client: ModelClient | None = None) -> TaskOrchestrator:


def test_batch_route_persists_runs_with_usage() -> None:
"""Batch routing persists one run per task, each carrying the worker Batch API's own usage."""
client = _CountingClient()
orchestrator = _orch(client)
records = orchestrator.batch_route([t["prompt"] for t in TASKS])
# This regression measures the worker Batch API usage contract only. The
# full CI environment installs fast-mlsirm, whose optional model-judge call
# is a separate spend source; allowing it into this fixture would make the
# aggregate usage source correctly mixed/unavailable and stop testing the
# worker provenance this case is named for.
with patch.object(orchestrator_module, "_resolve_fast_mlsirm_components", return_value=None):
records = orchestrator.batch_route([t["prompt"] for t in TASKS])

assert len(records) == 3
assert client.batch_calls == 1 and client.chat_calls == 0 # one batch, zero serial calls
Expand Down
Loading
Loading