From de1b4101a6a7f1e1396e6d4aeb0ef2c5927aad11 Mon Sep 17 00:00:00 2001 From: Chris Caldwell <2266680+chris-cald@users.noreply.github.com> Date: Sun, 12 Jul 2026 14:38:31 -0400 Subject: [PATCH] fix(llm): satisfy lowercase json_object prompt checks (#887) * fix(llm): satisfy lowercase json_object prompt checks * style(llm): preserve JSON acronym in prompt --- src/llm/backends/openai.py | 9 +++++---- tests/llm/test_backends/test_openai.py | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/llm/backends/openai.py b/src/llm/backends/openai.py index 92f13385..8c0ca8a4 100644 --- a/src/llm/backends/openai.py +++ b/src/llm/backends/openai.py @@ -30,11 +30,12 @@ def _json_object_instruction(response_format: type[BaseModel]) -> str: instruction — the deriver issues one structured call per batch on the worker hot path and would otherwise re-walk the schema + re-serialize it every call. """ - # "JSON" must appear in the messages to satisfy the json_object contract. + # Some OpenAI-compatible providers enforce this JSON-object precondition with + # a case-sensitive substring check, so include lowercase "json" explicitly. return ( - "You must respond with a single JSON object that conforms exactly to " - "the following JSON schema. Do not include any text, markdown, or code " - "fences outside the JSON object.\n\nJSON schema:\n" + "You must respond with a single JSON object (json) that conforms " + "exactly to the following JSON schema. Do not include any text, " + "markdown, or code fences outside the JSON object.\n\nJSON schema:\n" f"{json.dumps(response_format.model_json_schema())}" ) diff --git a/tests/llm/test_backends/test_openai.py b/tests/llm/test_backends/test_openai.py index 4270ebd8..0ff6988f 100644 --- a/tests/llm/test_backends/test_openai.py +++ b/tests/llm/test_backends/test_openai.py @@ -808,6 +808,7 @@ async def test_structured_output_json_object_mode_request_shape() -> None: assert system_messages, "expected a system message carrying the schema" system_content = system_messages[0]["content"] assert "JSON" in system_content + assert "json" in system_content assert "answer" in system_content # schema property serialized in assert isinstance(result.content, _StructuredResponse) assert result.content.answer == "ok" @@ -943,4 +944,6 @@ async def test_stream_structured_output_json_object_mode() -> None: call = _await_kwargs(client.chat.completions.create) assert call["response_format"] == {"type": "json_object"} system_messages = [m for m in call["messages"] if m["role"] == "system"] - assert system_messages and "JSON" in system_messages[0]["content"] + assert system_messages + assert "JSON" in system_messages[0]["content"] + assert "json" in system_messages[0]["content"]