diff --git a/open-sse/executors/chatgpt-session/messages.ts b/open-sse/executors/chatgpt-session/messages.ts index efbe49fc2d..6a44648c7d 100644 --- a/open-sse/executors/chatgpt-session/messages.ts +++ b/open-sse/executors/chatgpt-session/messages.ts @@ -34,18 +34,27 @@ function textFromContent(content: unknown): string { if (!Array.isArray(content)) return ""; const chunks: string[] = []; for (const part of content) { - if (!part || typeof part !== "object") continue; - const typed = part as Record; - if (typed.type === "text" && typeof typed.text === "string") { + const typed = + part && typeof part === "object" && !Array.isArray(part) + ? (part as Record) + : null; + if (typed && typed.type === "text" && typeof typed.text === "string") { chunks.push(typed.text); continue; } - if (typed.type === "image_url" || typed.type === "image") { + if (typed && (typed.type === "image_url" || typed.type === "image")) { throw new ChatGptSessionInputError( "vision_unsupported", "ChatGPT Session does not accept image input yet" ); } + // Every other part — file, input_audio, a future part type, or anything malformed — would + // otherwise be dropped in silence, and the model would answer about content it never + // received. Reject loudly instead. + throw new ChatGptSessionInputError( + "unsupported_content_part", + "ChatGPT Session does not accept this message content part type" + ); } return chunks.join("\n"); } diff --git a/tests/unit/chatgpt-session-messages.test.ts b/tests/unit/chatgpt-session-messages.test.ts index be0e91de58..d6b6de9f22 100644 --- a/tests/unit/chatgpt-session-messages.test.ts +++ b/tests/unit/chatgpt-session-messages.test.ts @@ -116,3 +116,21 @@ test("never carries tools into the parsed context", () => { }); assert.equal(parsed.context.tools, undefined); }); + +test("rejects any content part that is neither text nor an image", () => { + for (const part of [ + { type: "file", file: { file_id: "f-1" } }, + { type: "input_audio", input_audio: { data: "AA", format: "wav" } }, + ]) { + assert.throws( + () => + buildParsedRequest({ + route, + messages: [{ role: "user", content: [part] }], + stream: false, + }), + (error: unknown) => + error instanceof ChatGptSessionInputError && error.code === "unsupported_content_part" + ); + } +});