UNPKG

@adonis-agora/agent

Version:

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

147 lines • 7.42 kB
import type { StandardSchemaV1 } from '@standard-schema/spec'; import type { AiToolCtx, ToolHandler } from './spi/tool.js'; import type { ToolPresentation } from './tool-presentation.js'; import type { Actor, ToolSpec } from './types.js'; /** * The symbol the `@AiTool` decorator stamps its options onto (the tool class), read back by * discovery to register the class into the {@link import('./tool-registry.js').ToolRegistry}. A * global-registry symbol (`Symbol.for`) so it survives duplicate copies of this package in a tree. */ export declare const AI_TOOL_META_KEY: unique symbol; /** * Brand stamped on the object {@link defineTool} returns so discovery picks it up when it walks a * module's exports — the functional alternative to an `@AiTool` class. */ export declare const AGENT_TOOL_BRAND: unique symbol; export interface AiToolOptions { /** * What the model calls it. Omit on a class → the class name, camelCased, with a trailing `Tool` * dropped (`GetWeatherTool` → `getWeather`). Required on {@link defineTool}, which has no class. */ name?: string; /** * `read` auto-executes; `action` requires HITL approval. Default `'read'`. (Core's `ToolKind` also * has `agent` for delegation, but that kind is synthesized from an agent's `delegatesTo` — never * authored here.) */ kind?: 'read' | 'action'; description: string; /** * Input schema as a [Standard Schema](https://standardschema.dev) — Zod, Valibot, or ArkType. * Validated (again) before the handler runs. */ input: StandardSchemaV1; /** Roles allowed to invoke. Omit to inherit the config's `defaultRoles` (unrestricted by default). */ roles?: string[]; /** * Authz ability checked by an ability-aware `RolesPolicy` (e.g. an `@adonis-agora/authz` Bouncer * adapter → `bouncer.forUser(actor).allows(ability)`). Ignored by the default role-based policy. */ ability?: string; /** * Whether this tool exists in this deployment. `false` — or a predicate returning `false`, which * is re-evaluated every turn — drops it before the role filter, so the model is never shown it. * Omit → enabled. * * Use this for availability that is knowable without the container (a constant, `env.get(...)`, a * closure over something the app already holds). When the answer lives in an injected service, * implement `isEnabled()` on the tool class instead: this object is built at import time and * cannot reach the container. */ enabled?: boolean | (() => boolean | Promise<boolean>); /** * How a chat surface talks about this tool without naming it — sentence templates over the call's * input, an icon key, the approval prompt's wording, and how its output reads. Never shown to the * model. Served by `GET <path>/tools` to the actors who can reach the tool: * * ```ts * presentation: { * label: 'Cache purge', running: 'Purging {key}', done: 'Purged {key}', icon: 'cache', * tone: 'destructive', confirm: { title: 'Purge {key}?', verb: 'Purge' }, * } * ``` */ presentation?: ToolPresentation; replacementKey?: ToolSpec['replacementKey']; /** A successful call ends the turn — no model call narrates what it already showed. */ terminal?: boolean; } /** * The metadata a tool class carries for discovery + registration — from `@AiTool` or `static tool` — * with the defaults applied. */ export type AiToolMeta = AiToolOptions & { name: string; kind: 'read' | 'action'; }; /** `GetWeatherTool` → `getWeather`; `SQLQueryTool` → `sqlQuery`. */ export declare function toolNameFromClass(className: string): string; /** Structural shape of a tool class: a constructor whose instance implements `execute`. */ export type ToolClass = abstract new (...args: never[]) => ToolHandler; /** * Marks a class as an AI tool. The class must implement `execute(input, ctx)`. The provider's * `app/agent_tools` discovery (or the generated `hooks/tools` barrel) registers every `@AiTool` * class into the shared `ToolRegistry` at boot. * * ```ts * @AiTool({ name: 'getWeather', kind: 'read', description: '...', input: z.object({ city: z.string() }) }) * export default class GetWeatherTool implements ToolHandler<{ city: string }> { * async execute(input: { city: string }, ctx: AiToolCtx) { return { tempC: 21 } } * } * ``` */ export declare function AiTool(options: AiToolOptions): <T extends ToolClass>(target: T) => T; /** * Read a tool class's {@link AiToolMeta}. Two authoring forms are supported: * * 1. The `@AiTool({ … })` decorator (stamps {@link AI_TOOL_META_KEY}). * 2. A decorator-free `static tool = { name, kind, description, input, … }` config on the class — the * same shape, mirroring `@adonis-agora/durable`'s `static workflow`. Preferred where you'd rather * not rely on decorators. * * Accepts either the class itself or an instance: each mechanism is tried on the value, then on its * constructor (so an instance resolves the class's metadata). */ export declare function readAiToolMeta(target: unknown): AiToolMeta | undefined; /** * What {@link defineTool} takes: the `@AiTool` options with a required `name`, plus the per-actor * gate a class would implement as a `canUse()` method. */ export interface DefineToolOptions extends AiToolOptions { name: string; /** * Whether THIS actor may use the tool, decided per turn — after `enabled` and the `RolesPolicy`, * on both the offered list and the invoke. For a decision the app-wide policy cannot express (the * actor's plan, an entitlement row, ownership of the record). Omit → the role gate alone decides. */ canUse?: (actor: Actor) => boolean | Promise<boolean>; } /** A tool expressed as data + handler (from {@link defineTool}), not an `@AiTool` class. */ export interface FunctionalTool { spec: ToolSpec; handler: ToolHandler; } /** A {@link FunctionalTool} carrying {@link AGENT_TOOL_BRAND} — what {@link defineTool} returns. */ export interface BrandedFunctionalTool extends FunctionalTool { readonly [AGENT_TOOL_BRAND]: true; } /** Narrows an arbitrary module export to a branded functional tool for boot-time registration. */ export declare function isBrandedFunctionalTool(value: unknown): value is BrandedFunctionalTool; /** * The functional form of a tool: pass the same options as `@AiTool` plus an `execute` function, get * back a branded `{ spec, handler }` that discovery auto-registers. Export it from an `app/agent_tools` * module (or pass it to `defineConfig({ tools })`). * * ```ts * export const purgeCache = defineTool( * { name: 'purgeCache', kind: 'action', description: '...', input: z.object({ key: z.string() }) }, * async ({ key }, ctx) => { ... }, * ) * ``` */ export type DefineToolObjectOptions<S extends StandardSchemaV1, O> = Omit<DefineToolOptions, 'input'> & { input: S; } & ToolHandler<StandardSchemaV1.InferOutput<S>, O>; export declare function defineTool<S extends StandardSchemaV1, O>(options: DefineToolObjectOptions<S, O>): BrandedFunctionalTool; export declare function defineTool<I = unknown, O = unknown>(options: DefineToolOptions, execute: ((input: I, ctx: AiToolCtx) => Promise<O> | O) | ToolHandler<I, O>): BrandedFunctionalTool; //# sourceMappingURL=ai-tool-ref.d.ts.map