UNPKG

@adonis-agora/agent

Version:

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

163 lines • 7.53 kB
import type { ActionProposal, ActionProposalMutationResult } from '../spi/action-proposal-store.js'; import type { UiCapabilities } from '../ui-capabilities.js'; import { type ChatFrame, type ChatPart } from './sse.js'; /** * Body of `POST /agent/chat` (shape accepted by the provider → `AgentService.chat`). `message` is * required; everything else is optional context. `pageContext` reaches the tools' ctx (not the model * prompt) and is rebuilt from each turn's input, so send it on every message, not just the first. */ export interface AgentChatRequestBody { message: string; threadId?: string; agent?: string; persona?: string; pageContext?: { kind?: string; [key: string]: unknown; }; uiCapabilities?: UiCapabilities; /** Uploads named by id alone (`POST <base>/attachments` answered them). */ attachments?: unknown[]; /** Run THIS turn on a catalog model (`GET <base>/models`). Never pins it on the thread. */ model?: string; /** * Answer the thread's last user message again (needs `threadId`; `message` is ignored): the * server drops the old answer and streams a new one under a new run. */ regenerate?: true; /** * What to do when the thread already has a turn running: `'auto'` (default — run now, else wait * in the thread's queue), `'queue'` (always queue), `'interrupt'` (cancel the running turn and run * this next). A queued send answers `202` — see {@link AgentChatQueued}. */ mode?: 'auto' | 'queue' | 'interrupt'; } /** * What `POST {basePath}/chat` answers (`202`) when the message waits in its thread's queue instead * of running: nothing streams. `runId` is present when it started straight away (attach with * {@link AgentChatClient.resume}); otherwise it runs — under `messageId` as its run id — once the * turn ahead of it settles, announced by a `queue` event with `started` in that turn's stream. */ export interface AgentChatQueued { queued: true; threadId: string; messageId: string; /** 0-based place in the queue (`0` → runs next). */ position: number; queue: { items: { id: string; content: string; [key: string]: unknown; }[]; paused: unknown; }; runId?: string; /** The run an interrupt cancelled to make room for it. */ interrupting?: string; } /** Options for {@link createAgentChatClient}. */ export interface AgentChatClientOptions { /** * Base path the provider mounted its routes under (`POST {basePath}/chat`, * `GET {basePath}/chat/:runId/stream`). Defaults to `/agent`. */ basePath?: string; /** `fetch` implementation to use. Defaults to `globalThis.fetch`. */ fetch?: typeof fetch; /** * Extra headers merged into every request — e.g. an anti-CSRF token (`{ 'X-XSRF-TOKEN': ... }`). * Called per request so a rotating token is always read fresh. */ getHeaders?: () => Record<string, string>; /** Reconnection policy for a dropped stream, or `false` to disable and fail on the first drop. */ resume?: AgentChatResumeOptions | false; } /** Reconnection policy: how many times to re-attach, and the backoff before each attempt. */ export interface AgentChatResumeOptions { /** Max consecutive re-attach attempts before giving up. Defaults to 6. */ maxAttempts?: number; /** Backoff before attempt `n` (1-based), in ms. Defaults to `min(400 * n, 3000)`. */ backoffMs?: (attempt: number) => number; } /** Callbacks fired while a stream is consumed. All optional. */ export interface AgentChatHandlers { /** The assistant message's parts so far, rebuilt on every frame (safe to render directly). */ onParts?: (parts: ChatPart[]) => void; /** Each decoded renderable/control frame, in wire order. */ onFrame?: (frame: ChatFrame) => void; /** The run id, as soon as it is known (response header, then the `meta` frame). */ onRunId?: (runId: string) => void; /** The thread id, as soon as it is known. */ onThreadId?: (threadId: string) => void; } /** Arguments to {@link AgentChatClient.send}. */ export interface AgentChatSendOptions extends AgentChatHandlers { body: AgentChatRequestBody; signal?: AbortSignal; } /** The settled result of a completed chat turn. */ export interface AgentChatResult { runId?: string; threadId?: string; parts: ChatPart[]; /** Present when the server queued the message instead of streaming a reply (`202`). */ queued?: AgentChatQueued; proposalDecision?: ActionProposalMutationResult | { status: 'ambiguous'; proposalIds: string[]; }; } /** * Thrown when a run's stream dropped and could not be resumed within the retry budget. Carries the * partial parts received so far (and the ids) so a consumer can keep what streamed and surface a * "couldn't finish, try again" state instead of losing the message. */ export declare class AgentChatDisconnectedError extends Error { readonly runId: string | undefined; readonly threadId: string | undefined; readonly parts: ChatPart[]; constructor(runId: string | undefined, threadId: string | undefined, parts: ChatPart[]); } /** * The server refused the request before any stream started — a non-2xx answer. `message` is the * server's own words (`{ message, code? }`, the body every refusal answers), `code` its * machine-readable reason (`quota_exceeded`, `model_not_allowed`, `thread_required`, …) and `body` * the parsed answer, or `undefined` when it was not JSON. */ export declare class AgentChatHttpError extends Error { readonly status: number; readonly code: string | undefined; readonly body: unknown; constructor(status: number, message: string, code: string | undefined, body: unknown); } /** * The server ended the run with `event: error` (agent protocol). Not a dropped connection: the run * is over, so it is surfaced rather than re-attached. `code` is the server's (`quota_exceeded`, * `output_rejected`, `structured_output_invalid`, `run_failed`). */ export declare class AgentChatStreamError extends Error { readonly code: string; constructor(code: string, message: string); } /** * A framework-agnostic client for the agent chat SSE endpoints. `send` posts a turn and streams the * reply; if the connection drops before the run finishes, it re-attaches to * `GET {basePath}/chat/:runId/stream` — which replays the whole stream from the start and follows live * — with backoff, until the run emits `done` or the retry budget is exhausted. The run itself is * durable and keeps executing server-side across the drop, so no tokens are lost. */ export interface AgentChatClient { send(options: AgentChatSendOptions): Promise<AgentChatResult>; listActionProposals(threadId: string, signal?: AbortSignal): Promise<ActionProposal[]>; decideActionProposal(threadId: string, proposalId: string, decision: 'approved' | 'rejected', command?: { remember?: boolean; reason?: string; }, signal?: AbortSignal): Promise<ActionProposalMutationResult>; /** Re-attach to an already-started run (e.g. after a fresh page load) and stream it to completion. */ resume(runId: string, options?: AgentChatHandlers & { signal?: AbortSignal; }): Promise<AgentChatResult>; } export declare function createAgentChatClient(options?: AgentChatClientOptions): AgentChatClient; //# sourceMappingURL=chat-client.d.ts.map