Skip to content

Render nested function calls under their parent - #173

Draft
kompfner wants to merge 1 commit into
mainfrom
pk/nested-function-calls
Draft

kompfner wants to merge 1 commit into
mainfrom
pk/nested-function-calls

Conversation

@kompfner

Copy link
Copy Markdown

What a nested function call is

Pipecat's RTVI function-call events are gaining an optional parent_tool_call_id: the tool_call_id of the function call this one ran as part of. A tool's work can involve function calls of its own, made by another model on its behalf, e.g. a backend that a delegate tool hands work to makes calls while the delegate call is in progress; each of them names it as its parent. The field is absent for a call the bot's LLM made itself.

Rendering rule

Conversation (and so the Console template) groups function-call messages with a new nestFunctionCalls helper before rendering:

  • A call whose parent_tool_call_id matches a call rendered in the same conversation is shown indented under that parent, directly below the parent's row, using the same FunctionCallContent row (own status icon, name, collapsible arguments/result). Nesting recurses for deeper levels.
  • A call whose parent is not rendered (the app may hide it through Pipecat's report level, so the client never received it) is rendered at the top level, exactly like a call without a parent.
  • A parent with nested calls shows the count after its name: (delegate) · 2 nested calls (singular for one). functionCallLabel still applies to every row.
  • Arrival order is kept at each level. A child that arrives before its parent is shown top-level until the parent arrives.

FunctionCallContent gains a nestedCalls prop and MessageContainer a nestedFunctionCalls prop; nestFunctionCalls, NestedFunctionCall, and NestableFunctionCallData are exported from the package. The docs page for FunctionCallContent describes nested calls, and a vitest covers the grouping helper.

Dependencies

parent_tool_call_id is read through NestableFunctionCallData (FunctionCallData & { parent_tool_call_id?: string }) so this type-checks against the currently published @pipecat-ai/client-react. It depends on:

  • parent_tool_call_id reaching FunctionCallData in @pipecat-ai/client-react via pipecat-ai/pipecat-client-web (companion PR).
  • The field being produced by the bot: pipecat-ai/pipecat PR #5689.

Until both ship, every call renders at the top level as before. The client-react dependency version is unchanged.

A function call can carry parent_tool_call_id, the tool_call_id of the
call it ran as part of (e.g. calls a backend makes on behalf of a
delegate tool while that call is in progress). The Conversation view
groups such calls with nestFunctionCalls: a call whose parent is in the
conversation is rendered indented under the parent's row, with its own
status icon, name and collapsible details, recursively for deeper
nesting, and the parent shows how many calls ran under it
("(delegate) · 2 nested calls"). A call whose parent is not in the
conversation stays at the top level, exactly like a call without a
parent. Arrival order is kept at every level.

parent_tool_call_id is read through NestableFunctionCallData, an
intersection with FunctionCallData, until the @pipecat-ai/client-react
release that declares the field is published.
@vercel

vercel Bot commented Sep 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
voice-ui-kit-console-example Ready Ready Preview Sep 14, 2026 3:11pm UTC
voice-ui-kit-docs Ready Ready Preview Sep 14, 2026 3:11pm UTC

Request Review

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