Feature Type
Would make my life easier
Feature Description
When an LLM returns multiple tool calls, LiveKit currently starts each call as a separate asyncio task and waits for them together:
|
task = asyncio.create_task( |
|
_traceable_fnc_tool(function_callable, fnc_call), |
|
name=f"func_exec_{fnc_call.name}", # task name is used for logging when the task is cancelled |
|
) |
|
_set_activity_task_info( |
|
task, speech_handle=speech_handle, function_call=fnc_call, inline_task=True |
|
) |
|
tasks.append(task) |
|
task.add_done_callback(lambda task: tasks.remove(task)) |
|
except Exception as e: |
|
# catching exceptions here because even though the function is asynchronous, |
|
# errors such as missing or incompatible arguments can still occur at |
|
# invocation time. |
|
logger.exception( |
|
"exception occurred while executing tool", |
|
extra={ |
|
"function": fnc_call.name, |
|
"speech_id": speech_handle.id, |
|
}, |
|
) |
|
_tool_completed(make_tool_output(fnc_call=fnc_call, output=None, exception=e)) |
|
continue |
|
|
|
await asyncio.shield(asyncio.gather(*tasks, return_exceptions=True)) |
This works for independent tools, but in many real life workloads tools depend on others, due to shared dependencies.
For example, in a hotel booking flow, the LLM may return save_room_preference and save_meal_preference together. However, the runtime must execute save_room_preference first because the available meal options may depend on the selected room package.
It would be helpful to support an optional execution policy such as:
parallel: current behavior.
Custom dependency ordering: run independent calls in parallel while waiting for prerequisites.
The model should still be able to return multiple calls in one response. The ordering should happen locally during tool execution. Existing parallel behavior should remain the default.
Workarounds / Alternatives
- Setting parallel_tool_calls=False forces separate model turns between tools
- Applications can also build a wrapper tool or coordinate with locks, but this requires custom orchestration and does not have a clean view of all calls in the current batch.
- TaskGroup supports ordered conversational tasks, but not ordering ordinary tool calls returned together.
Additional Context
A related request exists for conditional TaskGroup workflows: #5697
This request is specifically about execution ordering for function tool calls within the same model turn.
Feature Type
Would make my life easier
Feature Description
When an LLM returns multiple tool calls, LiveKit currently starts each call as a separate asyncio task and waits for them together:
agents/livekit-agents/livekit/agents/voice/generation.py
Lines 842 to 865 in 03ab627
This works for independent tools, but in many real life workloads tools depend on others, due to shared dependencies.
For example, in a hotel booking flow, the LLM may return
save_room_preferenceandsave_meal_preferencetogether. However, the runtime must executesave_room_preferencefirst because the available meal options may depend on the selected room package.It would be helpful to support an optional execution policy such as:
parallel: current behavior.Custom dependency ordering: run independent calls in parallel while waiting for prerequisites.The model should still be able to return multiple calls in one response. The ordering should happen locally during tool execution. Existing parallel behavior should remain the default.
Workarounds / Alternatives
Additional Context
A related request exists for conditional TaskGroup workflows: #5697
This request is specifically about execution ordering for function tool calls within the same model turn.