Bug: reasoning parameter causes tool_call chain error in DeepAgents subagent
Environment
| Package | Version |
|---|---|
| deepagents | 0.4.11 |
| langchain | 1.2.12 |
| langchain-openai | 1.1.11 |
| langgraph | 1.1.3 |
| Python | 3.12+ |
| LLM Provider | Alibaba DashScope (OpenAI-compatible) |
| Model | qwen3.5-122b-a10b |
Description
When using ChatOpenAI with the reasoning parameter and create_deep_agent with subagents, the main agent works correctly (delegates task to subagent), but the subagent crashes during its internal tool call chain.
The reasoning parameter triggers the Responses API code path (_construct_lc_result_from_responses_api), which formats messages differently. When the subagent inherits this model and performs multi-step tool calling, the tool_call → tool_response message pairing breaks, and the LLM API rejects the request.
Reproduction Code
from langchain_openai import ChatOpenAI
from deepagents import create_deep_agent
# Tool functions (simplified)
async def query_kyc(company_name: str) -> str:
"""查询企业基本工商信息"""
return "企业名称:xxx有限公司\n法人:张三\n..."
async def query_field(company_name: str, query: str) -> str:
"""根据用户意图查询企业详细字段"""
return "纳税信用等级:A"
model = ChatOpenAI(
model="qwen3.5-122b-a10b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key="sk-xxx",
timeout=60,
reasoning={ # ← This causes the issue
"effort": "medium",
"summary": "auto"
}
)
subagent = {
"name": "Business_agent",
"description": "Query company information.",
"system_prompt": "You are a business info assistant. Use tools to query data.",
"tools": [query_kyc, query_field],
}
agent = create_deep_agent(
model=model,
system_prompt="You are an enterprise info expert.",
subagents=[subagent]
)
import asyncio
async def main():
async for chunk in agent.astream({"messages": [
{"role": "user", "content": "查询xxx有限公司的基本信息,纳税等级,开户行,画像和标签"}
]}):
print(chunk)
asyncio.run(main())
Actual Behavior
The main agent successfully delegates to the subagent via the task tool. Then the subagent crashes when it tries to call its own tools:
ValueError: ResponseError(code='server_error', message='<400> InternalError.Algo.InvalidParameter:
An assistant message with "tool_calls" must be followed by tool messages responding to each "tool_call_id".
The following tool_call_ids did not have response messages: message[4].role')
Full Stack Trace
Traceback (most recent call last):
File "core/main_agent.py", line 63, in <module>
asyncio.run(t1.quick_start(messages))
File "core/main_agent.py", line 45, in quick_start
async for chunk in agent.astream({"messages": messages}):
File "langgraph/pregel/main.py", line 3111, in astream
async for _ in runner.atick(
File "langgraph/pregel/_runner.py", line 304, in atick
await arun_with_retry(
File "langgraph/pregel/_retry.py", line 211, in arun_with_retry
return await task.proc.ainvoke(task.input, config)
# --- Main agent's tools node spawns the subagent ---
File "langgraph/prebuilt/tool_node.py", line 846, in _afunc
outputs = await asyncio.gather(*coros)
File "langgraph/prebuilt/tool_node.py", line 1191, in _arun_one
return await self._awrap_tool_call(tool_request, execute)
File "deepagents/middleware/subagents.py", line 463, in atask
result = await subagent.ainvoke(subagent_state)
# --- Inside subagent: model node tries to call LLM ---
File "langgraph/pregel/main.py", line 3462, in ainvoke
async for chunk in self.astream(
File "langgraph/pregel/main.py", line 3111, in astream
async for _ in runner.atick(
File "langchain/agents/factory.py", line 1352, in amodel_node
result = await awrap_model_call_handler(request, _execute_model_async)
# --- Through middleware chain ---
File "langchain/agents/middleware/todo.py", line 253, in awrap_model_call
File "deepagents/middleware/filesystem.py", line 1126, in awrap_model_call
File "deepagents/middleware/summarization.py", line 1024, in awrap_model_call
# --- LLM call crashes here ---
File "langchain/agents/factory.py", line 1321, in _execute_model_async
output = await model_.ainvoke(messages)
File "langchain_openai/chat_models/base.py", line 1744, in _agenerate
return _construct_lc_result_from_responses_api(
File "langchain_openai/chat_models/base.py", line 4423, in _construct_lc_result_from_responses_api
raise ValueError(response.error)
ValueError: ResponseError(code='server_error', message='<400> InternalError.Algo.InvalidParameter:
An assistant message with "tool_calls" must be followed by tool messages responding to each "tool_call_id".
The following tool_call_ids did not have response messages: message[4].role')
During task with name 'model' and id '0f42eef9-ac9e-b585-321b-e9a3f65283f8'
During task with name 'tools' and id 'cb8ef8e4-8e89-0d95-ac39-68555be375f7'
Expected Behavior
The reasoning parameter should work with subagents that perform multi-step tool calling, or the subagent should be able to override the model to avoid inheriting the Responses API code path.
Workaround
Use separate model instances — subagent config supports a model field to override the main agent’s model:
model_with_reasoning = ChatOpenAI(..., reasoning={"effort": "medium", "summary": "auto"})
model_basic = ChatOpenAI(...) # no reasoning
agent = create_deep_agent(
model=model_with_reasoning, # main agent: reasoning ON
subagents=[{
"name": "Business_agent",
"model": model_basic, # subagent: reasoning OFF ← fixes the issue
"tools": [query_kyc, query_field],
...
}]
)
Analysis
Root Cause
The issue is primarily in DashScope’s Responses API compatibility layer, not in langchain-openai or DeepAgents.
How it happens
-
The
reasoningparameter causeslangchain-openaito switch from the Chat Completions API path to the Responses API path (see_use_responses_apiatbase.py:1512:if self.reasoning is not None: return True). -
langchain-openaiconstructs the request using Responses API format — messages become a flatinputarray with typed blocks (reasoning,function_call,function_call_output, etc.) via_construct_responses_api_inputatbase.py:4225. -
DashScope’s OpenAI-compatible endpoint receives this Responses API format and internally converts it back to Chat Completions format for processing. Evidence: the error message uses Chat Completions terminology (“assistant message with tool_calls”) rather than Responses API terminology (“function_call” / “function_call_output”).
-
During this internal conversion, when multiple tool-calling rounds are flattened into the
inputarray (with interleavedreasoning,function_call, andfunction_call_outputblocks), DashScope’s conversion logic loses the tool_call → tool_response pairing, causing the validation to fail atmessage[4]. -
The main agent is unaffected because it only makes a single tool call (the
tasktool), so there’s no multi-round accumulation. The subagent crashes because it performs multi-step tool calling internally.
Summary
- Qwen model: Not involved — the request never reaches the model.
- DashScope compatibility layer: Primary issue — its Responses API → Chat Completions internal conversion breaks multi-round tool calling message pairing.
- langchain-openai: No bug — the Responses API format it generates is likely valid for OpenAI’s native API, but DashScope’s compatibility layer cannot handle it correctly.
- DeepAgents: No bug — it simply passes messages through; it is not responsible for API format conversion.