I found what looks like a tool-history race in @livekit/agents JS 1.6.2.
When a tool calls agent.updateTools() while it is executing, for example, removing itself after advancing application state—AgentActivity.updateTools() copies the chat context with the new toolCtx. That filters out the in-flight function call before LiveKit appends its function output. The next model request then contains an orphan output and logs:
function output missing the corresponding function call, ignoring
I have a minimal regression test that executes a tool, removes it mid-flight, and verifies the eventual call/output pair remains in agent.chatCtx. A narrow fix is to avoid filtering persistent pipeline-LLM history during AgentActivity.updateTools(); current tools are already supplied separately for each generation.
Is this behavior intentional?
Related question: is there a recommended scoped primitive for making a tool non-interruptible only while its operation runs, then restoring interruptibility for the result speech? ctx.disallowInterruptions() mutates the shared SpeechHandle, so we currently use a try/finally helper. If no primitive exists, would something like await ctx.withInterruptionsDisabled(operation) be useful upstream? It would need defined concurrency and already-interrupted-handle semantics.