Fix: Preserve OpenAI item ID on FunctionCall in Realtime sessions#4876
Conversation
There was a problem hiding this comment.
Devin Review found 1 potential issue.
🐛 1 issue in files not directly in the diff
🐛 Same missing id=item_id bug exists in realtime_model_beta.py but was not fixed (livekit-plugins/livekit-plugins-openai/livekit/plugins/openai/realtime/realtime_model_beta.py:1412-1416)
The PR fixes the missing id=item_id in realtime_model.py but the identical bug exists in realtime_model_beta.py. The FunctionCall constructor at this location does not pass id=item_id, so it generates a new local UUID instead of preserving the OpenAI-assigned item ID.
Root Cause
realtime_model_beta.py:1412 creates a FunctionCall without passing the id parameter, just like the original bug in realtime_model.py that this PR fixes. The item_id is already extracted at realtime_model_beta.py:1402 via assert (item_id := event.item.id) is not None but is never passed to the FunctionCall constructor.
This causes the same ID mismatch between agent._chat_ctx and _remote_chat_ctx described in the PR description, leading to previous_item_id not found errors when update_chat_ctx is called during active tool execution.
Impact: The same delete+recreate diffs and previous_item_id not found errors will occur for users of the beta realtime model.
View 2 additional findings in Devin Review.
Problem
In
_handle_response_output_item_done, theFunctionCallemitted throughfunction_chdoes not preserve the OpenAI-assigned item ID. It creates a new local UUID instead:This means
agent._chat_ctxand_remote_chat_ctxend up with different IDs for the same function_call item. Every other item type (assistant messages, user messages) correctly preserves the OpenAI ID, this is the only one that doesn't.This causes
update_chat_ctx(agent.chat_ctx)to produce delete+recreate diffs for function_call items, sincecompute_chat_ctx_diffmatches by ID. In our case, this leads toprevious_item_id not founderrors whenupdate_chat_ctxis called during active tool execution even if you are supposed to only change items furthest back in the context (we call it as part of a context summarization strategy).Fix
Pass
id=item_idto theFunctionCallconstructor.