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
Copy link
Copy Markdown

@devteamaegis devteamaegis commented May 26, 2026

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

Prevents the LiveKit tool handler from blocking the event loop by running the synchronous AgentMail HTTP call in a thread. This allows the status-update task to run so users see progress while the tool executes.

  • Bug Fixes
    • Off-load tool.func(...).model_dump_json() via asyncio.to_thread so _status_update can run and call generate_reply.
    • Add tests to confirm the status update fires during a slow sync tool and the JSON result is still returned correctly.

Written for commit 318509e. 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
Copy link
Copy Markdown

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

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

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