@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
176 lines • 9.73 kB
TypeScript
import type { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec';
import type { ToolHandler } from '../spi/tool.js';
import type { ToolPresentation } from '../tool-presentation.js';
import type { Actor, ToolSpec } from '../types.js';
import { type Catalog, type GenuiStreaming } from './catalog.js';
import { type GenuiChannels } from './channels.js';
import { type DefineSandboxOptions } from './sandbox.js';
import { type GenuiIssue, type JsonSchema } from './schema.js';
import { type TreeLimits, type TreeSchemaMode } from './tree.js';
/** A lib tool: register it with `aiTool(tool)` (AdonisJS) or `registry.register(tool.spec, tool.handler)`. */
export interface GenuiTool {
spec: ToolSpec & {
terminal?: boolean;
};
handler: ToolHandler;
}
/** What a genui tool returns to the model: what was pushed, and the `ui` frame's id. */
export interface GenuiToolOutput {
shown: string;
id: string;
/** What a check found that did not refuse the call (a prop the kit component does not declare). */
warnings?: string[];
}
/**
* Who a catalog is being resolved for. `tenant` is `actor.tenantRef`. `threadId` is absent only
* when a tool list is built outside a conversation (the MCP server's `tools/list`).
*/
export interface GenuiCatalogScope {
actor: Actor;
threadId?: string;
tenant?: string;
agentName?: string;
/** The channel the turn runs on (`web`, `whatsapp`, …), when known. */
channel?: string;
}
/** Answers which catalog applies to a request — a tenant's own, versioned components. */
export type ResolveGenuiCatalog = (scope: GenuiCatalogScope) => Catalog | Promise<Catalog>;
export interface GenuiToolsOptions {
/**
* `tree` (default): a single `ui__render` tool whose input is a nested `{ type, props, children }`
* tree composed from the catalog (json-render's nested shape). A tree of one component with no
* children is pushed as that component, exactly as its `ui__show_*` tool would push it.
* `per-component`: one tool per model-facing component, `ui__show_<snake>`, whose input IS the
* component's props — for small models, or when each tool should carry its exact schema. Layouts
* (`children: true`) get none: they can only be composed in a tree.
*/
mode?: 'per-component' | 'tree';
/**
* How the tree tool's input schema describes the nodes (see {@link treeJsonSchema}): `'strict'`
* (default) — a recursive union by `type` with each component's exact props; `'loose'` — one
* generic node shape, for a provider that refuses `$ref` in tool parameters.
*/
treeSchema?: TreeSchemaMode;
/**
* The model's turn ends once a genui call succeeds — no further model call to narrate what the UI
* already shows. Stamped as `spec.terminal`.
*/
terminal?: boolean;
/** Tool-name prefix for `per-component`. Default `ui__show_`. */
namePrefix?: string;
/** Tool name for `tree`. Default `ui__render`. */
treeToolName?: string;
/** Extra text prepended to the tree tool's description (when to call it, house rules). */
treeInstructions?: string;
/**
* Tree mode: components that ALSO get a tool of their own whose input IS their props —
* `componentTools: ['Sandbox']` adds `ui__sandbox`. For a big component a model writes on its
* own (the sandbox): with no tree to nest it in, there is no `{ type, props }` envelope to leave
* out. It still streams (`partialProps`) and may still be nested in a `ui__render` tree.
*/
componentTools?: readonly string[];
/** Tool-name prefix for {@link componentTools}. Default `ui__` (`Sandbox` → `ui__sandbox`). */
componentToolPrefix?: string;
/** Size limits for `tree`. */
treeLimits?: TreeLimits;
/**
* Tree mode: whether the layout is drawn WHILE the model writes it.
*
* - `'complete'` (default): nothing is drawn until the call has run; then the validated tree
* appears whole.
* - `'partial'`: the server parses the streaming `ui__render` arguments and pushes the tree so far
* as `partial` `ui` frames under the id the final push replaces — throttled, unvalidated, never
* persisted, never sent to a text channel. Nodes still being written are flagged `incomplete`; a
* component declared `streaming: 'complete'` is a `held` placeholder until its subtree closes.
*
* A component's own {@link ComponentDefinition.streaming} overrides this per component.
*/
streaming?: GenuiStreaming;
/** Least time between two partial tree frames of one call, in ms. Default 100. */
streamingThrottleMs?: number;
/**
* Also offer ONE generic tool taking `{ component, props }`, validated against the (resolved)
* catalog — how a model reaches components that only exist per request (a tenant's own), which a
* boot-time tool list cannot name. `true` names it `ui__show`; a string names it.
*/
showTool?: boolean | string;
/** Extra text prepended to the show tool's description. */
showInstructions?: string;
/** Roles allowed to call the tools (the `ToolSpec.roles` gate). Undefined → the roles policy default. */
roles?: string[];
/**
* The authorization ability the UI tools declare (`ToolSpec.ability`) — what an ability-aware
* authorizer (`authzToolAuthorizer` from `@adonis-agora/agent/authz`) checks the actor against.
* Under such an authorizer a tool with no ability is denied, so without this the UI tools are
* never offered. A string for every tool; a map by tool name (`{ ui__render: 'genui.render',
* ui__sandbox: 'genui.sandbox' }`, a tool it does not name declares none); or a function of the
* tool name and the component it shows (`undefined` for the tree and show tools). The authorizer
* still decides: nothing is allowed by default.
*/
ability?: GenuiAbility;
/** Override the generated presentation per component (or for the tree / show tool, under its tool name). */
presentation?: (component: string) => ToolPresentation | undefined;
/**
* The catalog for THIS request, consulted when a call is validated and when the turn's tool list
* is described to the model. The `catalog` argument is then the boot-time one: it names the
* per-component tools and is what a list built without a resolver would show. Omit → the
* `catalog` argument serves every request.
*/
resolveCatalog?: ResolveGenuiCatalog;
/**
* Per-channel generative UI (see {@link GenuiChannels}): each entry sets the mode, streaming,
* sandbox and rendering of one channel (`web`, `mobile`, `whatsapp`, `telegram`, `email`, or
* `default` for the rest), over the top-level options. The tools of every mode in use are
* registered; each turn is offered only those of its channel's mode, described with what that
* channel can draw. Omitted → every channel is served by the top-level options, as before.
*/
channels?: GenuiChannels;
/**
* The sandbox setting a channel without its own falls back to (`genui({ sandbox })` passes it).
* Only read with {@link channels}: the sandbox itself is a component of `catalog`.
*/
sandbox?: boolean | DefineSandboxOptions;
/**
* Generative-UI telemetry (see `ToolSpec.genui`): every UI call is recorded with its metadata —
* tool, channel, mode, attempt, validity, error category, tokens and cost, time to first and to
* complete frame. NEVER the generated HTML/JSX or props, unless `samplePayloads: true` (for
* debugging; off by default — keep it off where the UI may show personal data). `false` records
* nothing.
*/
telemetry?: GenuiTelemetryOptions | false;
}
/** {@link GenuiToolsOptions.telemetry}. */
export interface GenuiTelemetryOptions {
/** Also store each call's input (the generated code and props). Default `false`. */
samplePayloads?: boolean;
}
/** The default name of the generic show tool ({@link GenuiToolsOptions.showTool}). */
export declare const GENUI_SHOW_TOOL = "ui__show";
/**
* Tools that let a model push catalog components into the conversation as `ui` frames. Each call
* validates its input against the catalog (a refused call reaches the model as a tool error it can
* fix) and then pushes through `ctx.emitUi`, which streams the frame live and persists it on the
* assistant message.
*/
export declare function genuiTools(catalog: Catalog, options?: GenuiToolsOptions): GenuiTool[];
/** {@link GenuiToolsOptions.ability}: one ability, one per tool name, or a function of the tool. */
export type GenuiAbility = string | Readonly<Record<string, string>> | ((tool: {
name: string;
component?: string;
}) => string | undefined);
/** The ability a UI tool declares, from {@link GenuiToolsOptions.ability}. */
export declare function genuiToolAbility(ability: GenuiAbility | undefined, tool: {
name: string;
component?: string;
}): string | undefined;
/** The show tool's input: a component name (one of the catalog's) and its props. */
export declare function showToolJsonSchema(catalog: Catalog): JsonSchema;
type JsonStandardSchema = StandardSchemaV1 & StandardJSONSchemaV1;
/**
* A JSON Schema presented as a Standard Schema WITH the Standard JSON Schema extension, so the lib
* validates tool input through `~standard.validate` and the AI SDK adapter hands the model the
* schema itself (it reads `~standard.jsonSchema.input`).
*/
export declare function jsonStandardSchema(schema: JsonSchema, validate: (value: unknown) => GenuiIssue[]): JsonStandardSchema;
export {};
//# sourceMappingURL=tools.d.ts.map