UNPKG

eve

Version:

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

148 lines (147 loc) 8.43 kB
import type { FetchFileResult } from "#channel/adapter.js"; import { CHANNEL_SENTINEL } from "#channel/compiled-channel.js"; import type { TypedReceiveTarget } from "#channel/receive-target.js"; import type { SessionAuthContext } from "#channel/types.js"; import type { HandleMessageStreamEvent } from "#protocol/message.js"; import type { SessionContext } from "#public/definitions/callback-context.js"; import type { RouteDefinition, SendFn } from "#channel/routes.js"; import type { Session, SessionHandle } from "#channel/session.js"; declare const CHANNEL_METADATA_TYPE: unique symbol; export type { Session, SessionHandle } from "#channel/session.js"; export { GET, POST, PUT, PATCH, DELETE, WS } from "#channel/routes.js"; export type { HttpRouteDefinition, RouteDefinition, RouteHandlerArgs, SendFn, SendOptions, SendPayload, GetSessionFn, WebSocketMessage, WebSocketPeer, WebSocketRouteDefinition, WebSocketRouteHandler, WebSocketRouteHooks, WebSocketUpgradeRequest, WebSocketUpgradeResult, } from "#channel/routes.js"; type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessageStreamEvent, { type: T; }> extends { data: infer D; } ? D : undefined; /** * Session operations on the `channel` argument of every channel event handler. */ export interface ChannelSessionOps { readonly continuationToken: string; setContinuationToken(token: string): void; } /** * Channel context passed to event handlers: `TCtx` intersected with * {@link ChannelSessionOps}. */ export type ChannelContext<TCtx> = TCtx & ChannelSessionOps; type ChannelEventHandler<T extends HandleMessageStreamEvent["type"], TCtx> = (data: EventData<T>, channel: ChannelContext<TCtx>, ctx: SessionContext) => void | Promise<void>; type ChannelSessionFailedHandler<TCtx> = (data: EventData<"session.failed">, channel: ChannelContext<TCtx>) => void | Promise<void>; /** * Optional handlers keyed by session lifecycle event name. Each handler receives * the event `data`, the {@link ChannelContext}, and a {@link SessionContext} * `ctx`. The `session.failed` handler is the exception: it receives only `data` * and the channel context, with no `ctx`. */ export interface ChannelEvents<TCtx = void> { readonly "turn.started"?: ChannelEventHandler<"turn.started", TCtx>; readonly "actions.requested"?: ChannelEventHandler<"actions.requested", TCtx>; readonly "action.result"?: ChannelEventHandler<"action.result", TCtx>; readonly "message.completed"?: ChannelEventHandler<"message.completed", TCtx>; readonly "message.appended"?: ChannelEventHandler<"message.appended", TCtx>; readonly "reasoning.appended"?: ChannelEventHandler<"reasoning.appended", TCtx>; readonly "reasoning.completed"?: ChannelEventHandler<"reasoning.completed", TCtx>; readonly "input.requested"?: ChannelEventHandler<"input.requested", TCtx>; readonly "turn.failed"?: ChannelEventHandler<"turn.failed", TCtx>; readonly "turn.completed"?: ChannelEventHandler<"turn.completed", TCtx>; readonly "session.failed"?: ChannelSessionFailedHandler<TCtx>; readonly "session.completed"?: ChannelEventHandler<"session.completed", TCtx>; readonly "session.waiting"?: ChannelEventHandler<"session.waiting", TCtx>; readonly "authorization.required"?: ChannelEventHandler<"authorization.required", TCtx>; readonly "authorization.completed"?: ChannelEventHandler<"authorization.completed", TCtx>; } /** * Input passed to a channel's `receive` callback when another channel or * schedule proactively routes a message to it. */ export interface ReceiveInput<TReceiveTarget = Record<string, unknown>> { readonly message: string; readonly target: Readonly<TReceiveTarget>; readonly auth: SessionAuthContext | null; } /** * The object passed to {@link defineChannel}. `routes` is required; `state` * seeds durable adapter state, `context` builds the per-step `channel` argument * for `events` and `deliver`, `events` handle session lifecycle, `receive` * accepts cross-channel handoffs, `fetchFile` stages remote file URLs, and * `metadata` projects observability data. * * Generics: `TState` (adapter state), `TCtx` (context factory return type), * `TReceiveTarget` (cross-channel target shape), `TMetadata` (instrumentation * projection). */ export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> { readonly state?: TState; /** * Builds the per-step channel context handed to `events` and `deliver`. * Receives the live {@link SessionHandle}, so a factory can close over it to * register late-bound callbacks. eve writes state mutations made inside the * returned context back through `adapter.state`. * * Return the channel-owned context (thread handles, API clients, etc.). The * framework passes it as the `channel` argument to event handlers (with * {@link ChannelSessionOps} injected) and passes {@link SessionContext} as a * separate `ctx` argument. */ context?(state: NonNullable<TState>, session: SessionHandle): TCtx; readonly routes: readonly RouteDefinition<TState>[]; receive?(input: ReceiveInput<TReceiveTarget>, args: { send: SendFn<TState>; }): Promise<Session>; readonly events?: ChannelEvents<TCtx>; /** * Fetches bytes for a `URL` object encountered on a `FilePart.data` by the * staging pipeline. Return `null` to pass the URL through to the model * provider unchanged, or bytes / {@link FetchFileResult} to stage the file to * the sandbox. */ readonly fetchFile?: (url: string) => Promise<Buffer | FetchFileResult | null>; /** * Channel-owned metadata exposed to instrumentation callbacks. This is the * channel's public observability surface, not a dump of durable adapter state, * so keep it small. Return an object of JSON primitives, arrays, and plain * objects: eve omits `undefined` properties and drops projections containing * values such as `Date` or `Map`. */ readonly metadata?: (state: NonNullable<TState>) => TMetadata; /** * Identifier of the adapter family this channel belongs to. Set by * higher-level wrappers (e.g. `slackChannel` passes `"slack"`) so downstream * consumers can render typed channel chips instead of bucketing everything * under "unknown". * * Authors calling `defineChannel` directly do not need to set this; the * framework defaults to `"http"` for stateless channels and `"defineChannel"` * for stateful ones. */ readonly kindHint?: string; } /** * Opaque channel value produced by {@link defineChannel} and exported from * `agent/channels/<name>.ts`. Exposes the channel's routes, an optional * `receive` hook, and (via a phantom property) its metadata shape. Unlike * {@link ChannelDefinition} it has no `TCtx` parameter: the context type is * internal to the definition. */ export interface Channel<TState = undefined, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> extends TypedReceiveTarget<TReceiveTarget> { readonly __kind: typeof CHANNEL_SENTINEL; readonly [CHANNEL_METADATA_TYPE]?: TMetadata; readonly routes: readonly RouteDefinition<TState>[]; readonly receive?: (input: ReceiveInput<TReceiveTarget>, args: { send: SendFn<TState>; }) => Promise<Session>; } /** * Extracts the metadata projection type (`TMetadata`) from a {@link Channel}. * Resolves to `Record<string, unknown>` when the value is not a Channel. */ export type InferChannelMetadata<TChannel> = TChannel extends Channel<any, any, infer TMetadata> ? TMetadata : Record<string, unknown>; /** * Builds a {@link Channel} from a {@link ChannelDefinition}. Returns a value * placed at `agent/channels/<name>.ts`; the file path supplies the channel name * (do not add a `name` field). `TCtx` (the context factory's return type) is * internal to the definition and is not part of the returned Channel signature. */ export declare function defineChannel<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>>(definition: ChannelDefinition<TState, TCtx, TReceiveTarget, TMetadata>): Channel<TState, TReceiveTarget, TMetadata>;