mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-24 02:02:42 +00:00
Show failed Codex image generations in the chat (#5810)
When a Codex image request fails, Codex completes the imageGeneration item with status "failed", an empty result, and an optional failure record. The image mapper only knew how to render a successful image, so it returned nothing and the item vanished from the live timeline and from reopened history. Failed items now map to a failed image_generation tool call carrying the failure details. Closes #5619 Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> Co-authored-by: 3ae3ae <83870598+3ae3ae@users.noreply.github.com>
This commit is contained in:
@@ -6192,6 +6192,107 @@ describe("Codex app-server provider", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test.each([
|
||||
[
|
||||
"a usage limit",
|
||||
{ type: "usageLimitExceeded", limitId: "image_gen", resetsAt: 1786150800 },
|
||||
{ type: "usageLimitExceeded", limitId: "image_gen", resetsAt: 1786150800 },
|
||||
],
|
||||
["no failure details", null, { message: "Image generation failed" }],
|
||||
])(
|
||||
"emits failed imageGeneration items with %s as failed tool calls",
|
||||
(_label, failure, expectedError) => {
|
||||
const session = createSession();
|
||||
const events: AgentStreamEvent[] = [];
|
||||
session.subscribe((event) => events.push(event));
|
||||
|
||||
asInternals(session).handleNotification("item/completed", {
|
||||
item: {
|
||||
id: "image-generation-failed",
|
||||
type: "imageGeneration",
|
||||
status: "failed",
|
||||
revisedPrompt: "paint a blue whale",
|
||||
result: "",
|
||||
transparentBackground: null,
|
||||
failure,
|
||||
savedPath: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(events).toEqual([
|
||||
{
|
||||
type: "timeline",
|
||||
provider: "codex",
|
||||
turnId: "test-turn",
|
||||
item: {
|
||||
type: "tool_call",
|
||||
callId: "image-generation-failed",
|
||||
name: "image_generation",
|
||||
status: "failed",
|
||||
error: expectedError,
|
||||
detail: {
|
||||
type: "unknown",
|
||||
input: { prompt: "paint a blue whale" },
|
||||
output: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
test("keeps failed imageGeneration items in persisted history", async () => {
|
||||
const session = createSession();
|
||||
session.client = {
|
||||
request: vi.fn(async () => ({
|
||||
thread: {
|
||||
turns: [
|
||||
{
|
||||
items: [
|
||||
{
|
||||
type: "imageGeneration",
|
||||
id: "image-generation-failed",
|
||||
status: "failed",
|
||||
revisedPrompt: "paint a blue whale",
|
||||
result: "",
|
||||
transparentBackground: null,
|
||||
failure: { type: "usageLimitExceeded", limitId: "image_gen", resetsAt: null },
|
||||
savedPath: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
await asInternals(session).loadPersistedHistory(session.client);
|
||||
|
||||
const history: AgentStreamEvent[] = [];
|
||||
for await (const event of session.streamHistory()) {
|
||||
history.push(event);
|
||||
}
|
||||
|
||||
expect(history).toEqual([
|
||||
{
|
||||
type: "timeline",
|
||||
provider: "codex",
|
||||
item: {
|
||||
type: "tool_call",
|
||||
callId: "image-generation-failed",
|
||||
name: "image_generation",
|
||||
status: "failed",
|
||||
error: { type: "usageLimitExceeded", limitId: "image_gen", resetsAt: null },
|
||||
detail: {
|
||||
type: "unknown",
|
||||
input: { prompt: "paint a blue whale" },
|
||||
output: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("emits usage_updated on token usage updates and keeps usage on turn completion", () => {
|
||||
const session = createSession();
|
||||
const events: AgentStreamEvent[] = [];
|
||||
|
||||
@@ -1949,6 +1949,15 @@ function mapCodexThreadImageItem(
|
||||
});
|
||||
}
|
||||
|
||||
if (normalizedItem.status === "failed") {
|
||||
return mapCodexToolCallEnvelope({
|
||||
callId: firstStringField(normalizedItem, ["id"]),
|
||||
name: "image_generation",
|
||||
input: { prompt: firstStringField(normalizedItem, ["revisedPrompt", "revised_prompt"]) },
|
||||
error: normalizedItem.failure ?? { message: "Image generation failed" },
|
||||
});
|
||||
}
|
||||
|
||||
const savedPath = firstStringField(normalizedItem, ["savedPath", "saved_path"]);
|
||||
const result = codexImageOutputFromResult(normalizedItem.result);
|
||||
return renderProviderImageOutputAsAssistantMarkdown(
|
||||
|
||||
Reference in New Issue
Block a user