fix(coding-agent/eval): remove per-call model override from agent() (#6438)

Completes the maintainer's removal of per-call model selection from
subagent spawns (9f8aa87dbf removed it from the task tool and the
model-facing agent() docs/prompt, but the eval agent() runtime and all
four preludes still accepted and forwarded a per-call model).

Subagents now always resolve through the selected agent's frontmatter
model and settings, so an explicit model: "default" can no longer
silently route children onto the parent session model.

- agent-bridge: drops "model?" from agentArgsSchema and the request
  forward; adds "+": "delete" so a legacy model argument is stripped
  (same contract as the task wire schemas).
- JS/Python/Ruby/Julia preludes: remove the model parameter from
  agent(); completion()'s tier selector is unchanged.
- docs (tools/eval.md, python-repl.md) updated to the removed surface.

Refs #6438
This commit is contained in:
Slava Zavadsky
2026-08-04 08:35:01 -04:00
parent 003bb5548c
commit b8779dae63
10 changed files with 31 additions and 24 deletions
@@ -290,10 +290,7 @@ describe("runEvalAgent", () => {
}),
});
await runEvalAgent(
{ prompt: " hello ", label: "My Agent", model: "p/override", schema },
{ session, signal: abortController.signal },
);
await runEvalAgent({ prompt: " hello ", label: "My Agent", schema }, { session, signal: abortController.signal });
await runEvalAgent({ prompt: "plain" }, { session });
const firstOptions = runSpy.mock.calls[0]?.[0];
@@ -306,10 +303,26 @@ describe("runEvalAgent", () => {
expect(firstOptions.outputSchemaOverridesAgent).toBe(true);
expect(firstOptions.assignment).toBe("hello");
expect(firstOptions.description).toBe("My Agent");
expect(firstOptions.modelOverride).toEqual(["p/override"]);
// No per-call override: the agent's own frontmatter model applies.
expect(firstOptions.modelOverride).toEqual(["p/current"]);
expect(secondOptions.outputSchema).toBeUndefined();
expect(secondOptions.outputSchemaOverridesAgent).toBeUndefined();
});
it("drops a per-call model argument on agent() (removed, issue #6438)", async () => {
mockAgents();
const runSpy = vi.spyOn(taskExecutor, "runSubprocess").mockImplementation(async options => singleResult(options));
// The schema strips unknown keys; a legacy `model` argument is silently
// discarded so resolution is identical to omitting it — the agent's own
// frontmatter model applies (issue #6438).
await runEvalAgent({ prompt: "work", model: "default" }, { session: makeSession() });
await runEvalAgent({ prompt: "work" }, { session: makeSession() });
const withModel = runSpy.mock.calls[0]?.[0];
const withoutModel = runSpy.mock.calls[1]?.[0];
expect(withModel?.modelOverride).toEqual(withoutModel?.modelOverride);
});
it("returns host-parsed data for caller, agent, and inherited schemas", async () => {
const agentSchema = { type: "object" };
const sessionSchema = { type: "object" };
@@ -66,12 +66,11 @@ describe("eval js agent() handle", () => {
) => Promise<unknown>;
const schema = { type: "object", properties: { ok: { type: "boolean" } } };
await positionalAgent("scout", "reviewer", "p/model", "Legacy", schema, true, false, true, "strict");
await positionalAgent("scout", "reviewer", "Legacy", schema, true, false, true, "strict");
expect(seenArgs).toEqual({
prompt: "scout",
agent: "reviewer",
model: "p/model",
label: "Legacy",
schema,
isolated: true,