ag-ui-protocol / ag-ui-protocol/ag-ui

[Feature]: @ag-ui/mastra — opt-in live TOOL_CALL_START for server tools (a long-running server tool paints no running step)

Đang mở
#2,402 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
15.9k
Fork
1.4k
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
163

Mô tả

## Context

`@ag-ui/mastra@1.1.1`, `@ag-ui/client@0.0.57`, consumed through `@assistant-ui/react-ag-ui@0.0.54`. Our agent's tools are all SERVER tools on the Mastra agent (audio analysis, generation, retrieval) — several of them run for seconds to minutes.

## Finding

A server tool's call is not visible until it has already finished, so a long-running tool paints no "running" step.

Live tool-call streaming is deliberately gated to CLIENT tools (`isClientTool`, `integrations/mastra/typescript/src/mastra.ts:1467` on `44a92a0`), introduced by #2066 / OSS-393. A server tool therefore takes the buffered path: `case "tool-call"` (`:2007`) parks `{toolCallId, toolName, args}` in `pendingToolCall`, and `flush()` (`:1511`) runs only when the NEXT chunk arrives. For an ordinary sequential tool that next chunk is its own `tool-result`.

The consequence is that the subscriber receives TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END and TOOL_CALL_RESULT in one same-millisecond flush, after the tool has completed. A UI that renders tool activity has nothing to render during the part of the turn where the user is actually waiting.

Measured on our own stack (loopback capture of a multi-second transcription tool): the whole call family arrives in a single flush. On a synthetic `fullStream` with a 1500 ms gap between `tool-call-input-streaming-start` and `tool-result`, pristine 1.1.1 gives a 1 ms window between START and RESULT; with the gate widened, 1502 ms.

## Why this is not simply a bug

The gate is load-bearing, and the code says so at `:1459-1466`: buffering is what lets a following `tool-call-suspended` (`:2136`) or `background-task-started` (`:2211`) suppress the normal tool render by clearing `pendingToolCall`. You cannot retract an already-emitted live arg stream, so streaming server tools unconditionally would break those two paths.

## Proposal

An opt-in `MastraAgentConfig.streamServerToolCalls`, default `false` (exactly today's behaviour). When on, `tool-call-input-streaming-start` opens the call for any named tool rather than only client tools.

That leaves one real design question, which is why this is an issue rather than a drive-by PR: **what should a suspend / background-start do to a call that is already open?** Two defensible answers:

1. Close it — emit `TOOL_CALL_END` for the streamed call so no START is left without a terminal. The consumer then sees a tool call with no `TOOL_CALL_RESULT`, and the interrupt or the activity carries the outcome. This keeps the option usable with an honest documented caveat.
2. Refuse the combination — treat `streamServerToolCalls` as unsupported for suspendable / background tools and document that.

I have a branch implementing (1) with tests, happy to open it as a PR against whichever resolution you prefer, or to drop it if the shape is wrong for the project. Per CONTRIBUTING I am filing this first rather than opening the PR cold.

## Related

- #2066 (OSS-393) — the change that introduced the client-tool gate.
- #2380 — `@ag-ui/mastra` continuation-id reuse, same file.
- #2353, #2135 — open PRs touching the same bridge's stream lifecycle.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.