Skip to content

fix(livekit): use asyncio.to_thread so status-update task actually runs#32

Open
devteamaegis wants to merge 1 commit into
agentmail-to:mainfrom
devteamaegis:fix/livekit-status-update-blocks-event-loop
Open

fix(livekit): use asyncio.to_thread so status-update task actually runs#32
devteamaegis wants to merge 1 commit into
agentmail-to:mainfrom
devteamaegis:fix/livekit-status-update-blocks-event-loop

Conversation

@devteamaegis

@devteamaegis devteamaegis commented May 26, 2026

Copy link
Copy Markdown

Problem

The LiveKit tool handler is intended to display a status message to the user
while the underlying AgentMail API call is in flight:

status_update_task = asyncio.create_task(_status_update())

result = tool.func(self.client, raw_arguments).model_dump_json()  # sync HTTP

status_update_task.cancel()

tool.func calls the synchronous AgentMail client, which uses httpx.Client
and blocks the calling thread. In an async context that means the event
loop is blocked
for the entire duration of the HTTP request. Because the
event loop cannot run other tasks while it is blocked, _status_update is
never scheduled. When tool.func finally returns, the very next line cancels
the task — so generate_reply is never called and the user never sees the
status update.

Fix

Off-load tool.func to a thread pool with asyncio.to_thread. The event
loop stays free while the HTTP call runs in a worker thread, giving
_status_update the time slice it needs to run:

# before
result = tool.func(self.client, raw_arguments).model_dump_json()

# after
result = await asyncio.to_thread(
    lambda: tool.func(self.client, raw_arguments).model_dump_json()
)

Tests

python/tests/test_livekit_status_update.py (both pass):

  • test_status_update_fires_during_blocking_tool — a slow sync tool is used; after releasing the gate the test verifies generate_reply was called
  • test_tool_result_returned_correctly — the JSON result is still returned correctly after the change

Summary by cubic

Run the synchronous AgentMail HTTP call in a thread so the LiveKit tool handler doesn’t block the event loop. This lets the status-update task run and show progress while the tool executes.

  • Bug Fixes
    • Use asyncio.to_thread for tool.func(...).model_dump_json() so _status_update can execute and call generate_reply.
    • Add tests to verify the status update fires during a slow sync tool and the JSON result is returned unchanged.

Written for commit 0387c08. Summary will update on new commits.

Review in cubic

…execute

The LiveKit tool handler creates a _status_update task to notify the user
while a tool is executing, then immediately calls tool.func() synchronously.
Because tool.func() is a blocking HTTP call (using the sync AgentMail client),
it never yields to the event loop — so the _status_update task is never
scheduled.  By the time tool.func() returns, the task is cancelled before it
runs even once.  The status update therefore silently never fires.

Fix: off-load tool.func() to a thread via asyncio.to_thread().  This yields
the event loop back to other tasks while the HTTP call runs in a worker
thread, giving _status_update the opportunity to execute as intended.

Adds python/tests/test_livekit_status_update.py with two test cases:
- status update fires during a deliberately slow synchronous tool
- tool result JSON is returned correctly after the fix

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Re-trigger cubic

@devteamaegis devteamaegis force-pushed the fix/livekit-status-update-blocks-event-loop branch from 318509e to 0387c08 Compare June 11, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant