Chat runner drives that conversation turn by turn and keeps the history for you.
Prerequisites
- An environment and a task (see Tasks).
- An agent to drive the turns (see Run on any model).
A chat-style task
A task’s prompt can be plain text or a list ofPromptMessages. To accept a running conversation, take a messages parameter and yield it as the prompt:
tasks.py
run.prompt becomes the message list, and agents consume it as normalized turns through run.prompt_messages.
Driving it with Chat
Chat wraps a concrete Task plus an Agent. Each send() appends the user message, runs the agent over a fresh run with the full history, appends the reply, and returns the Trace:
chat.py
Chat is imported from hud.eval (also re-exported as hud.Chat). The task’s messages argument is replaced with the running conversation on every send; pass runtime= to place each turn’s rollout (with no runtime it serves the task’s source locally when minted in-process, else uses the HUD runtime tunnel by the task’s env name).
Managing history
The conversation history is the publicchat.messages list — persist it, restore it, or reset it directly:
| Operation | Description |
|---|---|
await chat.send(message) | Send a user turn; returns the reply Trace. |
chat.messages | The history ({"role", "content"} dicts) — json.dumps it to persist, assign to restore, clear to reset. |
Serving a chat
Chat is protocol-agnostic: any frontend — a web handler, a notebook, a wire protocol — just calls await chat.send(...). For example, behind FastAPI:
cookbooks/a2a-chat/server.py — copy and adapt it; the protocol adapter is deliberately not part of the SDK.
When to use chat vs. a single-turn task
- Single-turn task — the default. One prompt, one graded answer. Use it for evals and training (see Tasks).
- Chat task — when the interaction itself is the thing: assistants, tool-use dialogues, or anything where the agent needs prior turns. The grading model is the same — you still yield a reward.