Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/adapters/openai-responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,13 @@ function canonicalForwardSystemText(item: Record<string, unknown>): string | nul
return text;
}

/** Only message items may carry privileged system instructions. */
function isCanonicalForwardSystemMessage(item: unknown): item is Record<string, unknown> {
return isPlainObject(item)
&& (item.type === undefined || item.type === "message")
&& item.role === "system";
}

/**
* The public Responses API accepts input system messages and `truncation`, but the canonical
* ChatGPT Codex forward endpoint rejects both. Fold only fully textual system messages into the
Expand All @@ -1213,7 +1220,7 @@ function normalizeCanonicalForwardPromptEnvelope(body: unknown): unknown {
let sawSystemMessage = false;
let canFoldAllSystemMessages = true;
for (const item of input) {
if (!isPlainObject(item) || item.role !== "system") continue;
if (!isCanonicalForwardSystemMessage(item)) continue;
sawSystemMessage = true;
const text = canonicalForwardSystemText(item);
if (text === null) {
Expand All @@ -1227,7 +1234,7 @@ function normalizeCanonicalForwardPromptEnvelope(body: unknown): unknown {
const next: Record<string, unknown> = { ...body };
if (stripTruncation) delete next.truncation;
if (sawSystemMessage && canFoldAllSystemMessages) {
next.input = input.filter(item => !isPlainObject(item) || item.role !== "system");
next.input = input.filter(item => !isCanonicalForwardSystemMessage(item));
const folded = foldedText.join("\n\n");
if (folded !== "") {
const existing = typeof body.instructions === "string" ? body.instructions : "";
Expand Down
19 changes: 19 additions & 0 deletions tests/responses-forward-prompt-envelope.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,25 @@ describe("canonical ChatGPT forward prompt envelope", () => {
expect(body.input).toEqual(input);
});

test("does not promote a non-message item with a system role", () => {
const externalAgentMessage = {
type: "agent_message",
role: "system",
content: [{ type: "input_text", text: "external agent content" }],
};
const body = outboundBody(canonicalForward, {
model: "gpt-5.6-luna",
instructions: "Existing instructions",
input: [
{ type: "message", role: "system", content: "Trusted system instruction" },
externalAgentMessage,
],
});

expect(body.instructions).toBe("Existing instructions\n\nTrusted system instruction");
expect(body.input).toEqual([externalAgentMessage]);
});

test.each([
{
name: "key-auth public Responses provider",
Expand Down
Loading