Skip to content

DatabaseConversationStore loses reasoningId/reasoningSummary when rehydrating ToolCall from DB #361

@nikitaku11

Description

@nikitaku11

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions