Bug
When replaying conversation history that includes tool calls from a reasoning model, the OpenAI Responses API returns HTTP 400:
Item 'fc_xxx' of type 'function_call' was provided without its required 'reasoning' item: 'rs_xxx'.
Root Cause
DatabaseConversationStore::getLatestConversationMessages() reconstructs ToolCall objects from the database but omits the reasoningId and reasoningSummary fields:
// Current (broken)
new ToolCall(
id: $toolCall['id'],
name: $toolCall['name'],
arguments: $toolCall['arguments'],
resultId: $toolCall['result_id'] ?? null,
// reasoningId and reasoningSummary are NOT restored
)
Both fields ARE serialized correctly via ToolCall::toArray() (which includes reasoning_id and reasoning_summary), so they exist in the database. They're just not read back.
As a result, every rehydrated ToolCall has reasoningId = null. Then in OpenAi/Concerns/MapsMessages.php, mapAssistantMessage() filters with ->whereNotNull('reasoningId'), so no reasoning items are emitted. The subsequent request then includes function_call items that reference reasoning items the API expects to be present, causing the 400.
Fix
Pass the stored fields when reconstructing ToolCall objects:
new ToolCall(
id: $toolCall['id'],
name: $toolCall['name'],
arguments: $toolCall['arguments'],
resultId: $toolCall['result_id'] ?? null,
reasoningId: $toolCall['reasoning_id'] ?? null,
reasoningSummary: $toolCall['reasoning_summary'] ?? null,
)
Steps to Reproduce
Use an agent with 'reasoning' => ['effort' => 'low', 'summary' => 'auto'] provider options
Complete a conversation turn where the model uses a tool
Send a follow-up message in the same conversation
Observe HTTP 400 from the OpenAI Responses API
Environment
Laravel AI package (laravel/ai)
OpenAI provider with reasoning models or models with reasoning enabled
Bug
When replaying conversation history that includes tool calls from a reasoning model, the OpenAI Responses API returns HTTP 400:
Root Cause
DatabaseConversationStore::getLatestConversationMessages()reconstructsToolCallobjects from the database but omits thereasoningIdandreasoningSummaryfields:Both fields ARE serialized correctly via ToolCall::toArray() (which includes reasoning_id and reasoning_summary), so they exist in the database. They're just not read back.
As a result, every rehydrated ToolCall has reasoningId = null. Then in OpenAi/Concerns/MapsMessages.php, mapAssistantMessage() filters with ->whereNotNull('reasoningId'), so no reasoning items are emitted. The subsequent request then includes function_call items that reference reasoning items the API expects to be present, causing the 400.
Fix
Pass the stored fields when reconstructing ToolCall objects:
Steps to Reproduce
Use an agent with 'reasoning' => ['effort' => 'low', 'summary' => 'auto'] provider options
Complete a conversation turn where the model uses a tool
Send a follow-up message in the same conversation
Observe HTTP 400 from the OpenAI Responses API
Environment
Laravel AI package (laravel/ai)
OpenAI provider with reasoning models or models with reasoning enabled