fix(rectification): stop forcing named tool_choice on thinking models
Independent Staging Quality Gate / validate (push) Successful in 10m5s
Independent Staging Quality Gate / publish (push) Has been cancelled

Homepage opening failed immediately because thinking-mode providers reject a required first-tool choice.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-18 20:33:08 +08:00
co-authored by Cursor
parent 37e62094d7
commit fa6019a303
4 changed files with 75 additions and 5 deletions
@@ -134,6 +134,9 @@ function safeErrorCode(error: unknown): string {
if (message.includes("agentic_rectification_case_terminal")) return "case_terminal";
if (message.includes("agentic_rectification_case_not_found")) return "case_not_found";
if (message.includes("agentic_rectification_case_session_mismatch")) return "case_session_mismatch";
if (message.includes("Thinking mode does not support this tool_choice")) {
return "thinking_tool_choice_unsupported";
}
return "run_failed";
}
@@ -276,6 +279,10 @@ export async function runV9AgentTurn(options: V9AgentRunOptions): Promise<V9Agen
outcome = await streamAttempt(attemptNumber, attemptId);
} catch (error) {
const errorCode = safeErrorCode(error);
const reason = error instanceof Error ? error.message.slice(0, 180) : "UnknownError";
console.error(
`[rectification-v10] attempt failed case=${caseId} turn=${turnId} attempt=${attemptId} code=${errorCode} reason=${reason}`,
);
outcome = {
ok: false,
status: isRetryableError(errorCode) ? "retryable" : "failed",
@@ -486,7 +493,7 @@ export async function runV9AgentTurn(options: V9AgentRunOptions): Promise<V9Agen
abortSignal: AbortSignal;
prepareStep: (input: { stepNumber: number }) => {
activeTools: string[];
toolChoice: { type: "tool"; toolName: string };
toolChoice: "auto";
} | undefined;
},
): Promise<{
@@ -500,10 +507,13 @@ export async function runV9AgentTurn(options: V9AgentRunOptions): Promise<V9Agen
}).stream(messages, {
maxSteps,
abortSignal: abortController.signal,
// Thinking-mode providers reject named/required tool_choice. Restrict
// the first step to read-case and keep tool_choice auto; the runner
// still refuses any other public tool before case.loaded.
prepareStep: ({ stepNumber }) => stepNumber === 0
? {
activeTools: ["rectification-read-case"],
toolChoice: { type: "tool", toolName: "rectification-read-case" },
toolChoice: "auto",
}
: undefined,
});