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

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

Abierto
#2,146 2 comentarios 1 reacción 0 asignados Ver en GitHub
enhancement proposal
Lenguaje dominante
Python
Estrellas
15.9k
Forks
1.4k
Merge medio
1 d 17 h
PR fusionados (30 d)
163

Descripción

## 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.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.