UNPKG

eve

Version:

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

261 lines (260 loc) 11 kB
import type { LanguageModel, ModelMessage, UserContent } from "ai"; import type { SessionCapabilities } from "#channel/types.js"; import type { AlsContext } from "#context/container.js"; import type { HandleMessageStreamEvent, RuntimeIdentity } from "#protocol/message.js"; import type { RunMode } from "#shared/run-mode.js"; import type { RuntimeActionResult } from "#runtime/actions/types.js"; import type { RuntimeModelReference } from "#runtime/agent/bootstrap.js"; import type { InputResponse } from "#runtime/input/types.js"; import type { SandboxState } from "#sandbox/state.js"; import type { JsonObject } from "#shared/json.js"; import type { InternalToolDefinition } from "#shared/tool-definition.js"; import type { AgentReasoningDefinition } from "#shared/agent-definition.js"; import type { HarnessToolDefinition } from "#harness/execute-tool.js"; /** * Serializable tool definition stored on the session. * * Carries schema but no execute function so the session stays serializable * across workflow step boundaries. */ export type SessionToolDefinition = Readonly<InternalToolDefinition>; /** Authored-key → opaque-value map stored on `session.state`. */ export type SessionStateMap = Readonly<Record<string, unknown>>; /** * Compaction configuration stored on the session. */ export interface CompactionConfig { readonly lastKnownInputTokens?: number; readonly lastKnownPromptMessageCount?: number; readonly recentWindowSize: number; readonly threshold: number; } /** * Serializable agent configuration stored on the session. */ export interface SessionAgent { /** * Optional model used only for compaction summaries. * * When omitted, the harness uses the active turn model for compaction. */ readonly compactionModelReference?: RuntimeModelReference; /** `defineDynamic.fallback` for dynamic-model agents; serves whenever no scoped selection is set. */ readonly dynamicModelDefaultReference?: RuntimeModelReference; readonly modelReference: RuntimeModelReference; readonly reasoning?: AgentReasoningDefinition; readonly system: string; readonly tools: readonly SessionToolDefinition[]; } /** * Serializable session state passed between harness and runtime. * * Only contains plain data -- no resolved model instances or tool execute * functions. The harness resolves those at step time via injected config. */ export interface HarnessSession { readonly agent: SessionAgent; readonly compaction: CompactionConfig; readonly continuationToken: string; readonly history: ModelMessage[]; readonly limits?: SessionLimits; readonly outputSchema?: JsonObject; /** * Stable identifier of the top user-facing session in the dispatch * chain. For a top-level session this field is `undefined` and * `sessionId` itself is the root. For any delegated subagent session, * `rootSessionId` carries the original root sessionId so descendant * dispatch sites (and observability tags) can attribute work back to * the user-facing session without walking the chain. */ readonly rootSessionId?: string; readonly sessionId: string; readonly sandboxState?: SandboxState; readonly state?: SessionStateMap; /** * Number of local delegated subagent hops from the root session to this * session. Root sessions are depth 0. */ readonly subagentDepth?: number; /** * Effective maximum subagent calls one `Workflow` invocation may dispatch * for this session, configured by `experimental_workflow({ maxSubagents })`. * When omitted, the dispatch step applies the framework default. */ readonly workflowMaxSubagents?: number; } /** * Token limits stored on one durable session. */ export interface SessionLimits { /** * Maximum provider-reported input tokens this durable session may spend * before eve refuses to start another model call. Absent when the session * is uncapped. Root sessions default to 40M unless authored otherwise; * delegated subagent sessions receive the parent's remaining quota at * dispatch time. */ readonly maxInputTokensPerSession?: number; /** * Maximum provider-reported output tokens this durable session may spend before * eve refuses to start another model call. */ readonly maxOutputTokensPerSession?: number; } /** * Input payload for a harness turn. * * Carries an optional message and/or structured input responses from the * channel emitter's `onDeliver`. The message may be a plain text string or * a structured AI SDK {@link UserContent} array (mixing `text`, `image`, * and `file` parts) to support multimodal attachments delivered by * channels. The harness resolves any pending input batch at the start of * `runStep` before the model call. */ export interface StepInput { readonly inputResponses?: readonly InputResponse[]; readonly message?: string | UserContent; /** * Context strings from the channel delivery. Each entry is appended * as a `role: "user"` message to `session.history` before the * delivery message. Populated by channels via `SendPayload.context`. */ readonly context?: readonly string[]; /** * Run-scoped schema that replaces the session's current output schema when * present. Omitted continuations keep the existing schema. */ readonly outputSchema?: JsonObject; /** * Runtime-owned action results being resumed into the current turn. * * This field is internal to the execution/harness boundary and is never * produced by channels. */ readonly runtimeActionResults?: readonly RuntimeActionResult[]; } /** * Terminal result indicating the conversation is finished. */ export interface StepDone { readonly done: true; readonly output: unknown; /** * Marks a terminal turn that failed (e.g. a task-mode turn that could not * fulfil its output schema). For a delegated subagent this routes the result * to the parent as an error tool-result rather than an empty success. */ readonly isError?: boolean; } /** * The harness's instruction to the runtime about what to do next. * * - A `StepFn` reference means "call this step immediately" (tool loop continuation). * - `null` means "park and wait for the next user message." * - `StepDone` means "the conversation is finished." */ export type StepNext = StepDone | StepFn | null; /** * Result returned by one harness step invocation. */ export interface StepResult { readonly next: StepNext; readonly session: HarnessSession; } /** * A single step of AI work. Takes the current session and optional user input, * returns the updated session and an instruction for the runtime. */ export type StepFn = (session: HarnessSession, input?: StepInput) => Promise<StepResult>; /** * Map from tool name to its harness-owned definition. * * The harness uses these definitions for schema extraction, tool execution * (via {@link buildToolSet}), approval gates, and compaction hooks. */ export type HarnessToolMap = ReadonlyMap<string, HarnessToolDefinition>; /** * Callback that writes one event to the event stream. * * Composed by the runtime from the underlying writable and the channel's * event handler, then injected into the harness so it can emit lifecycle * events without knowing about writables or handlers. */ export type HarnessEmitFn = (event: HandleMessageStreamEvent, messages?: readonly import("ai").ModelMessage[]) => Promise<void>; /** * Unified event handler: emits the event to the stream, then * dispatches to hook subscribers and dynamic tool resolvers. * * Same signature as {@link HarnessEmitFn} but semantically broader — * every event goes through channel adapter, stream write, hooks, * and dynamic tool dispatch in one call. */ export type HandleEventFn = (event: HandleMessageStreamEvent, messages?: readonly import("ai").ModelMessage[]) => Promise<void>; /** * Dependencies injected into the tool-loop harness at construction time. */ export interface ToolLoopHarnessConfig { /** Cancellation signal for the active turn. */ readonly abortSignal?: AbortSignal; /** * Session-level capabilities. The harness reads * {@link SessionCapabilities.requestInput} when assembling the * per-step toolset to decide whether `ask_question` is available. */ readonly capabilities?: SessionCapabilities; /** * Exposes the `Workflow` orchestration tool — an isolated JavaScript sandbox * whose only callable operations are this agent's subagents and remote * agents. Resolved from the `experimental_workflow(...)` definition exported * by `agent/tools/workflow.ts`. Only root sessions ever see the tool. * Defaults to `false`. */ readonly workflow?: boolean; /** * Maximum subagent calls one `Workflow` invocation may dispatch, from the * authored Workflow tool definition. Advertised in the tool description; * the dispatch step enforces it. Defaults to * {@link import("#harness/workflow-subagent-limit.js").DEFAULT_WORKFLOW_MAX_SUBAGENTS}. */ readonly workflowMaxSubagents?: number; readonly handleEvent?: HandleEventFn; /** * Execution mode for the current harness. * * Conversation mode parks after a final assistant reply so the runtime can * await the next user message. Task mode must return `{ done: true, output }` * for terminal assistant text inside the current invocation. */ readonly mode: RunMode; /** * Called after compaction to let the execution layer re-apply * framework-owned state preservation (read-before-write reset, todo * re-injection). The harness appends the returned messages to the * compacted history. */ readonly onCompaction?: () => readonly ModelMessage[]; readonly dispatchDynamicModelEvent?: (input: { readonly ctx: AlsContext; readonly event: HandleMessageStreamEvent; readonly fallback: RuntimeModelReference; readonly messages: readonly ModelMessage[]; }) => Promise<void>; readonly resolveModel: (reference: RuntimeModelReference) => Promise<LanguageModel>; /** * Runtime identity metadata attached to the `session.started` event. * * When provided, the harness includes this in the first `session.started` * event so remote consumers (eval runners, reporters) receive * authoritative server-side metadata. */ readonly runtimeIdentity?: RuntimeIdentity; /** * Unified tool definitions for this harness step. * * Each entry carries schema, execution, and approval gates. The * harness derives AI SDK tool definitions, runs * {@link buildToolSet}, and checks approval gates from these * definitions directly. */ readonly tools: HarnessToolMap; }