fix(planner): the other four server-side calls were still on the metered key

The test that was supposed to prevent this grepped for the literal
`runtime.complete(` and passed while the phase planner (`mission_plan.rs`),
both swarm calls, and a second enhance path in `claws.rs` still billed the
pay-as-you-go account. They spell the receiver `state.runtime` or wrap the
call across lines, so the receiver name was never the thing to match. The
test now matches the METHOD, and covers all five files.

`complete_or` gains the rule that makes it safe to apply everywhere: a
`name:model` spec is an operator's explicit provider choice — the swarm
worker model is configured exactly that way — and is passed straight to
`Runtime::resolve_provider` untouched. Only a bare name is ambiguous, and a
bare name is precisely what resolves to the default provider. Hijacking a
chosen Kimi or GLM model onto Anthropic would be the same silent-substitution
bug pointed the other way.

`validator_preflight` and the evaluator judge keep calling the runtime
directly, on purpose: both exist to exercise the CONFIGURED spec.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-08 15:55:52 -07:00
co-authored by Claude Opus 5
parent deed591da6
commit ee5a939ce6
4 changed files with 86 additions and 26 deletions
+13 -8
View File
@@ -174,14 +174,19 @@ pub async fn suggest(
PLANNABLE_KINDS.join(", "),
);
let raw = state
.runtime
.complete(PLAN_SYSTEM, &prompt, PLANNER_MODEL, 2000, false)
.await
.map_err(|e| {
eprintln!("mission {id}: plan proposal failed: {e}");
ApiError::Internal
})?;
let raw = crate::subscription::complete_or(
&state.runtime,
PLAN_SYSTEM,
&prompt,
PLANNER_MODEL,
2000,
false,
)
.await
.map_err(|e| {
eprintln!("mission {id}: plan proposal failed: {e}");
crate::subscription::as_api_error(&e)
})?;
let parsed: Value = crate::routes::claws::extract_json(&raw).ok_or_else(|| {
eprintln!("mission {id}: planner returned no JSON: {raw}");