fix(ai): use "(no tool output)" placeholder for empty tool results without images (#6290)
OpenAI Completions and Responses providers unconditionally replaced empty tool result text with "(see attached image)", even when the result had no image content. This caused the model to hallucinate image attachments for commands that produce no output (e.g. curl -s with SSL errors, grep with no matches, true/false). Now matches the Google provider behavior: "(see attached image)" is only used when images are actually present; empty results get "(no tool output)". Co-authored-by: tzwm <tzwm@users.noreply.github.com> Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
This commit is contained in:
@@ -54,6 +54,17 @@ function buildToolResult(toolCallId: string, timestamp: number): ToolResultMessa
|
||||
};
|
||||
}
|
||||
|
||||
function buildEmptyToolResult(toolCallId: string, timestamp: number): ToolResultMessage {
|
||||
return {
|
||||
role: "toolResult",
|
||||
toolCallId,
|
||||
toolName: "bash",
|
||||
content: [{ type: "text", text: "" }],
|
||||
isError: false,
|
||||
timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
describe("openai-completions convertMessages", () => {
|
||||
it("batches tool-result images after consecutive tool results", () => {
|
||||
const { compat: _compat, ...baseModel } = getModel("openai", "gpt-4o-mini");
|
||||
@@ -100,4 +111,39 @@ describe("openai-completions convertMessages", () => {
|
||||
);
|
||||
expect(imageParts.length).toBe(2);
|
||||
});
|
||||
|
||||
it("uses '(no tool output)' placeholder for empty tool results without images", () => {
|
||||
const { compat: _compat, ...baseModel } = getModel("openai", "gpt-4o-mini");
|
||||
const model: Model<"openai-completions"> = {
|
||||
...baseModel,
|
||||
api: "openai-completions",
|
||||
input: ["text", "image"],
|
||||
};
|
||||
|
||||
const now = Date.now();
|
||||
const assistantMessage: AssistantMessage = {
|
||||
role: "assistant",
|
||||
content: [{ type: "toolCall", id: "tool-1", name: "bash", arguments: { command: "true" } }],
|
||||
api: model.api,
|
||||
provider: model.provider,
|
||||
model: model.id,
|
||||
usage: emptyUsage,
|
||||
stopReason: "toolUse",
|
||||
timestamp: now,
|
||||
};
|
||||
|
||||
const context: Context = {
|
||||
messages: [
|
||||
{ role: "user", content: "Run the command", timestamp: now - 1 },
|
||||
assistantMessage,
|
||||
buildEmptyToolResult("tool-1", now + 1),
|
||||
],
|
||||
};
|
||||
|
||||
const messages = convertMessages(model, context, compat);
|
||||
const toolMessage = messages.find((m) => m.role === "tool") as { role: "tool"; content: string } | undefined;
|
||||
expect(toolMessage).toBeTruthy();
|
||||
expect(toolMessage?.content).toBe("(no tool output)");
|
||||
expect(toolMessage?.content).not.toContain("see attached image");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user