eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
278 lines (277 loc) • 13.7 kB
TypeScript
import type { StandardJSONSchemaV1 } from "#compiled/@standard-schema/spec/index.js";
import type { PublicToolDefinition, ToolModelOutput } from "#shared/tool-definition.js";
import type { SessionContext } from "#public/definitions/callback-context.js";
import type { Approval } from "#public/definitions/approval.js";
import type { JsonObject } from "#shared/json.js";
import type { AuthorizationDefinition, ConnectionAuthorizationContext, NonInteractiveAuthorizationDefinition, TokenResult } from "#runtime/connections/types.js";
import { type DynamicEvents, type DynamicEventsWithFallback, type DynamicSentinel } from "#shared/dynamic-tool-definition.js";
type ApprovalContextInput<TInput> = unknown extends TInput ? Record<string, unknown> : TInput;
type DynamicEventMapHandler<TEvents extends DynamicEvents> = Extract<NonNullable<TEvents[keyof TEvents]>, (...args: never[]) => unknown>;
type DynamicEventMapResult<TEvents extends DynamicEvents> = Awaited<ReturnType<DynamicEventMapHandler<TEvents>>>;
export type { ToolModelOutput } from "#shared/tool-definition.js";
/**
* Authorization provider passed to {@link ToolContext.getToken} or
* {@link ToolContext.requireAuth}. Accepts the same shapes as a connection's
* `auth`:
* - a `getToken`-only object (static API keys, pre-provisioned JWTs);
* `principalType` may be omitted and defaults to `"app"`.
* - a full interactive OAuth definition (e.g. `connect("okta/myagent")` from
* `@vercel/connect/eve`, or {@link defineInteractiveAuthorization}).
*/
export type ToolAuthDefinition = (Omit<NonInteractiveAuthorizationDefinition, "principalType"> & {
readonly principalType?: NonInteractiveAuthorizationDefinition["principalType"];
}) | AuthorizationDefinition;
export type ToolAuthProvider = ToolAuthDefinition;
/**
* Controls Eve runtime behavior for an inline tool auth provider.
*/
export interface ToolAuthOptions {
/**
* Connection metadata passed through to provider callbacks. Tool-only
* providers usually leave this unset; connection-backed helpers can use it
* to receive the upstream server URL.
*/
readonly connection?: ConnectionAuthorizationContext;
/**
* Optional human-readable provider name shown in sign-in UI. Presentation
* only; it does not affect OAuth scopes, token cache keys, or callback URLs.
*/
readonly displayName?: string;
/**
* Optional Eve auth-flow key for token caches, callback URLs, pending
* authorization state, and authorization completion. This is not an OAuth
* scope. For Vercel Connect OAuth targeting such as `scopes`, `resources`,
* or `authorizationDetails`, configure the provider with
* `connect({ connector, tokenParams })`.
*/
readonly authKey?: string;
}
/**
* 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.
*/
export type ToolContext = SessionContext & {
/** Aborts when the active turn is cancelled. */
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> {
execute(input: TInput, ctx: ToolContext): Promise<TOutput> | 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>;
}
/**
* 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 StandardJSONSchemaV1<unknown, unknown>, TOutputSchema extends StandardJSONSchemaV1<unknown, unknown>>(definition: {
description: ToolDefinition<unknown, unknown>["description"];
inputSchema: TInputSchema;
outputSchema: TOutputSchema;
execute(input: StandardJSONSchemaV1.InferOutput<TInputSchema>, ctx: ToolContext): Promise<StandardJSONSchemaV1.InferOutput<TOutputSchema>> | StandardJSONSchemaV1.InferOutput<TOutputSchema>;
approval?: ToolDefinition<StandardJSONSchemaV1.InferOutput<TInputSchema>, unknown>["approval"];
toModelOutput?: ToolDefinition<unknown, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["toModelOutput"];
}): ToolDefinition<StandardJSONSchemaV1.InferOutput<TInputSchema>, StandardJSONSchemaV1.InferOutput<TOutputSchema>>;
export declare function defineTool<TSchema extends StandardJSONSchemaV1<unknown, unknown>, TOutput>(definition: {
description: ToolDefinition<unknown, unknown>["description"];
inputSchema: TSchema;
outputSchema?: JsonObject;
execute(input: StandardJSONSchemaV1.InferOutput<TSchema>, ctx: ToolContext): Promise<TOutput> | TOutput;
approval?: ToolDefinition<StandardJSONSchemaV1.InferOutput<TSchema>, unknown>["approval"];
toModelOutput?: ToolDefinition<unknown, TOutput>["toModelOutput"];
}): ToolDefinition<StandardJSONSchemaV1.InferOutput<TSchema>, TOutput>;
export declare function defineTool<TOutputSchema extends StandardJSONSchemaV1<unknown, unknown>>(definition: {
description: ToolDefinition<unknown, unknown>["description"];
inputSchema: JsonObject;
outputSchema: TOutputSchema;
execute(input: Record<string, unknown>, ctx: ToolContext): Promise<StandardJSONSchemaV1.InferOutput<TOutputSchema>> | StandardJSONSchemaV1.InferOutput<TOutputSchema>;
approval?: ToolDefinition<Record<string, unknown>, unknown>["approval"];
toModelOutput?: ToolDefinition<unknown, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["toModelOutput"];
}): ToolDefinition<Record<string, unknown>, StandardJSONSchemaV1.InferOutput<TOutputSchema>>;
export declare function defineTool<TOutput>(definition: {
description: ToolDefinition<unknown, unknown>["description"];
inputSchema: JsonObject;
outputSchema?: JsonObject;
execute(input: Record<string, unknown>, ctx: ToolContext): Promise<TOutput> | TOutput;
approval?: ToolDefinition<Record<string, unknown>, unknown>["approval"];
toModelOutput?: ToolDefinition<unknown, TOutput>["toModelOutput"];
}): ToolDefinition<Record<string, unknown>, TOutput>;
export declare function defineTool<TInput = unknown, TOutput = unknown>(definition: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
/**
* Defines a dynamic resolver evaluated at runtime from stream-event
* handlers. It is shared across three slots, and the directory it is
* authored in (not this function) decides what each handler must return
* and which events are honored. The file's path-derived slug names the
* single-entry case; a `Record<string, ...>` return names entries
* `slug__key`. Return `null` to contribute nothing for that event.
*
* Per-slot return shape:
* - `agent/tools/`: return a single `defineTool(...)`, a
* `Record<string, defineTool(...)>`, or `null`.
* - `agent/skills/`: return a single `defineSkill(...)`, a
* `Record<string, defineSkill(...)>`, or `null`.
* - `agent/instructions/`: return a single `defineInstructions({ markdown })`,
* which lowers to one `{ role: "system", content: markdown }` message,
* or `null`. (Maps are not meaningful here.)
*
* Per-slot events: tools resolvers run at `session.started`,
* `turn.started`, and `step.started`. Instructions and skills resolvers
* contribute to the system prompt, so for cache stability they run only
* at `session.started` and `turn.started`; the runtime never invokes a
* handler keyed on `step.started` in those slots.
*
* ```ts
* import { defineDynamic, defineTool } from "eve/tools";
* import { z } from "zod";
*
* export default defineDynamic({
* events: {
* "session.started": async (event, ctx) => ({
* export: defineTool({
* description: "Export data",
* inputSchema: z.object({ format: z.string() }),
* async execute(input) {
* return doExport(input.format);
* },
* }),
* }),
* },
* });
* ```
*
* A single return is named after the file slug. A map names each entry by its
* bare key — there is no automatic slug prefix, so namespace keys yourself
* (e.g. `team__playbook`) when a bare name might collide. A dynamic tool/skill
* whose name matches an authored one overrides it; two dynamic resolvers
* emitting the same name is an error.
*/
export declare function defineDynamic<const TEvents extends DynamicEvents>(definition: {
readonly events: TEvents;
}): DynamicSentinel<DynamicEventMapResult<TEvents>>;
export declare function defineDynamic<const TEvents extends DynamicEventsWithFallback, TFallback = unknown>(definition: {
readonly fallback: TFallback;
readonly events: TEvents;
}): DynamicSentinel<Exclude<DynamicEventMapResult<TEvents>, undefined>, TFallback>;
/**
* 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 framework default whose
* name matches the file's slug.
*/
export interface DisabledToolSentinel {
readonly kind: typeof DISABLED_TOOL_SENTINEL_KIND;
}
/**
* Returns a sentinel that disables the framework 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;
/**
* Discriminator written into definitions returned by
* {@link experimental_workflow}.
*/
declare const EXPERIMENTAL_WORKFLOW_TOOL_KIND = "eve:enable-workflow-tool";
/**
* Configuration accepted by {@link experimental_workflow}.
*/
export interface ExperimentalWorkflowToolInput {
/**
* Maximum number of subagent or remote-agent calls one `Workflow` program
* may dispatch, counted across sequential and parallel calls alike.
*
* Calls beyond the limit fail with a `WORKFLOW_SUBAGENT_LIMIT_REACHED`
* result instead of starting a child session.
*
* @default 100
*/
readonly maxSubagents?: number;
}
/**
* Framework `Workflow` tool definition returned by
* {@link experimental_workflow}.
*/
export interface ExperimentalWorkflowToolDefinition extends ExperimentalWorkflowToolInput {
readonly kind: typeof EXPERIMENTAL_WORKFLOW_TOOL_KIND;
}
/**
* Enables and configures the experimental framework `Workflow` tool, an
* isolated JavaScript sandbox whose only callable operations are this agent's
* subagents and remote agents. Export the result from
* `agent/tools/workflow.ts`:
*
* ```ts
* import { experimental_workflow } from "eve/tools";
*
* export default experimental_workflow({ maxSubagents: 25 });
* ```
*
* Only the root session sees the tool. The resulting model-facing tool is
* still called `Workflow`.
*/
export declare function experimental_workflow(input?: ExperimentalWorkflowToolInput): ExperimentalWorkflowToolDefinition;
/**
* Type guard for a definition returned by {@link experimental_workflow}.
*/
export declare function isExperimentalWorkflowToolDefinition(value: unknown): value is ExperimentalWorkflowToolDefinition;