persona.chat — /api/v1/developer/agui.
Runs an Agent as the asserted external user, streaming the response as AG-UI events. Requires
the client to have been constructed with externalUserId set — a bare Project credential has no
Subject to chat as; the server rejects it with 400 EXTERNAL_USER_REQUIRED.
Methods
stream(agentId, options)
Yields each raw AG-UI event as it arrives:agentId— the Agent to run.- The underlying request is
POST /api/v1/developer/aguiwithx-agent-id: <agentId>and (when set)x-thread-id: <threadId>headers — routing is header-based, not body-based. - Malformed/partial SSE frames are skipped rather than thrown; the stream ends when the run finishes.
sendMessage(agentId, options)
Convenience wrapper overstream() — drains the full run and returns:
SendMessageOptions
AG-UI event types
stream() yields the standard @ag-ui/core EventType union. The SDK re-exports EventType
from the package root so you don’t need a separate @ag-ui/core dependency just to compare
event.type:
The full, versioned JSON Schema for every
CUSTOM event’s payload is served at
GET /api/v1/developer/agui/schema (not yet wrapped by a typed method — call it via
HttpClient if you need it). Every stream response carries the active
schema version on the X-AGUI-Schema-Version header. The TypeScript counterparts
(ClarificationRequestPayload, HitlRequestPayload, McpAppPayload, SubagentActivityPayload)
are exported from the package root and kept in sync with that document.
Human-in-the-loop: interrupts and resuming
If an Agent’sinterruptOn config requires confirming a sensitive tool call, or the run needs a
clarifying answer, the run pauses instead of finishing normally: it emits a CUSTOM event
instead of RUN_FINISHED, and sendMessage() detects this and sets result.interrupt:
Resume on the next
sendMessage()/stream() call for the same Thread, with messages: []
(no new user message — you’re answering the interrupt, not starting a new turn) and resume set:
ChatResume is a union: { decisions: unknown[] } (for hitl) | { answers: unknown[]; text?: string } (for clarification) | Record<string, unknown> (for anything else). The shape you must
pass depends on the interrupt kind. ChatInterrupt.value is typed unknown — its concrete shape
depends on the interrupt payload (see the HitlRequestPayload/ClarificationRequestPayload types
for the backend’s shapes).
Structured run errors
If a run ends in a genuine failure — not an interrupt —sendMessage() sets result.error
instead of result.interrupt, as a typed PersonaRunErrorEvent:
PersonaRunErrorEvent: { type: 'RUN_ERROR', code: RunErrorCode, message: string, retryable: boolean, providerName?: string }.
RunErrorCode values: