/** * Agent glue: forge ADK tools from a media pipeline, so a model can drive local media work. * * @module @nhtio/adk/batteries/media/forge * * @remarks * The pipeline core (`@nhtio/adk/batteries/media`) is agent-agnostic; this module is the layer * that knows the ADK loop. {@link forgeMediaTools} mints `Tool` instances over a configured * {@link @nhtio/adk/batteries/media!MediaPipeline} in one of two surfaces (the consumer picks * per deployment): * * - `'composite'` — one `media_query` tool taking `{ media_id, q }` (a pipe expression — the * headline LLM DSL) or `{ media_id, ops }` (structured form), plus `list_media`. The tool * description embeds the engine-narrowed verb grammar so the model never sees a verb the * deployment can't run. One round-trip for multi-step work. * - `'granular'` — one narrow tool per available verb (`doc_select`, `sheet_update_cells`, …), * each internally a one-verb plan. Friendlier to small models; bigger tool list. * * Media flows in by reference: the model passes `media_id` values it discovered via the * `list_media` tool (or inline id markers, where the LLM battery renders them); the resolver * scans `ctx.turnMessages[].attachments` and `ctx.turnToolCalls[].results` by default. Outputs * are persisted through `ctx.storeMediaBytes` and returned as `Media.toolGenerated(...)`, so * file results land on `ToolCall.results` as first-class media. * * Processing failures return readable strings (`Error (CODE): …`) the model can act on; the * pipe DSL's own syntax/semantic errors render the same way, so a model can repair its * statement and retry. An optional {@link ToolGateFn} runs before every execution — the seam * for human-approval/RBAC flows built on `ctx.waitFor` (the ADK gates primitive). */ import { foldVerb } from "./verbs"; import { Tool, Media } from "../../common"; import type { MediaPipeline } from "./index"; import type { DispatchContext } from "../../types"; /** * Resolves a `media_id` to a {@link @nhtio/adk!Media} visible in the current dispatch. * The default implementation scans turn messages' attachments and prior tool-call results. */ export type MediaResolverFn = (ctx: DispatchContext, mediaId: string) => Media | undefined | Promise; /** * Optional per-call gate run before any pipeline execution. Throwing aborts the call and * surfaces through the standard tool-error path. The canonical implementation awaits * `ctx.waitFor({ reason: 'tool_approval', payload: call })` and throws on denial — WHO * approves and HOW is the consumer's contract; this is the seam. */ export type ToolGateFn = (ctx: DispatchContext, call: { tool: string; args: unknown; }) => void | Promise; /** Options for {@link forgeMediaTools}. */ export interface ForgeMediaToolsOptions { /** Which tool surface to mint. */ surface: 'composite' | 'granular'; /** Media-id resolution. Default: scan turn attachments + tool-call Media results. */ resolveMedia?: MediaResolverFn; /** Optional pre-execution gate (see {@link ToolGateFn}). */ gate?: ToolGateFn; /** Per-tool name/description overrides, keyed by the minted tool's default name. */ overrides?: Record; } /** * The default media resolver: scan `ctx.turnMessages[].attachments`, then * `ctx.turnToolCalls[].results`, for a Media with the given id. * * @param ctx - The dispatch context. * @param mediaId - The id to find. * @returns The Media, or `undefined` when nothing in the turn carries that id. */ export declare const defaultResolveMedia: MediaResolverFn; /** * Forge agent tools over a configured media pipeline. * * @remarks * The minted set follows the pipeline's configured engines: in the composite surface the * `media_query` grammar text only advertises available verbs; in the granular surface a tool * is minted only for verbs whose engine (if any) is configured. Either way `list_media` is * included — it is the model's entry point for discovering `media_id` values. * * The returned record is keyed by tool name so consumers can register selectively or pass * `Object.values(tools)` to `TurnRunnerConfig.tools`. * * @param pipeline - A pipeline from `createMediaPipeline`. * @param options - Surface, resolver, gate, and overrides. * @returns The minted tools, keyed by name. */ export declare const forgeMediaTools: (pipeline: MediaPipeline, options: ForgeMediaToolsOptions) => Record; /** Re-exported so consumers can fold verbs the same way the forge does. */ export { foldVerb };