eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
111 lines (110 loc) • 5.64 kB
TypeScript
import { type ChannelCors } from "#channel/cors.js";
import type { UserContent } from "ai";
import type { ChannelReceiveContext } from "#channel/channel-operations.js";
import type { RouteDefinition } from "#channel/routes.js";
import type { Session, SessionHandle } from "#channel/session.js";
import type { DeliverPayload, SessionAuthContext, TurnPolicy } from "#channel/types.js";
import type { StepInput } from "#harness/types.js";
import type { AudienceContext } from "#shared/conversation-context.js";
import type { ChannelAudience } from "#shared/channel-audience.js";
/**
* Enriched return shape from a channel's {@link ChannelAdapter.fetchFile}
* function. Return a bare {@link Buffer} when only bytes are known, or
* this record when the fetch discovers a more accurate `mediaType` or
* `filename` (e.g. from an HTTP `Content-Type` header).
*
* When fields are provided, staging prefers them over the values the
* channel populated at ingestion time.
*/
export interface FetchFileResult {
readonly bytes: Buffer;
readonly mediaType?: string;
readonly filename?: string;
}
/** Runtime context supplied while resolving a channel-owned file URL. */
export interface FetchFileContext {
readonly state: Readonly<Record<string, unknown>>;
}
export type FetchFileFunction = (url: string, context?: FetchFileContext) => Promise<Buffer | FetchFileResult | null>;
/**
* Input passed to a channel's `receive` callback when another channel or
* schedule proactively routes a message to it.
*/
export interface GenericReceiveInput<TReceiveTarget = Record<string, unknown>> {
readonly message: string | UserContent;
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,
* `audience` classifies conversation visibility, and `metadata` projects
* custom observability data.
*
* Generics: `TState` (adapter state), `TCtx` (context factory return type),
* `TReceiveTarget` (cross-channel target shape), `TMetadata` (instrumentation
* projection).
*/
export interface GenericChannelDefinition<TEvents, TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
/** Policy used by message sends that do not provide an explicit override. */
readonly turnPolicy?: TurnPolicy;
deliver?(payload: DeliverPayload, ctx: TCtx): StepInput | void | Promise<StepInput | void>;
readonly state?: TState;
/**
* CORS policy for this channel's HTTP routes. `true` enables H3/Nitro's
* permissive defaults (`origin`, methods, request headers, and exposed
* headers all `"*"`); `false` or omission leaves CORS untouched. Pass an
* object for a serializable subset of H3/Nitro CORS options.
*/
readonly cors?: ChannelCors;
/**
* 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 ChannelContinuationOps} injected) and passes {@link SessionContext}
* as a separate `ctx` argument.
*/
context?(state: NonNullable<TState>, session: SessionHandle): TCtx;
readonly routes: readonly RouteDefinition<TState>[];
receive?(input: GenericReceiveInput<TReceiveTarget>, ctx: ChannelReceiveContext<TState>): Promise<Session>;
readonly events?: TEvents;
/**
* 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?: FetchFileFunction;
/**
* 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;
/**
* Classifies who can observe the originating conversation. The hook runs
* after route auth with channel state, the authenticated principal, run mode,
* and deployment environment. Return `"unknown"` when classification is not
* confident; consumers treat it as non-public.
*/
readonly audience?: (input: AudienceContext<TState>) => ChannelAudience;
/**
* 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;
}