From 5f8ed7bb4e213313137b3db2258b6520cda0d518 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Tue, 12 May 2026 15:19:58 -0700 Subject: [PATCH] fix(examples-chat): disable strict mode on render_a2ui_surface OpenAI strict tool binding requires every nested object schema in the parameters tree to declare additionalProperties: false. Our envelope shape carries list[dict] for components/contents (untyped inner objects), which strict mode rejects with a 400: 'additionalProperties' is required to be supplied and to be false Typing the inner shapes would over-couple the example graph to the A2UI v1 spec internals. The envelope-args normalizer (Python + TS parity) was already designed as the safety net for non-canonical shapes, so we lean on it and disable strict mode. Live smoke against the demo confirms the parent LLM still produces canonical envelopes the vast majority of the time (per the spike: 80-93%% canonical without strict). --- examples/chat/python/src/graph.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/chat/python/src/graph.py b/examples/chat/python/src/graph.py index 78b6330c6..699509bac 100644 --- a/examples/chat/python/src/graph.py +++ b/examples/chat/python/src/graph.py @@ -394,12 +394,19 @@ async def generate(state: State, config: RunnableConfig) -> dict: render_a2ui_surface if gen_ui_mode == "a2ui" else generate_json_render_spec ) - # Strict mode is enabled for the envelope-emission tool so OpenAI enforces - # the canonical {envelopes: [...]} argument shape; the JS bridge and Python - # normalizer treat the non-canonical shapes as safety nets. + # Note on strict mode: OpenAI strict tool binding requires every nested + # object schema in the parameters tree to declare additionalProperties: + # false. The envelope shape carries list[dict] for components/contents + # (untyped inner objects), which strict mode rejects with a 400 + # ('additionalProperties is required to be supplied and to be false'). + # Typing the inner shapes would over-couple this example to the A2UI v1 + # spec; instead we leave strict OFF and rely on the envelope-args + # normalizer (Python: src/streaming/envelope_normalizer.py; TS: + # libs/chat/src/lib/a2ui/envelope-normalizer.ts) to canonicalize the + # four observed argument shapes (envelopes / envelope / positional / + # flat). The spike showed 80-93% canonical even without strict. llm = ChatOpenAI(**kwargs).bind_tools( [search_documents, request_approval, research, gen_ui_tool], - strict=True if gen_ui_mode == "a2ui" else False, ) # Append A2UI v1 schema to system prompt when in a2ui mode, so the parent # LLM knows how to construct the envelopes directly.