UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

144 lines • 5.91 kB
/** * Client-side counterpart to {@link import('../sse.js').AgentSseEncoder}: parses the provider's SSE * back into typed frames the browser can render. Kept framework-agnostic (no React, no Adonis) so * any consumer — a React hook, a Vue composable, a plain fetch loop — decodes the wire format the * same way, and so the envelope stays owned by the package that emits it. * * Wire format — the agent stream protocol shared with `@dudousxd/nestjs-agent`: * - `event: meta\ndata: {runId,threadId}` — sent once, first, before any token * - `id: <seq>\ndata: <AgentStreamEvent>` — one event per frame (`{"kind":"text","text":…}`, * `ui`, `elicitation`, `approval-requested`, reasoning, tool calls, steps, title, …) * - `event: error\ndata: {code,message}` — the run failed (terminal) * - `event: done\ndata: {}` — the run's stream finished */ import type { ElicitationRequest } from '../elicitation.js'; import type { ToolConfirmation } from '../tool-presentation.js'; /** A rendered part of an assistant message: streamed text, or a named component with its props. */ export type ChatPart = { type: 'text'; text: string; } | { type: 'component'; name: string; data: unknown; id?: string; version?: number; fallbackText?: string; componentVersions?: Record<string, number>; /** * A preview of a layout the model is still writing (genui `streaming: 'partial'`): unvalidated, * replaced in place by the final component under the same `id`. */ partial?: true; }; /** A decoded stream frame — the typed form of one SSE event. */ export type ChatFrame = { type: 'text'; delta: string; } | { type: 'component'; name: string; data: unknown; id?: string; version?: number; fallbackText?: string; componentVersions?: Record<string, number>; /** * A preview of a layout the model is still writing (genui `streaming: 'partial'`): unvalidated, * replaced in place by the final component under the same `id`. */ partial?: true; } | { type: 'meta'; runId?: string; threadId?: string; } /** A failed run (`event: error` under the agent protocol). Terminal, like `done`. */ | { type: 'error'; code: string; message: string; } /** Any other agent-protocol event — reasoning, tool calls, steps, title, … */ | { type: 'event'; event: Record<string, unknown> & { kind: string; }; } /** * A question set the run is parked on, with everything needed to answer it: `runId` and * `toolCallId` are the body `POST /agent/tool-call/answer` takes, and `request` is the form. * * `runId` is NOT necessarily the run this stream was opened for. A delegated sub-agent forwards * its frames into its top-level ancestor's stream — that is the only stream a human is watching — * so the run to answer is the child's, and reading it off `meta` would address the wrong one. */ | { type: 'elicitation'; runId: string; toolCallId: string; request: ElicitationRequest; } /** * An action tool awaiting an approve/reject, with what it means to run. `runId`/`toolCallId` are * the body `POST /agent/tool-call/approve` (or `/reject`) takes — and `runId` is the parked run, * which for a delegated sub-agent is not the run this stream was opened for. */ | { type: 'approval'; target?: { kind: 'proposal'; proposalId: string; }; runId: string; toolCallId: string; toolName: string; input: unknown; confirmation?: ToolConfirmation; approver?: string; expiresAt?: string; reason?: string; } | { type: 'done'; }; /** One raw SSE event: the `event:` name (default `message`) and the joined `data:` payload. */ export interface SseEvent { event: string; data: string; /** * The frame's `id:` — its sequence number in the run. Strictly increasing within a run, gaps * allowed; `meta`, `done` and `error` carry none. */ id?: string; } /** * Parses one raw SSE frame (the text between `\n\n` separators, without them) into `{event, data}`. * A frame with no `data:` line (e.g. a `:` keep-alive comment) returns `null`. */ export declare function parseSseEvent(frame: string): SseEvent | null; /** * Decodes a parsed {@link SseEvent} into a typed {@link ChatFrame}, or `null` when the payload is * malformed (non-JSON, or missing required fields) so callers can skip it without crashing. */ export declare function decodeFrame(event: SseEvent): ChatFrame | null; /** * Folds a renderable {@link ChatFrame} (text or component) into the message's parts, concatenating * consecutive text deltas into the trailing text part and appending components in order. A * `step-start` closes the text before it with a paragraph break ({@link STEP_SEPARATOR}), so two * model steps never run into each other. * `meta`/`elicitation`/`approval`/`done` are control frames and are ignored here — a form to put to * the user is not a part of the assistant's message. Returns a new array (never mutates the input). */ export declare function foldPart(parts: ChatPart[], frame: ChatFrame): ChatPart[]; /** What separates the text of two consecutive model steps in one message: a paragraph break. */ export declare const STEP_SEPARATOR = "\n\n"; /** * Reads a byte {@link ReadableStream} (a `fetch` `response.body`) as a sequence of raw SSE events, * splitting on the `\n\n` frame separator and buffering partial frames across chunks. Yields only * frames that carry a `data:` payload (keep-alives are dropped). */ export declare function readSseStream(body: ReadableStream<Uint8Array>): AsyncGenerator<SseEvent>; /** The parts with every preview left standing removed — what a finished stream keeps. */ export declare function settleParts(parts: ChatPart[]): ChatPart[]; //# sourceMappingURL=sse.d.ts.map