Comma Agents
@comma-agents/tuiHooks

useChat

Bind a view to a single chat session — read messages, status, errors, and send input or permission decisions.

useChat binds a component to a single chat session. It observes the session's messages, lifecycle status, error state, and pending input/permission requests. It provides action methods to start a strategy, send user input, resolve permission requests, reset, and stop.

Must be called inside <DaemonContextProvider> and <ChatSessionsContextProvider>.

import { useChat } from "@comma-agents/tui";

const chat = useChat();

// Read state
chat.messages;        // readonly ChatMessage[]
chat.status;          // "idle" | "running" | "waiting_input" | "waiting_permission" | ...
chat.error;           // string | null
chat.strategyName;    // string | null

// Start a new strategy
const sessionId = chat.startStrategy("path/to/strategy.json", "initial input");

// Send input while waiting
chat.sendInput("user reply text");

// Resolve a permission prompt
chat.sendPermissionDecision("allow");

// Lifecycle
chat.reset();   // Clear messages and go back to idle
chat.stop();    // Send stop command for this run

Session Resolution

By default, useChat() binds to the currently active session (set by startStrategy or setActiveSessionId). You can bind to a specific session by passing a sessionId:

const chat = useChat(someSessionId);

When no matching session exists -- for example, on first mount before any strategy has been started -- the returned view exposes empty values. startStrategy remains functional and creates a new session.

UseChatState

FieldTypeDescription
sessionIdstring | nullId of the bound session, or null
messagesreadonly ChatMessage[]Chat messages for this session
statusChatStatusUI lifecycle status
errorstring | nullLatest error message, or null
pendingInputAgentstring | nullAgent waiting for user input
strategyNamestring | nullName of the strategy for this session
strategyPathstring | nullPath to the strategy file
readOnlybooleanWhether this is a loaded (non-live) session
pendingPermissionRequestPendingPermissionRequest | nullHead of the permission queue
runIdstring | nullDaemon run id
connectionStatusWebSocketStatusCurrent daemon connection status
startStrategy(strategyPath, input?, cwd?) => ChatSessionIdStart a new strategy
sendInput(text: string) => voidSend user input to the waiting agent
sendPermissionDecision(decision: ...) => voidResolve a permission request
reset() => voidClear messages and status
stop() => voidStop the current daemon run

ChatStatus

The ChatStatus type extends the daemon's RunStatus with TUI-only states:

  • idle -- Session exists but no run has started
  • running -- A daemon run is active
  • waiting_input -- An agent is waiting for user input
  • waiting_permission -- A sandbox permission request is pending
  • completed / error / cancelled -- Terminal states from the daemon

ChatMessage

Each message has the shape:

FieldTypeDescription
idstringUnique message identifier
role"user" | "agent" | "system"Sender role for color resolution
senderstringDisplay name (agent name, "you", "system")
textstringFull text content
segmentsreadonly MessageSegment[]?Typed body parts (tool calls, thinking, etc.)
streamingbooleanWhether the message is still receiving tokens
timestampnumberUnix timestamp in milliseconds

MessageSegment

Agent messages may have ordered segments for richer rendering:

TypeDescription
textPlain text with streaming tracking
tool-callA tool invocation with name and raw arguments
tool-resultA tool invocation result (completed or error)
thinkingModel reasoning/thinking block
mcp-callAn MCP tool invocation with server, tool, args, and optional output

useChatSessions

useChatSessions returns the full session map and controls:

import { useChatSessions } from "@comma-agents/tui";

const {
  sessions,          // ReadonlyMap<ChatSessionId, ChatSession>
  activeSessionId,
  setActiveSessionId,
  createSession,
  persistedSessions,
  loadPersistedSession,
  fetchPersistedSessions,
  removeSession,
} = useChatSessions();

Use this when you need to manage multiple sessions or display a session picker rather than binding to a single session view.

On this page