Demo app for learning and reference. Not intended for production use as-is.
Why it exists
Most agent frameworks run in-process — if your server restarts, the agent run is lost. Agent Chat demonstrates the Temporal-first model:| Capability | How Agent Chat shows it |
|---|---|
| Durable conversations | Chat history and agent runs survive server restarts |
| Split client / worker | API starts workflows; worker process executes them |
| Streaming | AG-UI–shaped JSON over SSE to the browser |
| Conversation persistence | PostgreSQL for app data; SDK conversation bridge for agent context |
Stack
| Layer | Technology |
|---|---|
| Agent runtime | Agent SDK for Go + Temporal |
| API | Go — chi router, pgx, REST + SSE |
| UI | React Router 7 + Vite + Tailwind CSS v4 |
| Data | PostgreSQL (conversations and messages) |
| Infra | Docker Compose — Postgres, Temporal, API, worker, UI |
Architecture
The API and Temporal worker are separate processes from the same server image.APP_MODE selects the role:
| Mode | Process | SDK pattern |
|---|---|---|
server | HTTP API + agent client | NewAgent with DisableLocalWorker + EnableRemoteWorkers |
worker | Temporal worker | NewAgentWorker with matching config |
agentsetup.CommonOptions — same name, LLM client, conversation config, and Temporal settings — so the SDK fingerprint check passes.
server/agent/) feeds message history into WithConversation on each run.
Key code patterns
1. Split client / worker with shared config Both API and worker callCommonOptions() to get identical SDK options. The API adds DisableLocalWorker + EnableRemoteWorkers; the worker uses the options as-is. This ensures the SDK fingerprint check passes at activity entry.
ev.ToJSON() and written to the SSE response. The Temporal workflow continues even if the browser disconnects.
interfaces.Conversation over PostgreSQL instead of the in-memory or Redis backends. This lets conversation history survive restarts and be shared across worker replicas.
WithConversation — the SDK injects history into every LLM call automatically. See Conversation.
SDK features demonstrated
| Feature | Agent Chat usage |
|---|---|
| Temporal runtime | Every chat message triggers a durable workflow |
| Conversation | Custom PostgreSQL-backed interfaces.Conversation |
| Streaming | Stream() with SSE bridge forwarding ev.ToJSON() |
| AG-UI Protocol | TEXT_MESSAGE_CONTENT, RUN_FINISHED, RUN_ERROR events |
| LLM Providers | OpenAI, Anthropic, or Gemini via env config |
Prerequisites
- Docker and Docker Compose — all services run in containers; no local Go or Node install required
- LLM API key — for OpenAI, Anthropic, or Gemini (set in
server/.env) - Ports
3000(UI),9090(API),7233+8233(Temporal),5432(Postgres) available locally
Run locally
| Service | URL |
|---|---|
| Chat UI | http://localhost:3000 |
| Go API | http://localhost:9090 |
| Temporal UI | http://localhost:8233 |
docker compose down. Optional: LLM_BASE_URL, AGENT_SYSTEM_PROMPT, AGENT_NAME, AGENT_CONVERSATION_WINDOW_SIZE. For streaming toggle, copy ui/.env.example to ui/.env and set ENABLE_STREAM=true (SSE) or false (REST).
API and streaming
| Endpoint | Method | Purpose |
|---|---|---|
/api/conversations | GET, POST | List and create conversations |
/api/conversations/:id/messages | GET, POST | Message history; blocking agent reply |
/api/conversations/:id/messages/stream | POST | SSE stream of AG-UI JSON events |
ev.ToJSON(). After RUN_FINISHED, the server emits a MESSAGE_PERSISTED extension frame with the database message id.
Closing the browser stream does not cancel the Temporal workflow — use GET /api/conversations/:id/messages to reconcile state.
UI streaming
The UI maps AG-UI events to chat bubbles:| Event | UI behavior |
|---|---|
TEXT_MESSAGE_CONTENT | Incremental assistant text via delta |
RUN_ERROR | Display error message |
MESSAGE_PERSISTED | Replace streaming bubble with persisted message id |
ENABLE_STREAM in Docker (ui service env) or VITE_ENABLE_STREAM for local UI dev.
Related docs in this portal
Durable Agent
SDK durable execution example
Agent Worker
Client and worker split example
AG-UI Protocol
Event format and frontend integration
AG-UI Example
Minimal SSE server in the SDK repo