Merge pull request #4224 from pipecat-ai/aleix/optional-function-call-timeout

Make function_call_timeout_secs optional
This commit is contained in:
Aleix Conchillo Flaqué
2026-04-01 14:39:10 -07:00
committed by GitHub
2 changed files with 12 additions and 13 deletions

View File

@@ -0,0 +1 @@
- ⚠️ `LLMService.function_call_timeout_secs` now defaults to `None` instead of `10.0`. Deferred function calls will run indefinitely unless a timeout is explicitly set at the service level or per-call. If you relied on the previous 10-second default, pass `function_call_timeout_secs=10.0` explicitly.

View File

@@ -185,7 +185,7 @@ class LLMService(UserTurnCompletionLLMServiceMixin, AIService):
def __init__( def __init__(
self, self,
run_in_parallel: bool = True, run_in_parallel: bool = True,
function_call_timeout_secs: float = 10.0, function_call_timeout_secs: Optional[float] = None,
settings: Optional[LLMSettings] = None, settings: Optional[LLMSettings] = None,
**kwargs, **kwargs,
): ):
@@ -194,8 +194,8 @@ class LLMService(UserTurnCompletionLLMServiceMixin, AIService):
Args: Args:
run_in_parallel: Whether to run function calls in parallel or sequentially. run_in_parallel: Whether to run function calls in parallel or sequentially.
Defaults to True. Defaults to True.
function_call_timeout_secs: Timeout in seconds for deferred function calls. function_call_timeout_secs: Optional timeout in seconds for deferred function
Defaults to 10.0 seconds. calls.
settings: The runtime-updatable settings for the LLM service. settings: The runtime-updatable settings for the LLM service.
**kwargs: Additional arguments passed to the parent AIService. **kwargs: Additional arguments passed to the parent AIService.
@@ -753,11 +753,7 @@ class LLMService(UserTurnCompletionLLMServiceMixin, AIService):
# Start a timeout task for deferred function calls # Start a timeout task for deferred function calls
async def timeout_handler(): async def timeout_handler():
try: try:
effective_timeout = ( effective_timeout = item.timeout_secs or self._function_call_timeout_secs
item.timeout_secs
if item.timeout_secs is not None
else self._function_call_timeout_secs
)
await asyncio.sleep(effective_timeout) await asyncio.sleep(effective_timeout)
logger.warning( logger.warning(
f"{self} Function call [{runner_item.function_name}:{runner_item.tool_call_id}] timed out after {effective_timeout} seconds." f"{self} Function call [{runner_item.function_name}:{runner_item.tool_call_id}] timed out after {effective_timeout} seconds."
@@ -768,13 +764,15 @@ class LLMService(UserTurnCompletionLLMServiceMixin, AIService):
except asyncio.CancelledError: except asyncio.CancelledError:
raise raise
timeout_task = self.create_task(timeout_handler()) if item.timeout_secs or self._function_call_timeout_secs:
timeout_task = self.create_task(timeout_handler())
# Yield to the event loop so the timeout task coroutine gets entered
# before it could be cancelled. Without this, cancelling the task before
# it starts would leave the coroutine in a "never awaited" state.
await asyncio.sleep(0)
try: try:
# Yield to the event loop so the timeout task coroutine gets entered
# before it could be cancelled. Without this, cancelling the task before
# it starts would leave the coroutine in a "never awaited" state.
await asyncio.sleep(0)
if isinstance(item.handler, DirectFunctionWrapper): if isinstance(item.handler, DirectFunctionWrapper):
# Handler is a DirectFunctionWrapper # Handler is a DirectFunctionWrapper
await item.handler.invoke( await item.handler.invoke(