From 583ab57a5929cdda6642d8d0eda2d53e6d1ecaeb Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 2 Jun 2026 14:18:33 +0200 Subject: [PATCH] Set response_format json_schema strict=False in OpenRouter adapter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous strict=True default rejected the activity-core daily-triage schema (and most real-world application schemas) because OpenAI strict mode requires additionalProperties:false on every object and every property in the required list. Application-supplied schemas typically do not meet that bar — adding additionalProperties recursively at the adapter would be surprising and may break callers that rely on extra fields. Flipping strict to False keeps the schema as a soft constraint; the model still produces structured output and the activity-core canary's 400 from OpenRouter goes away. Callers who need strict enforcement can pass response_format directly via model_params, where the adapter's pass-through handling preserves the strict flag they set. Co-Authored-By: Claude Opus 4.7 --- llm_connect/openrouter.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/llm_connect/openrouter.py b/llm_connect/openrouter.py index 46d9aef..9a7c283 100644 --- a/llm_connect/openrouter.py +++ b/llm_connect/openrouter.py @@ -181,12 +181,20 @@ def _merge_model_params(payload: Dict[str, Any], model_params: Dict[str, Any]) - except (ValueError, TypeError): schema = None if isinstance(schema, dict): + # strict=False: OpenAI's strict mode requires additionalProperties + # to be false on every object and every property in the required + # list. Most application-supplied schemas are not written that + # way (the activity-core daily-triage schema, for example, has + # neither). With strict=False, OpenRouter still honours the + # schema as a soft constraint and the model's output remains + # structured. Callers can opt back into strict by including + # `strict: true` themselves in a custom `response_format`. payload["response_format"] = { "type": "json_schema", "json_schema": { "name": "structured_output", "schema": schema, - "strict": True, + "strict": False, }, }