mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-22 15:25:09 +00:00
fix: harden Responses API tool call conversion
This commit is contained in:
@@ -683,14 +683,17 @@ class OpenAICompletion(BaseLLM):
|
||||
|
||||
if role == "assistant" and message.get("tool_calls"):
|
||||
items: list[dict[str, Any] | LLMMessage] = []
|
||||
if message.get("content"):
|
||||
items.append({"role": "assistant", "content": message["content"]})
|
||||
for tool_call in message["tool_calls"]:
|
||||
function = tool_call.get("function", {})
|
||||
args = function.get("arguments", "")
|
||||
items.append(
|
||||
{
|
||||
"type": "function_call",
|
||||
"call_id": tool_call.get("id", ""),
|
||||
"call_id": tool_call.get("id") or f"call_{id(tool_call)}",
|
||||
"name": function.get("name", ""),
|
||||
"arguments": function.get("arguments", ""),
|
||||
"arguments": args if isinstance(args, str) else json.dumps(args),
|
||||
}
|
||||
)
|
||||
return items
|
||||
|
||||
@@ -1277,7 +1277,9 @@ def is_tool_call_list(response: list[Any]) -> bool:
|
||||
# Bedrock-style
|
||||
if isinstance(first_item, dict) and "name" in first_item and "input" in first_item:
|
||||
return True
|
||||
# OpenAI Responses API-style (flat dict, no nested "function" key)
|
||||
# OpenAI Responses API-style (flat dict, no nested "function" key). This
|
||||
# intentionally accepts the same broad shape as the Bedrock check above;
|
||||
# only provider paths that return lists reach this classifier.
|
||||
if (
|
||||
isinstance(first_item, dict)
|
||||
and "name" in first_item
|
||||
|
||||
@@ -1006,6 +1006,37 @@ def test_openai_responses_api_converts_assistant_tool_calls_message():
|
||||
}
|
||||
|
||||
|
||||
def test_openai_responses_api_preserves_assistant_content_with_tool_calls():
|
||||
"""Assistant text must be retained when it accompanies tool calls."""
|
||||
llm = OpenAICompletion(model="gpt-4o-mini", api="responses")
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "I'll fetch that page now.",
|
||||
"tool_calls": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "fetch_page",
|
||||
"arguments": {"url": "https://example.com"},
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
params = llm._prepare_responses_params(messages)
|
||||
|
||||
assert params["input"][0] == {
|
||||
"role": "assistant",
|
||||
"content": "I'll fetch that page now.",
|
||||
}
|
||||
assert params["input"][1]["type"] == "function_call"
|
||||
assert params["input"][1]["call_id"].startswith("call_")
|
||||
assert params["input"][1]["arguments"] == '{"url": "https://example.com"}'
|
||||
|
||||
|
||||
def test_openai_responses_api_converts_tool_result_message():
|
||||
"""Regression: tool-role messages (Chat-Completions shape) must become
|
||||
function_call_output input items for the Responses API.
|
||||
|
||||
Reference in New Issue
Block a user