UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

273 lines (272 loc) 14.8 kB
import type { ToolExecutionOptions } from "ai"; import type { StandardJSONSchemaV1, StandardSchemaV1 } from "#compiled/@standard-schema/spec/index.js"; import type { Approval } from "#approval/definition.js"; import type { SessionContext } from "#context/session-context.js"; import type { JsonObject } from "#shared/json.js"; import type { TokenResult } from "#shared/connection-types.js"; import type { ToolAuthOptions, ToolAuthProvider } from "#tools/auth.js"; import type { InputOption } from "#shared/input.js"; import type { ToolModelOutput } from "#tools/model-output.js"; type ApprovalContextInput<TInput> = unknown extends TInput ? Record<string, unknown> : TInput; export type { ToolAuthDefinition, ToolAuthOptions, ToolAuthProvider } from "#tools/auth.js"; export type { ToolModelOutput, ToolModelOutputPart } from "#tools/model-output.js"; export type ToolExecuteOptions = Omit<ToolExecutionOptions<unknown>, "context">; export type ToolExecuteFn<TInput = unknown, TOutput = unknown> = (input: TInput, options: ToolExecuteOptions) => Promise<TOutput> | TOutput | AsyncIterable<TOutput>; export type ToolExecution = "background"; interface ToolDefinitionBase { /** Whether delegated agent sessions receive this tool. Defaults to `true`. */ readonly availableInSubagents?: boolean; readonly description: string; readonly execution?: ToolExecution; } export interface ToolLabelDefinition<TInput = unknown, TOutput = unknown> { /** Returns the presentation-safe label when one action invocation starts. */ start(input: Readonly<TInput>): string; /** Projects one preliminary output snapshot into presentation-safe label text. */ delta?(input: Readonly<TInput>, partial: Readonly<TOutput>): string; /** Projects a successful final output into presentation-safe settlement text. */ complete?(input: Readonly<TInput>, output: Readonly<TOutput>): string; } /** * Internal/compiled tool definition shape. Carries `name` because the * compiler stamps a path-derived identifier onto every tool entry. * * Authored public definitions (see {@link PublicToolDefinition}) do not * carry `name`; identity comes from the file path. */ export interface InternalToolLabelDefinition { readonly complete?: (input: unknown, output: unknown) => string; readonly delta?: (input: unknown, partial: unknown) => string; readonly start?: (input: unknown) => string; } export interface InternalToolDefinition extends ToolDefinitionBase { label?: InternalToolLabelDefinition; name: string; inputSchema: JsonObject | null; outputSchema?: JsonObject; } export type PublicToolInputSchema<TInput = unknown> = StandardSchemaV1<unknown, TInput> | StandardJSONSchemaV1<unknown, TInput> | JsonObject; export type PublicToolOutputSchema<TOutput = unknown> = StandardJSONSchemaV1<unknown, TOutput> | JsonObject; /** * Authored public tool definition shape. Identity is derived from the * file path at compile time, so `name` is intentionally absent here. */ export interface PublicToolDefinition<TInput = unknown, TOutput = unknown> extends ToolDefinitionBase { label?: ToolLabelDefinition<TInput, TOutput>; inputSchema: PublicToolInputSchema<TInput>; /** * Optional schema describing the value returned by the tool executor. * The AI SDK can use this for tool result typing. */ outputSchema?: PublicToolOutputSchema<TOutput>; /** Derives the input-scoped key recorded when this tool is approved. */ approvalKey?: (input: Readonly<ApprovalContextInput<TInput>>) => string; } export interface InternalToolDefinitionWithExecuteFn<TInput = unknown, TOutput = unknown> extends InternalToolDefinition { execute: ToolExecuteFn<TInput, TOutput>; } export interface PublicToolDefinitionWithExecuteFn<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TOutput> { execute: ToolExecuteFn<TInput, TOutput>; } /** * A question a workflow tool asks the human on the session's channel, sent * with `ctx.ask` from a `defineWorkflowTool` executor. Channels render it the * way they render tool approvals. */ export interface ToolInputRequest { /** * Whether the user may answer with free text instead of one of the * {@link options}. */ readonly allowFreeform?: boolean; /** * Whether the user's next message may skip the question. When `true`, a * message that does not answer it resolves the request as `dismissed`, and * the message reaches the agent as usual. */ readonly dismissible?: boolean; /** Rendering hint: confirmation buttons, a selection list, or a text field. */ readonly display?: "confirmation" | "select" | "text"; /** Selectable answers. */ readonly options?: readonly InputOption[]; readonly prompt: string; } /** * The outcome of a {@link ToolInputRequest}. * * - `answered`: the user picked an option or typed an answer. * - `dismissed`: the user moved on without answering a `dismissible` request. * - `unavailable`: the session cannot reach a human, such as a scheduled run, * so the request resolved immediately without being shown. */ export type ToolInputResponse = { readonly status: "answered"; /** The selected option's `id`, when the user picked one. */ readonly optionId?: string; /** Free text, when the user typed an answer. */ readonly text?: string; } | { readonly status: "dismissed"; } | { readonly status: "unavailable"; }; /** * Authored tool context. Passed as the last argument to * {@link ToolDefinition.execute}. * * Extends {@link SessionContext} with token accessors. Passing a provider * resolves that provider inline, which lets one tool use multiple credentials. * * Workflow tools use the separate `WorkflowToolContext` provided by * `defineWorkflowTool`. */ export type ToolContext = SessionContext & { /** * Aborts when the work this tool is doing is cancelled: the active turn * for an ordinary tool, the durable run for a workflow tool. In a workflow * body the signal is durable — it survives replay and steps that receive it * observe the abort — and the run waits a grace period for the body to * unwind through `finally` before it ends. */ readonly abortSignal: AbortSignal; /** * Id of the current tool call — the same `callId` carried by the call's * stream events and its {@link ApprovalContext}. */ readonly callId: string; /** * Final runtime name of the current tool, including any namespace * qualification. This is the same `toolName` carried by stream events and * the tool's {@link ApprovalContext}. */ readonly toolName: string; /** * Resolves the bearer token for an inline provider. This accepts the same * auth shapes as a connection's `auth` field, including `connect("...")` * from `@vercel/connect/eve`. */ getToken(provider: ToolAuthProvider, options?: ToolAuthOptions): Promise<TokenResult>; /** * Signals that the caller must complete authorization for an inline * provider before proceeding. Use this after a downstream `401` rejects a * token returned by {@link getToken}. */ requireAuth(provider: ToolAuthProvider, options?: ToolAuthOptions): never; }; /** * Public tool definition authored in `agent/tools/*.ts`. * * The tool's runtime name is the filename slug under `agent/tools/` without * the extension (`agent/tools/get_weather.ts` registers as `get_weather`). * Authored definitions have no `name` field; identity is path-derived. */ export interface ToolDefinition<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TOutput> { readonly execution?: never; execute(input: TInput, ctx: ToolContext): Promise<TOutput> | TOutput | AsyncIterable<TOutput>; /** * Optional per-tool approval gate. The return value determines whether * user approval is required before executing this tool. * * Use the helpers from `eve/tools/approval` for common cases: * - {@link always}: always require approval * - {@link never}: never require approval * - {@link once}: require approval only the first time per session */ approval?: Approval<ApprovalContextInput<TInput>>; /** * Optional projection controlling what the model sees as the tool result. * Receives the full `TOutput` from {@link execute} and returns the * model-facing {@link ToolModelOutput}. * * When omitted, the model sees the full `execute` return value * (default AI SDK serialization). Channel event handlers * (`action.result`) always receive the full output regardless. */ toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>; } type ToolOutputFromExecuteReturn<TReturn> = TReturn extends Promise<infer TOutput> ? TOutput : TReturn extends AsyncIterable<infer TOutput> ? TOutput : TReturn; type ToolDefinitionWithExecuteReturn<TInput, TOutput, TReturn> = ToolDefinition<TInput, TOutput> & { execute(input: TInput, ctx: ToolContext): TReturn; }; /** * Defines a tool configuration, used both for static tools (default export * from `agent/tools/*.ts`) and as the entry wrapper inside `defineDynamic` * resolvers. * * For static tools, the runtime tool name is the filename slug. `defineTool` * stamps a brand that lifecycle code validates; it rejects raw object literals. */ export declare function defineTool<TInputSchema extends StandardSchemaV1<unknown, unknown> | StandardJSONSchemaV1<unknown, unknown>, TOutputSchema extends StandardJSONSchemaV1<unknown, unknown>, TReturn extends Promise<StandardJSONSchemaV1.InferOutput<TOutputSchema>> | StandardJSONSchemaV1.InferOutput<TOutputSchema> | AsyncIterable<StandardJSONSchemaV1.InferOutput<TOutputSchema>>>(definition: { description: ToolDefinition<unknown, unknown>["description"]; inputSchema: TInputSchema; outputSchema: TOutputSchema; execute(input: StandardSchemaV1.InferOutput<TInputSchema>, ctx: ToolContext): TReturn; label?: ToolDefinition<StandardSchemaV1.InferOutput<TInputSchema>, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["label"]; approval?: ToolDefinition<StandardSchemaV1.InferOutput<TInputSchema>, unknown>["approval"]; approvalKey?: ToolDefinition<StandardSchemaV1.InferOutput<TInputSchema>, unknown>["approvalKey"]; toModelOutput?: ToolDefinition<unknown, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["toModelOutput"]; }): ToolDefinitionWithExecuteReturn<StandardSchemaV1.InferOutput<TInputSchema>, StandardJSONSchemaV1.InferOutput<TOutputSchema>, TReturn>; export declare function defineTool<TSchema extends StandardSchemaV1<unknown, unknown> | StandardJSONSchemaV1<unknown, unknown>, TReturn>(definition: { description: ToolDefinition<unknown, unknown>["description"]; inputSchema: TSchema; outputSchema?: JsonObject; execute(input: StandardSchemaV1.InferOutput<TSchema>, ctx: ToolContext): TReturn; label?: ToolDefinition<StandardSchemaV1.InferOutput<TSchema>, ToolOutputFromExecuteReturn<TReturn>>["label"]; approval?: ToolDefinition<StandardSchemaV1.InferOutput<TSchema>, unknown>["approval"]; approvalKey?: ToolDefinition<StandardSchemaV1.InferOutput<TSchema>, unknown>["approvalKey"]; toModelOutput?: ToolDefinition<unknown, ToolOutputFromExecuteReturn<TReturn>>["toModelOutput"]; }): ToolDefinitionWithExecuteReturn<StandardSchemaV1.InferOutput<TSchema>, ToolOutputFromExecuteReturn<TReturn>, TReturn>; export declare function defineTool<TOutputSchema extends StandardJSONSchemaV1<unknown, unknown>, TReturn extends Promise<StandardJSONSchemaV1.InferOutput<TOutputSchema>> | StandardJSONSchemaV1.InferOutput<TOutputSchema> | AsyncIterable<StandardJSONSchemaV1.InferOutput<TOutputSchema>>>(definition: { description: ToolDefinition<unknown, unknown>["description"]; inputSchema: JsonObject; outputSchema: TOutputSchema; execute(input: Record<string, unknown>, ctx: ToolContext): TReturn; label?: ToolDefinition<Record<string, unknown>, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["label"]; approval?: ToolDefinition<Record<string, unknown>, unknown>["approval"]; approvalKey?: ToolDefinition<Record<string, unknown>, unknown>["approvalKey"]; toModelOutput?: ToolDefinition<unknown, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["toModelOutput"]; }): ToolDefinitionWithExecuteReturn<Record<string, unknown>, StandardJSONSchemaV1.InferOutput<TOutputSchema>, TReturn>; export declare function defineTool<TReturn>(definition: { description: ToolDefinition<unknown, unknown>["description"]; inputSchema: JsonObject; outputSchema?: JsonObject; execute(input: Record<string, unknown>, ctx: ToolContext): TReturn; label?: ToolDefinition<Record<string, unknown>, ToolOutputFromExecuteReturn<TReturn>>["label"]; approval?: ToolDefinition<Record<string, unknown>, unknown>["approval"]; approvalKey?: ToolDefinition<Record<string, unknown>, unknown>["approvalKey"]; toModelOutput?: ToolDefinition<unknown, ToolOutputFromExecuteReturn<TReturn>>["toModelOutput"]; }): ToolDefinitionWithExecuteReturn<Record<string, unknown>, ToolOutputFromExecuteReturn<TReturn>, TReturn>; export declare function defineTool<TInput = unknown, TOutput = unknown>(definition: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>; export declare function stampToolDefinition<T extends { readonly description: string; readonly inputSchema?: unknown; readonly outputSchema?: unknown; readonly execute: (...args: never[]) => unknown; readonly label?: ToolLabelDefinition; readonly approval?: Approval<never>; readonly approvalKey?: (...args: never[]) => unknown; readonly toModelOutput?: (...args: never[]) => unknown; }>(definition: T, definer: "defineTool" | "defineWorkflowTool"): T; /** * Marker discriminator written into every {@link DisabledToolSentinel}. */ declare const DISABLED_TOOL_SENTINEL_KIND = "eve:disabled-tool"; /** * Marker value returned from {@link disableTool}. Export this as the default * export of a file in `agent/tools/` to remove the model tool whose name * matches the file's slug, including framework defaults and derived subagent * tools. */ export interface DisabledToolSentinel { readonly kind: typeof DISABLED_TOOL_SENTINEL_KIND; } /** * Returns a sentinel that disables the model tool whose name matches the * containing file's slug. */ export declare function disableTool(): DisabledToolSentinel; /** * Type guard: returns whether `value` is a {@link DisabledToolSentinel} * produced by {@link disableTool}. */ export declare function isDisabledToolSentinel(value: unknown): value is DisabledToolSentinel;