fix: prevent KeyError in _FunctionToolBatchExecutor under eager_task_factory#2733
Closed
guoyangzhen wants to merge 1 commit into
Closed
fix: prevent KeyError in _FunctionToolBatchExecutor under eager_task_factory#2733guoyangzhen wants to merge 1 commit into
guoyangzhen wants to merge 1 commit into
Conversation
…factory (openai#2729) Under asyncio.eager_task_factory (used by Textual on Python 3.12+), create_task() starts executing the coroutine before returning. This creates a race where the task can complete and be processed by _partition_pending_tasks before self.task_states[task] is registered, causing KeyError. Fix: wrap _run_single_tool in an inner async function so eager execution runs the empty synchronous preamble and yields at the first await, returning control to _create_tool_task to finish registration. The wrapper approach is preferred over registering before create_task because we need the task object as the dict key.
Member
|
@guoyangzhen thanks for sharing this. I believe my PR #2731 should already resolve the issue, but do you still see some patterns that are not covered by my change? If so, can you add unit tests covering the patterns as well? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
After upgrading from
openai-agents==0.9.3to0.12.5, streamed runs with parallel tool calls fail with:This only reproduces under
asyncio.eager_task_factory(used by Textual TUI framework on Python 3.12+).Root Cause
In
_FunctionToolBatchExecutor._create_tool_task():Under
eager_task_factory,create_task()starts executing the coroutine immediately before returning. The task can complete and be processed by_partition_pending_tasks→self.task_states[task]beforeself.task_states[task] = task_stateexecutes, causingKeyError.The issue reporter confirmed this with a minimal reproduction showing the scheduling problem on Python 3.13.
Fix
Wrap
_run_single_toolin an innerasync defso thateager_task_factoryruns the wrapper's synchronous preamble (which is empty) and yields at the firstawait, returning control to_create_tool_taskto finishtask_statesregistration.This is preferred over "register before create_task" because the task object (needed as the dict key) is only available from
create_task()'s return value.Testing
The fix ensures that when
eager_task_factoryeagerly executes the wrapper:await self._run_single_tool(...)and suspends_create_tool_taskself.task_states[task] = task_stateexecutes — state is now registered_run_single_toolruns safely