fix(sse): reject unsupported chatgpt-session content parts instead of dropping them

textFromContent threw for image parts but silently skipped everything else, so a `file`
or `input_audio` part vanished and the model answered about content it never received.
Any part that is neither a text part nor an already-handled image part now throws
ChatGptSessionInputError with code "unsupported_content_part" (a terminal 400).
This commit is contained in:
diegosouzapw
2026-09-02 08:30:57 -03:00
parent e200f2d9e6
commit 68ef6a7241
2 changed files with 31 additions and 4 deletions

View File

@@ -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<string, unknown>;
if (typed.type === "text" && typeof typed.text === "string") {
const typed =
part && typeof part === "object" && !Array.isArray(part)
? (part as Record<string, unknown>)
: 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");
}

View File

@@ -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"
);
}
});