fix(coding-agent): resolve branch model selection with one catalog lookup

getBranchSelection looked up the model catalog once per assistant message,
which made prompt submission scale with session length. Walk the branch
backward instead: only the last model_change can hold against later
responses, so at most that model needs a lookup.

closes #10198
This commit is contained in:
Armin Ronacher 2026-09-30 14:19:46 +02:00
parent 37c9d0d200
commit a0660b174e
3 changed files with 87 additions and 13 deletions

View file

@ -122,26 +122,37 @@ export function findLatestResponse(messages: readonly AgentMessage[]): Assistant
* `model_change`, because responses name the physical models it routed to. Otherwise the latest
* physical response wins, as in sessions without virtual models. A virtual model that is no longer
* registered does not hold, so the selection falls back to the physical model that answered last.
*
* Only the last `model_change` can hold, so this looks up at most one model in the catalog.
*/
export function getBranchSelection(
branch: readonly SessionEntry[],
getModel: (provider: string, modelId: string) => Model<Api> | undefined,
): { provider: string; modelId: string } | undefined {
const isVirtual = (provider: string, modelId: string) => {
const model = getModel(provider, modelId);
return model !== undefined && isVirtualModel(model);
};
let selection: { provider: string; modelId: string } | undefined;
for (const entry of branch) {
for (let i = branch.length - 1; i >= 0; i--) {
const entry = branch[i];
if (entry.type === "model_change") {
selection = { provider: entry.provider, modelId: entry.modelId };
} else if (entry.type === "message" && entry.message.role === "assistant" && !isVirtualModel(entry.message)) {
if (!selection || !isVirtual(selection.provider, selection.modelId)) {
selection = { provider: entry.message.provider, modelId: entry.message.model };
}
return { provider: entry.provider, modelId: entry.modelId };
}
if (entry.type === "message" && entry.message.role === "assistant" && !isVirtualModel(entry.message)) {
const response = { provider: entry.message.provider, modelId: entry.message.model };
const change = findLastModelChange(branch, i);
const model = change && getModel(change.provider, change.modelId);
return change && model && isVirtualModel(model) ? change : response;
}
}
return selection;
return undefined;
}
function findLastModelChange(
branch: readonly SessionEntry[],
before: number,
): { provider: string; modelId: string } | undefined {
for (let i = before - 1; i >= 0; i--) {
const entry = branch[i];
if (entry.type === "model_change") return { provider: entry.provider, modelId: entry.modelId };
}
return undefined;
}
/** Latest router state a session branch stores for a virtual model. */