Skip to main content
HUD environments aren’t limited to single-turn evals. You can build multi-turn chat experiences where users talk to your environment over multiple turns, and the environment owns the conversation flow. This guide walks through the full setup: defining a chat scenario, using Chat directly, serving over A2A, and building web apps on top.

Defining a Chat Scenario

A chat scenario is a regular @env.scenario() with chat=True. This tells HUD to pass prior conversation history into the scenario on every turn.
from typing import Any
from hud import Environment

env = Environment("support")

@env.scenario("help", chat=True)
async def help_chat(messages: list[dict[str, Any]] | None = None):
    messages = messages or []
    yield f"You said: {messages[-1]['content'] if messages else 'nothing yet'}"
    yield 1.0
Key points:
  • chat=True — HUD enforces that the scenario accepts a messages parameter.
  • messages — Prior turns are passed in automatically. The scenario can read history to maintain context.
  • The environment owns the flow — The scenario decides what to ask, when to ask it, and how to use the tools. No SDK-side routing needed.

Using Chat

Quick Start with env.chat()

The simplest way to create a chat instance:
chat = env.chat("help", model="claude-haiku-4-5")

r1 = await chat.send("Look into account ABC-123")
print(r1.content)

r2 = await chat.send("What's their current plan?")
print(r2.content)
env.chat() defaults to trace=False, quiet=True — no platform traces, no browser popups. Ideal for server and app usage.

Chat Directly (Full Control)

For more control, use Chat with an environment task:
from hud.services import Chat

chat = Chat(
    env("help"),
    model="claude-sonnet-4-20250514",
    max_steps=10,
    trace=True,      # record traces on HUD platform
    quiet=False,      # show trace links
)

r1 = await chat.send("Look into account ABC-123")
print(r1.content)

Chat Parameters

ParameterTypeDefaultDescription
modelstrRequiredModel name (auto-resolves to agent class)
max_stepsint10Max agent tool-call steps per turn
traceboolTrueRecord traces on the HUD platform
quietboolTrueSuppress banner/link output
agent_paramsdictNoneExtra kwargs forwarded to agent creation
namestrscenario nameHuman-readable name for AgentCard
descriptionstrautoDescription for AgentCard

History Management

Chat manages history internally. Each send() appends the user message, runs the agent, and appends the response.
# Export history for persistence (e.g., save to database)
history = chat.export_history()

# Later, restore it
chat.load_history(history)

# Or reset completely
chat.clear()

Multi-User Sessions with ChatService

ChatService manages multiple independent conversations, each identified by a session_id. Use it for web apps with per-user chats.

Direct Python Usage

from hud.services import ChatService

service = ChatService(
    env("help"),
    model="claude-haiku-4-5",
)

# Each session_id gets independent history
r1 = await service.send("Hello", session_id="user-alice")
r2 = await service.send("Different question", session_id="user-bob")

# Manage sessions
service.clear(session_id="user-alice")
history = service.export_history(session_id="user-bob")
service.load_history(saved_messages, session_id="user-bob")
Sessions auto-expire after 30 minutes of inactivity.

Serving Over A2A

ChatService also implements the A2A protocol for cross-language/cross-network clients:
service.serve(host="0.0.0.0", port=9999)
Or with environment variables:
HUD_ENV=support HUD_SCENARIO=help \
    uv run python examples/03_a2a_chat_server.py
The service publishes an agent card at /.well-known/agent-card.json and accepts A2A messages at the root endpoint.
Each ChatService targets exactly one scenario. If your environment has multiple chat-compatible scenarios, run one service per scenario or build client-side routing.

Building a Web App

A common pattern: FastAPI backend wraps Chat, Next.js frontend provides the UI.
from fastapi import FastAPI

app = FastAPI()
chat = env.chat("help", model="claude-haiku-4-5")

@app.post("/api/chat")
async def chat_endpoint(message: str):
    result = await chat.send(message)
    return {"response": result.content}

@app.post("/api/chat/clear")
async def clear():
    chat.clear()
    return {"status": "cleared"}
For multi-user support, use ChatService with session_id derived from the user’s auth token.

When to Use What

ApproachWhen
env.chat()Quick setup, scripts, notebooks, single-user apps
Chat directlyFull control over trace/quiet/agent params
ChatService.send()Multi-user apps (per-user sessions in Python)
ChatService.serve()A2A protocol for cross-language/network clients

Examples