Skip to content

Commit fbd5a23

Browse files
authored
fix(core): revert "fix: tool call streaming bug with inconsistent indices from Qwen3" (#32307)
Reverts #32160 Original issue stems from using `ChatOpenAI` to interact with a `qwen` model. Recommended to use [langchain-qwq](https://python.langchain.com/docs/integrations/chat/qwq/) which is built for Qwen
1 parent fc2f66c commit fbd5a23

File tree

2 files changed

+0
-95
lines changed

2 files changed

+0
-95
lines changed

libs/core/langchain_core/utils/_merge.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -108,39 +108,6 @@ def merge_lists(left: Optional[list], *others: Optional[list]) -> Optional[list]
108108
else e
109109
)
110110
merged[to_merge[0]] = merge_dicts(merged[to_merge[0]], new_e)
111-
# Special handling for tool call chunks: if this chunk appears to be
112-
# a continuation of a prior chunk (has None name/id) and no matching
113-
# index was found, try to merge with the most recent tool call chunk
114-
# that has a name/id.
115-
# Fixes issues with models that send inconsistent indices.
116-
# See #31511 for more.
117-
elif (
118-
e.get("type") == "tool_call_chunk"
119-
and e.get("name") is None
120-
and e.get("id") is None
121-
and merged
122-
):
123-
# Find the most recent tool call chunk with a valid name or id
124-
for i in reversed(range(len(merged))):
125-
if (
126-
isinstance(merged[i], dict)
127-
and merged[i].get("type") == "tool_call_chunk"
128-
and (
129-
merged[i].get("name") is not None
130-
or merged[i].get("id") is not None
131-
)
132-
):
133-
# Merge with this chunk
134-
new_e = (
135-
{k: v for k, v in e.items() if k != "type"}
136-
if "type" in e
137-
else e
138-
)
139-
merged[i] = merge_dicts(merged[i], new_e)
140-
break
141-
else:
142-
# No suitable chunk found, append as new
143-
merged.append(e)
144111
else:
145112
merged.append(e)
146113
else:

libs/core/tests/unit_tests/test_messages.py

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,65 +1197,3 @@ def test_convert_to_openai_image_block() -> None:
11971197
}
11981198
result = convert_to_openai_image_block(input_block)
11991199
assert result == expected
1200-
1201-
1202-
def test_tool_call_streaming_different_indices() -> None:
1203-
"""Test that tool call chunks with different indices but logically part of the same
1204-
tool call are merged correctly. This addresses issues with models like Qwen3 that
1205-
send inconsistent indices during streaming.
1206-
1207-
See #31511.
1208-
1209-
""" # noqa: D205
1210-
# Create chunks that simulate Qwen3 behavior:
1211-
# First chunk has index=1, subsequent chunks have index=0 with name=None, id=None
1212-
chunk1 = AIMessageChunk(
1213-
content="",
1214-
tool_call_chunks=[
1215-
create_tool_call_chunk(
1216-
name="search_function",
1217-
args='{"query": "langchain',
1218-
id="call_123",
1219-
index=1, # Initial index
1220-
)
1221-
],
1222-
)
1223-
1224-
chunk2 = AIMessageChunk(
1225-
content="",
1226-
tool_call_chunks=[
1227-
create_tool_call_chunk(
1228-
name=None, # Continuation chunk
1229-
args=' tutorial"}',
1230-
id=None, # Continuation chunk
1231-
index=0, # Different index
1232-
)
1233-
],
1234-
)
1235-
1236-
# Merge chunks as happens during streaming
1237-
merged_chunk: AIMessageChunk = chunk1 + chunk2 # type: ignore[assignment]
1238-
1239-
# Should result in a single merged tool call chunk
1240-
assert len(merged_chunk.tool_call_chunks) == 1
1241-
assert merged_chunk.tool_call_chunks[0]["name"] == "search_function"
1242-
assert merged_chunk.tool_call_chunks[0]["args"] == '{"query": "langchain tutorial"}'
1243-
assert merged_chunk.tool_call_chunks[0]["id"] == "call_123"
1244-
1245-
# Should result in a single valid tool call
1246-
assert len(merged_chunk.tool_calls) == 1
1247-
assert len(merged_chunk.invalid_tool_calls) == 0
1248-
1249-
# Verify the final tool call is correct
1250-
tool_call = merged_chunk.tool_calls[0]
1251-
assert tool_call["name"] == "search_function"
1252-
assert tool_call["args"] == {"query": "langchain tutorial"}
1253-
assert tool_call["id"] == "call_123"
1254-
1255-
# Test with message_chunk_to_message
1256-
message: AIMessage = message_chunk_to_message(merged_chunk) # type: ignore[assignment]
1257-
1258-
assert len(message.tool_calls) == 1
1259-
assert len(message.invalid_tool_calls) == 0
1260-
assert message.tool_calls[0]["name"] == "search_function"
1261-
assert message.tool_calls[0]["args"] == {"query": "langchain tutorial"}

0 commit comments

Comments
 (0)