OptionalappOrigin of the Pouchy deployment, e.g. "https://pouchy.ai".
OptionalcontextWorld-state kinds this surface emits (declared at handshake).
OptionaldebugInstrumentation (0.32.0). true logs structured events via
console.debug('[pouchy-sdk]', …); a function receives every
CompanionDebugEvent (HTTP request/response, delivered envelope,
stream-state transition, synthesized error) for your own logger /
devtools / test recorder. Events never carry the token or any header —
method, path, status, timing, envelope type/id only. Zero cost when
unset.
OptionalfetchInjectable fetch (for Node < 18 / tests). Defaults to global fetch.
Optionalinit: RequestInitOptionalinit: RequestInitOptionalhandlesAction types this surface can perform (declared at handshake). Stored but
never consumed server-side today — a client-side capability hint whose one
SDK effect is opting a tool-less embed into the auto-offered host-control
verbs on connectCall() voice sessions. It does NOT register tools for text
turns: a tool you want called on a text turn must be declared in tools.
OptionalmodalitiesRequested I/O modalities (intersected with the token's grant server-side).
OptionalonCalled when a request or the event stream is rejected with 401 (expired /
revoked token — session tokens live 1h by default). Return a fresh token
(e.g. re-minted by your backend via POST /v1/sessions) and the client
retries transparently; return null to give up, surfacing the failure
exactly as without this hook. Scope denials (403 missing_scope) are
configuration errors and never trigger it. Alternative: call setToken()
proactively on your own refresh schedule.
OptionaloutboxPersistence for the offline queue (see queueOffline). Defaults to
localStorage when available (privacy-mode / quota failures fall back
silently), else an in-memory page-lifetime store. The key is
pouchy-outbox:${surface}, so each surface keeps its own queue.
OptionalqueueOpt-in offline send queue (0.34.0). A sendText that fails at the NETWORK
level (fetch rejected before any HTTP response, or navigator.onLine is
false) is queued instead of lost, and replayed FIFO once the server is
reachable again — after a successful connect(), on every stream
reconnect, or via flushOutbox(). Replays reuse the ORIGINAL turnId:
the server dedupes completed turnIds (10 min TTL, last 8 per session),
so a retry after an ambiguous failure can never double-run a turn. HTTP
error responses (4xx/5xx incl. 429) are NEVER queued — the server saw
those; they keep the normal throw semantics. Default false.
OptionalreplayReplay of pause-orphaned tool calls (0.37.0). When connect() resumes a
session whose turn is paused on tool calls THIS surface never answered
(the page reloaded / crashed mid-pause), the handshake carries them as
pendingToolCalls and the client re-emits each to your onToolCall
handler with replayed: true — post the results as usual and the paused
turn completes instead of being abandoned. Register onToolCall BEFORE
calling connect()/start() to receive them. The result apply is
idempotent per call id, but the APP-side effect may not be: if a tool
has side effects, treat call.id as an idempotency key when
replayed is set. Pass false to disable the re-emit — the calls stay
readable on the HelloAck.pendingToolCalls you get from connect().
Default true.
OptionalrequestDeadline for a request to produce RESPONSE HEADERS, in ms (0.35.0).
Bounds every HTTP call the client makes (connect, sendText, recall, …) so
a server that accepts the TCP connection but never answers can't hang a
helper forever — previously only sendText({ awaitReply }) had any
deadline. Reading a response BODY (the SSE event stream, a streaming
sendText reply) is never bounded by this — the timer is cleared the
moment headers arrive. Composes with any per-call AbortSignal (whichever
fires first wins); the timeout rejects as a status-0 CompanionError with
code 'request_timeout'. Default 30_000; 0 disables.
OptionalstreamReceive transport for the reply stream. 'sse' (default) works on every deploy; 'websocket' opts into the lower-latency WS plane when the host supports it (adapter-node / a WS gateway) and falls back to SSE if the socket can't open — so enabling it can never stop reply delivery.
OptionalsurfaceLogical surface (one resumable session per surface), default "default".
A Pouchy access token — normally a session token from POST /v1/sessions; a PAT (pchy_…) for personal integrations.
OptionaltoolsTools the companion may ask this surface to perform (companion.tool_call).
OptionalvisitorOpen a REPRESENTATIVE ("on-behalf-of" / 代聊) session: the companion fields
this VISITOR's messages on the owner's behalf — customer-service style —
drawing only on screened owner context (persona + share-screened facts, plus
the knowledge base when the owner's token grants expose:knowledge). Each
visitor (stable opaque id, 8-64 url-safe chars that YOU keep stable per
end-user) gets their own continuous thread. Requires the token's represent
scope — without it the handshake is rejected (never silently downgraded to an
owner-facing session).
OptionalwebInjectable WebSocket constructor (Node without a global WebSocket, or tests). Defaults to globalThis.WebSocket when present.
Static description of THIS app/game so the companion is grounded in where it is (drives reasoning + the call opener). Live state still flows via sendWorldState.