UNPKG

@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
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