Skip to content

Feature: per-tool execute timeout, a hung blocking tool stalls the turn forever #2428

Description

@HoneyTyagii

Problem

tool() has no execution timeout. If a blocking tool's execute() never settles (a fetch to a dead endpoint, a third-party SDK that hangs, a forgotten await), the turn stalls indefinitely:

  • ToolExecutor.runTool (agents/src/voice/tool_executor.ts) awaits the tool promise with no time bound
  • The tool's AbortSignal only fires on interruption / explicit cancel() / drain(), never on elapsed time
  • The only related knob, DRAIN_TOOL_TIMEOUT_MS (via LK_DRAIN_PLAYOUT_TIMEOUT_MS), bounds how long drain waits after abort was already signalled; it does nothing for a tool that hangs mid-turn while the user is silent

Requested behavior

An executeTimeout (ms) option on tool():

const getWeather = tool({
  name: 'getWeather',
  description: '...',
  parameters: z.object({ location: z.string() }),
  executeTimeout: 10_000,
  execute: async ({ location }, { abortSignal }) => { ... },
});

On expiry:

  1. Abort the tool's existing AbortController (one already exists per running task)
  2. Emit a FunctionCallOutput with a timeout ToolError so the model can tell the user the tool timed out (related: fix(tts): restart ChunkedStream retries under fresh request IDs #1994, "Cancelled function tools vanish without a trace")
  3. Clean up the RunningTask entry so hasRunningTasks returns to normal

Optionally a default at the Toolset / AgentSession level, with per-tool override.

Why not just AbortSignal.timeout() in every execute?

That's the current workaround and it's:

  • Boilerplate repeated in every tool, easy to forget
  • Powerless when execute ignores the signal (many SDK calls don't accept one), since nothing races the promise from the outside
  • Inconsistent: some tools end up with timeouts, others don't, and a single offender still wedges the whole turn

Environment

  • agents-js 1.4.x / current main

Happy to contribute a PR if the approach sounds good.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions