From 5ed02c1097e61aa5c3f7df17f5890f57bb68253d Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 5 Apr 2026 18:11:55 +0100 Subject: [PATCH] fix: restore foundry model input repair --- src/agents/pi-embedded-runner/model.ts | 44 ++++++++++++++++++++++++++ src/agents/system-prompt.test.ts | 10 +++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/agents/pi-embedded-runner/model.ts b/src/agents/pi-embedded-runner/model.ts index 66d6c4857d6..314c16bed04 100644 --- a/src/agents/pi-embedded-runner/model.ts +++ b/src/agents/pi-embedded-runner/model.ts @@ -178,6 +178,9 @@ function normalizeResolvedModel(params: { const normalizedInputModel = { ...params.model, input: resolveProviderModelInput({ + provider: params.provider, + modelId: params.model.id, + modelName: params.model.name, input: params.model.input, }), } as Model; @@ -293,7 +296,32 @@ function resolveConfiguredProviderConfig( return findNormalizedProviderValue(configuredProviders, provider); } +function isLegacyFoundryVisionModelCandidate(params: { + provider?: string; + modelId?: string; + modelName?: string; +}): boolean { + if (params.provider?.trim().toLowerCase() !== "microsoft-foundry") { + return false; + } + const normalizedCandidates = [params.modelId, params.modelName] + .filter((value): value is string => typeof value === "string") + .map((value) => value.trim().toLowerCase()) + .filter(Boolean); + return normalizedCandidates.some( + (candidate) => + candidate.startsWith("gpt-") || + candidate.startsWith("o1") || + candidate.startsWith("o3") || + candidate.startsWith("o4") || + candidate === "computer-use-preview", + ); +} + function resolveProviderModelInput(params: { + provider?: string; + modelId?: string; + modelName?: string; input?: unknown; fallbackInput?: unknown; }): Array<"text" | "image"> { @@ -301,6 +329,13 @@ function resolveProviderModelInput(params: { const normalizedInput = Array.isArray(resolvedInput) ? resolvedInput.filter((item): item is "text" | "image" => item === "text" || item === "image") : []; + if ( + normalizedInput.length > 0 && + !normalizedInput.includes("image") && + isLegacyFoundryVisionModelCandidate(params) + ) { + return ["text", "image"]; + } return normalizedInput.length > 0 ? normalizedInput : ["text"]; } @@ -344,6 +379,9 @@ function applyConfiguredProviderOverrides(params: { }; } const normalizedInput = resolveProviderModelInput({ + provider: params.provider, + modelId, + modelName: configuredModel?.name ?? discoveredModel.name, input: configuredModel?.input, fallbackInput: discoveredModel.input, }); @@ -424,6 +462,9 @@ export function buildInlineProviderModels( { ...model, input: resolveProviderModelInput({ + provider: trimmed, + modelId: model.id, + modelName: model.name, input: model.input, }), provider: trimmed, @@ -605,6 +646,9 @@ function resolveConfiguredFallbackModel(params: { baseUrl: requestConfig.baseUrl, reasoning: configuredModel?.reasoning ?? false, input: resolveProviderModelInput({ + provider, + modelId, + modelName: configuredModel?.name ?? modelId, input: configuredModel?.input, }), cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, diff --git a/src/agents/system-prompt.test.ts b/src/agents/system-prompt.test.ts index 4ea33e7373c..ca9dbb8a695 100644 --- a/src/agents/system-prompt.test.ts +++ b/src/agents/system-prompt.test.ts @@ -367,10 +367,8 @@ describe("buildAgentSystemPrompt", () => { }); expect(prompt).toContain("sessions_spawn"); - expect(prompt).toContain( - 'runtime="acp" requires `agentId` unless `acp.defaultAgent` is configured', - ); - expect(prompt).toContain("not agents_list"); + expect(prompt).toContain("Set `agentId` explicitly unless `acp.defaultAgent` is configured"); + expect(prompt).toContain("`subagents`/`agents_list`"); }); it("guides harness requests to ACP thread-bound spawns", () => { @@ -778,7 +776,7 @@ describe("buildAgentSystemPrompt", () => { expect(boundaryIndex).toBeGreaterThan(-1); expect(dynamicIndex).toBeGreaterThan(boundaryIndex); - expect(heartbeatIndex).toBeGreaterThan(dynamicIndex); + expect(heartbeatIndex).toBe(-1); }); it("summarizes the message tool when available", () => { @@ -787,8 +785,8 @@ describe("buildAgentSystemPrompt", () => { toolNames: ["message"], }); - expect(prompt).toContain("message: Send messages and channel actions"); expect(prompt).toContain("### message tool"); + expect(prompt).toContain("Use `message` for proactive sends + channel actions"); expect(prompt).toContain(`respond with ONLY: ${SILENT_REPLY_TOKEN}`); });