Skip to content

[Gastown] Agent Streaming Endpoint — Container WebSocket/SSE for Live Agent Observation #343

@jrf0110

Description

@jrf0110

Parent: #204 | Priority: P0 — Blocks usable dashboard

Problem

The container creates stream tickets (UUIDs with 60s TTL in-memory) via POST /agents/:agentId/stream-ticket, and the worker handler handleContainerStreamTicket constructs stream URLs. But the actual endpoint that would consume these tickets and stream events to the browser does not exist. The AgentStream.tsx component connects via EventSource to a URL that serves nothing.

The "watch an agent work" experience — the core value proposition of the dashboard — is completely blocked by this.

What Exists

  • control-server.ts: POST /agents/:agentId/stream-ticket — creates tickets, stores in Map<string, {agentId, expires}> with 60s TTL and max 1000 entries
  • process-manager.ts: SSE consumers already subscribe to kilo serve /event and track per-agent events (tool calls, completions, messages)
  • town-container.handler.ts: handleContainerStreamTicket proxies to container and wraps result in a stream URL
  • AgentStream.tsx: Connects via EventSource to the constructed URL, renders events in a scrollable log

What's Missing

A GET /agents/:agentId/stream endpoint on the control server that:

  1. Validates a stream ticket from the query string (?ticket=<uuid>)
  2. Opens an SSE connection to the client
  3. Subscribes to the relevant kilo serve session's event stream (already tracked in ManagedAgent.sseConsumer)
  4. Forwards relevant events (tool calls, assistant messages, file edits, errors) to the browser
  5. Sends periodic keepalive comments to prevent connection timeout
  6. Closes cleanly when the agent exits or the client disconnects

Implementation Approach

The process-manager.ts already has per-agent SSE consumers that receive all events from kilo serve. The new endpoint needs to:

  1. Add a GET /agents/:agentId/stream route to control-server.ts
  2. Validate the ticket, consume it (one-use)
  3. Create a ReadableStream that subscribes to the agent's events
  4. The existing ManagedAgent needs a way to register additional event listeners (besides the internal SSE consumer). A simple event emitter or callback list on the ManagedAgent object.
  5. Format events as SSE: event: <type>\ndata: <json>\n\n
  6. Handle cleanup on disconnect

Acceptance Criteria

  • GET /agents/:agentId/stream?ticket=<uuid> endpoint on control server
  • Ticket validation and one-time consumption
  • SSE stream of agent events (tool calls, messages, completions, errors)
  • Periodic keepalive to prevent timeout
  • Clean disconnect handling (client closes, agent exits)
  • AgentStream.tsx component works end-to-end (connect → see live events)
  • Multiple concurrent viewers for the same agent work correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions