mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 23:42:03 +00:00
feat(skills): add model override support via skill frontmatter (#2949)
* feat(skills): add model override support via skill frontmatter Allow skills to specify a `model` field in YAML frontmatter to override which model is used for subsequent turns within the same agentic loop. The override flows through ToolResult → ToolCallResponseInfo → SendMessageOptions and naturally expires when the loop ends. Resolves #2052 * fix(core): only include modelOverride in response when defined Fixes strict equality test failures in nonInteractiveToolExecutor.test.ts where the extra undefined modelOverride field caused object mismatch. * fix(skills): fix model override pipeline issues - Wire up modelOverride in interactive CLI path (useGeminiStream) - Fix inherit/no-model unable to clear a prior override by using 'in' operator instead of truthiness checks in scheduler and CLI - Reject empty/whitespace model strings in parseModelField() - Extract shared parseModelField() to deduplicate skill-load and skill-manager parsing logic - Propagate modelOverride through stop-hook continuation in client * fix(skills): persist model override across turns in interactive and cron paths The interactive path stored the skill model override in a local variable, causing it to be lost when subsequent non-skill tool turns ran. Use a ref to persist the override for the duration of the agentic loop, resetting on new user messages. Also propagate modelOverride in the cron execution loop for consistency with the main non-interactive path. * fix(skills): preserve model override on retry and add unit tests Retry in interactive mode was clearing modelOverrideRef, causing the skill-selected model to silently fall back to session default. Guard the reset so retries preserve the active override. Add unit tests for parseModelField (edge cases, type validation) and modelOverride propagation through the skill tool result path.
This commit is contained in:
parent
189df1b098
commit
9a889dc614
12 changed files with 250 additions and 8 deletions
|
|
@ -251,6 +251,7 @@ export async function runNonInteractive(
|
|||
let currentMessages: Content[] = [{ role: 'user', parts: initialParts }];
|
||||
|
||||
let isFirstTurn = true;
|
||||
let modelOverride: string | undefined;
|
||||
while (true) {
|
||||
turnCount++;
|
||||
if (
|
||||
|
|
@ -270,6 +271,7 @@ export async function runNonInteractive(
|
|||
type: isFirstTurn
|
||||
? SendMessageType.UserQuery
|
||||
: SendMessageType.ToolResult,
|
||||
modelOverride,
|
||||
},
|
||||
);
|
||||
isFirstTurn = false;
|
||||
|
|
@ -368,6 +370,13 @@ export async function runNonInteractive(
|
|||
if (toolResponse.responseParts) {
|
||||
toolResponseParts.push(...toolResponse.responseParts);
|
||||
}
|
||||
|
||||
// Capture model override from skill tool results.
|
||||
// Use `in` so that undefined (from inherit/no-model skills) clears a prior override,
|
||||
// while non-skill tools (field absent) leave the current override intact.
|
||||
if ('modelOverride' in toolResponse) {
|
||||
modelOverride = toolResponse.modelOverride;
|
||||
}
|
||||
}
|
||||
currentMessages = [{ role: 'user', parts: toolResponseParts }];
|
||||
} else {
|
||||
|
|
@ -400,6 +409,7 @@ export async function runNonInteractive(
|
|||
{ role: 'user', parts: [{ text: cronPrompt }] },
|
||||
];
|
||||
let cronIsFirstTurn = true;
|
||||
let cronModelOverride: string | undefined;
|
||||
|
||||
while (true) {
|
||||
const cronToolCallRequests: ToolCallRequestInfo[] = [];
|
||||
|
|
@ -412,6 +422,7 @@ export async function runNonInteractive(
|
|||
type: cronIsFirstTurn
|
||||
? SendMessageType.Cron
|
||||
: SendMessageType.ToolResult,
|
||||
modelOverride: cronModelOverride,
|
||||
},
|
||||
);
|
||||
cronIsFirstTurn = false;
|
||||
|
|
@ -476,6 +487,10 @@ export async function runNonInteractive(
|
|||
...toolResponse.responseParts,
|
||||
);
|
||||
}
|
||||
|
||||
if ('modelOverride' in toolResponse) {
|
||||
cronModelOverride = toolResponse.modelOverride;
|
||||
}
|
||||
}
|
||||
cronMessages = [
|
||||
{ role: 'user', parts: cronToolResponseParts },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue