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

[Feature]: server-decided display name for tool calls and responses

未关闭
#2,146 2 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看
enhancement proposal
主要语言
Python
星标
15.9k
派生
1.4k
平均合并
1 天 17 小时
30 天内合并 PR
163

描述

## Summary

Tool-call events (`TOOL_CALL_START` / `TOOL_CALL_ARGS` / `TOOL_CALL_END` / `TOOL_CALL_RESULT`) carry the tool's **technical identity** (`toolCallId`, `toolCallName`, args, result) but there is **no field for a human-facing display name** — a short, often localized string describing what the tool is doing or what it returned. There's no first-class way for the **server/agent to decide** what display name the UI should show for either the call or its response.

## Why this matters

### The user sees internal tool names

Tool names are identifiers designed for the LLM, not for humans. A user watching the agent work should see **actions** ("Checking the weather in Paris…", "Booking the flight…"), not internal identifiers (`get_current_weather`, `create_flight_reservation`). Today the UI has two options: show the raw `toolCallName` as-is (poor UX), or maintain a client-side `toolName → displayName` map.

### The frontend shouldn't need to know the agent's tool inventory

The mapping from tool name to display name is **backend knowledge**: the server knows which tools exist, what they do, and how to describe them to a user. Forcing the frontend to maintain that map creates tight coupling — the UI has to be updated whenever the agent gains new tools, renames one, or groups several under a shared description. In practice this means:

- **Duplication**: the agent's tool catalog is partially replicated in the UI.
- **Drift**: UI descriptions go stale when tools change.
- **Per-client burden**: every frontend (web, mobile, voice, …) has to maintain its own copy.

A `displayName` field lets the **agent decide what the user sees**, and the UI just renders it — decoupling presentation from the agent's internal naming.

### Two distinct moments, two distinct strings

Backends typically differentiate:

- **Call phase** (`TOOL_CALL_START`): a present-continuous status shown while the tool runs.
- `search_web` → "Searching the web…"
- `read_file` → "Reading the file…"
- `send_email` → "Sending the email…"
- `run_sql_query` → "Querying the database…"
- `generate_image` → "Generating the image…"

- **Response phase** (`TOOL_CALL_RESULT`): a past-tense or completion string shown once the result arrives.
- `search_web` → "Web search complete"
- `read_file` → "File loaded"
- `send_email` → "Email sent"
- `run_sql_query` → "Query returned 42 rows"
- `generate_image` → "Image ready"

This mapping is also:

- **i18n-aware**: different locales render different strings.
- **Selective**: some tools have a display name; others are intentionally silent (internal bookkeeping tools the user doesn't need to see).
- **Grouping-friendly**: several tools can share the same display name (e.g. a documentation toolset whose members are all shown as "Searching documentation…").

When porting such a backend to AG-UI, that presentation logic has **nowhere to live**:

- The UI receives only `toolCallName` and must **hardcode a `toolName → displayName` map on the client** — duplicating and drifting from what the server already knows, and forcing per-client localization.
- Or the server resorts to a **side-channel `CUSTOM` event** correlated by `toolCallId`, which works but is ad-hoc: no standard event name/shape, every UI has to special-case it, and ordering/correlation is left to the integrator.

Neither lets the server cleanly say *"when you render this tool call / response, show this to the user"*.

## Questions / possible directions (for discussion)

1. **A `displayName` field on `ToolCallStartEvent` and `ToolCallResultEvent`** — an optional, already-localized string the server provides alongside `toolCallName`. Minimal, transport-agnostic, and the natural home for "what to display". UIs fall back to `toolCallName` when absent. Two separate fields cover the call phase and the response phase independently.
2. **A documented `CUSTOM`-event convention** — reserved event names + payload shapes for both moments (`{ toolCallId, displayName, phase: "call" | "result" }`) that UIs are expected to honor, so the side-channel becomes a spec'd pattern instead of per-integration glue.
3. **Per-tool `displayName` in tool definitions / capabilities** — the UI looks up a `toolName → { callDisplayName, resultDisplayName }` map advertised once (e.g. via capabilities). Cleaner but static (no per-call / per-locale variation).

Each has trade-offs (per-call + localizable favors 1/2; "advertise once" favors 3). I'd love a maintainer's take on the intended direction.

## Offer

Once the shape is settled I'm happy to implement the `ag-ui-adk` side (e.g. surfacing server-provided `displayName` fields onto `TOOL_CALL_START` / `TOOL_CALL_RESULT` or as spec'd `CUSTOM` events), and can prototype the chosen option. Flagging it as design-first because option 1 touches the event schema in core.

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。