From e4f3147688e375359f40f8152e6e8f355c6a5459 Mon Sep 17 00:00:00 2001 From: Sawyer Date: Tue, 3 Nov 2026 20:03:22 -0800 Subject: [PATCH] fix: reject unknown keys in nested quirk objects --- src/responses.test.ts | 17 +++++++++++++++++ src/responses.ts | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/responses.test.ts b/src/responses.test.ts index 52f90ca..23a61af 100644 --- a/src/responses.test.ts +++ b/src/responses.test.ts @@ -101,6 +101,23 @@ describe("Responses adapter — block-index lifecycle", () => { }), ).toThrow(); }); + + test.each([ + ["headers", { headers: { statc: {} } }], + [ + "headers.fromOption", + { + headers: { fromOption: [{ optionKey: "a", header: "x-a", hedr: "" }] }, + }, + ], + [ + "systemPrompt", + { systemPrompt: { role: "system", shape: "string", rol: "system" } }, + ], + ["reasoning", { reasoning: { sumary: "auto" } }], + ])("rejects an unrecognized %s field instead of ignoring it", (_, quirks) => { + expect(() => createOpenAIResponsesAdapter(source, quirks)).toThrow(); + }); }); describe("Responses request builder — quirk matrix", () => { diff --git a/src/responses.ts b/src/responses.ts index 60e8457..6c35d0e 100644 --- a/src/responses.ts +++ b/src/responses.ts @@ -31,6 +31,7 @@ import { const HeaderFromOption = type({ optionKey: "string", header: "string", + "+": "reject", }); type HeaderFromOption = typeof HeaderFromOption.infer; @@ -38,6 +39,7 @@ const ResponsesHeaders = type({ "static?": { "[string]": "string" }, "modelHeader?": "string", "fromOption?": HeaderFromOption.array(), + "+": "reject", }); // `shape: "string"` sends plain string content (Grok/OpenAI); `"parts"` @@ -46,6 +48,7 @@ const ResponsesHeaders = type({ const SystemPromptPlacement = type({ role: "'system' | 'developer'", shape: "'string' | 'parts'", + "+": "reject", }); type SystemPromptPlacement = typeof SystemPromptPlacement.infer; @@ -55,6 +58,7 @@ const ReasoningQuirks = type({ // The wire value Interchange's neutral `max` effort becomes. The highest // level differs per model, so only the source can name it. "maxEffort?": "'xhigh' | 'max'", + "+": "reject", }); type ReasoningQuirks = typeof ReasoningQuirks.infer;