Files
OmniRoute/open-sse/executors/codex/toolCallRepair.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

58 lines
2.2 KiB
TypeScript

// Repairs Codex Responses-API `input` arrays that are missing an output item for a
// function/custom tool call, which upstream rejects. Extracted from codex.ts to keep
// the executor chokepoint file under the file-size gate (leaf module, no `this` usage).
type ResponsesInputItem = Record<string, unknown>;
const TOOL_CALL_OUTPUT_TYPES = new Set(["function_call_output", "custom_tool_call_output"]);
function outputTypeForCall(callType: "function_call" | "custom_tool_call"): string {
return callType === "custom_tool_call" ? "custom_tool_call_output" : "function_call_output";
}
/**
* Mutates `body.input` in place, inserting an empty output item immediately after
* any `function_call`/`custom_tool_call` item that has no matching output item.
*/
export function repairMissingCodexToolCallOutputs(body: Record<string, unknown>): void {
if (!Array.isArray(body.input)) return;
const existingOutputKeys = new Set<string>();
for (const item of body.input) {
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
const record = item as ResponsesInputItem;
if (typeof record.type !== "string" || !TOOL_CALL_OUTPUT_TYPES.has(record.type)) continue;
if (typeof record.call_id === "string" && record.call_id.trim()) {
existingOutputKeys.add(`${record.type}:${record.call_id.trim()}`);
}
}
const repaired: unknown[] = [];
let insertedCount = 0;
for (const item of body.input) {
repaired.push(item);
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
const record = item as ResponsesInputItem;
if (record.type !== "function_call" && record.type !== "custom_tool_call") continue;
const callId = typeof record.call_id === "string" ? record.call_id.trim() : "";
const outputType = outputTypeForCall(record.type);
const outputKey = `${outputType}:${callId}`;
if (!callId || existingOutputKeys.has(outputKey)) continue;
repaired.push({
type: outputType,
call_id: callId,
output: "",
});
existingOutputKeys.add(outputKey);
insertedCount++;
}
if (insertedCount > 0) {
body.input = repaired;
console.debug(
`[Codex] repairMissingCodexToolCallOutputs: inserted ${insertedCount} empty tool output item(s)`
);
}
}