eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
301 lines (300 loc) • 12.8 kB
TypeScript
import type { LanguageModel, ModelMessage, UserContent } from "ai";
import type { SessionAuthContext, SessionCapabilities } from "#channel/types.js";
import type { AlsContext } from "#context/container.js";
import type { RuntimeIdentity, StepStartedStreamEvent, UnstampedMessageStreamEvent } from "#protocol/message.js";
import type { RunMode } from "#shared/run-mode.js";
import type { RuntimeActionResult } from "#shared/action-types.js";
import type { RuntimeModelReference } from "#runtime/agent/bootstrap.js";
import type { InputResponse } from "#shared/input.js";
import type { SandboxState } from "#sandbox/state.js";
import type { JsonObject } from "#shared/json.js";
import type { TokenUsage } from "#shared/token-usage.js";
import type { InternalToolDefinition } from "#tools/definition.js";
import type { AgentReasoningDefinition } from "#shared/agent-definition.js";
import type { HarnessToolDefinition } from "#harness/execute-tool.js";
import type { HarnessModelMessage } from "#harness/messages.js";
import type { SessionInstrumentation } from "#instrumentation/runtime.js";
import type { HistoryViewProjector, PreparedHistoryView } from "#shared/history-view.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;
readonly thresholdPercent?: number;
}
/**
* Serializable agent configuration stored on the session.
*/
interface SessionAgentBase {
/**
* Optional model used only for compaction summaries.
*
* When omitted, the harness uses the active turn model for compaction.
*/
readonly compactionModelReference?: RuntimeModelReference;
readonly reasoning?: AgentReasoningDefinition;
readonly system: string;
readonly tools: readonly SessionToolDefinition[];
}
export type SessionAgent = SessionAgentBase & ({
readonly dynamicModel?: never;
readonly modelReference: RuntimeModelReference;
} | {
readonly dynamicModel: true;
readonly modelReference?: RuntimeModelReference;
});
/**
* 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: HarnessModelMessage[];
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;
/** Framework task that owns this durable session, when present. */
readonly taskId?: string;
}
export declare function requireSessionModelReference(session: HarnessSession): RuntimeModelReference;
/**
* 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;
/**
* Maximum provider-reported model token cost this durable session may spend,
* in US dollars, before eve refuses to start another model call.
*/
readonly maxTokenCostUsdPerSession?: 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 AttributedInputResponse {
readonly auth: SessionAuthContext | null;
readonly response: InputResponse;
}
export interface StepInput {
/** Internal responder-bound input produced at the delivery boundary. */
readonly attributedInputResponses?: readonly AttributedInputResponse[];
readonly inputResponses?: readonly InputResponse[];
readonly message?: string | UserContent;
/** Internal actor attribution for `message`. */
readonly messageAuth?: SessionAuthContext | null;
/**
* Context strings from the channel delivery. Each entry is appended as a
* synthetic user-role 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;
/** User-facing answer produced when a conversation turn settles. */
export interface SettledTurn {
readonly output: unknown;
readonly isError?: boolean;
/**
* Usage this turn added to the child's session subtree. The harness never
* sets it; the durable turn step fills it with the per-turn delta before
* the answer crosses the park boundary to the delegated caller.
*/
readonly usage?: TokenUsage;
}
/**
* Result returned by one harness step invocation.
*/
export interface StepResult {
readonly steered?: true;
/** Background-tool effects projected onto the session that entered this step. */
readonly backgroundTaskSession?: HarnessSession;
/** Durable tasks started by background tools and awaiting the parent commit barrier. */
readonly backgroundTasks?: readonly {
readonly callId?: string;
readonly taskInboxToken: string;
readonly taskId: string;
readonly taskRunId: string;
}[];
readonly next: StepNext;
readonly session: HarnessSession;
/**
* Present when a conversation turn settled with a user-facing answer; carried
* across the park boundary so a delegated parent can be notified.
*/
readonly settledTurn?: SettledTurn;
}
/**
* 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: UnstampedMessageStreamEvent, 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: UnstampedMessageStreamEvent, messages?: readonly import("ai").ModelMessage[]) => Promise<void>;
/**
* Dependencies injected into the tool-loop harness at construction time.
*/
export interface ToolLoopHarnessConfig {
readonly steeringSignal?: AbortSignal;
/** Cancellation signal for the active turn. */
readonly abortSignal?: AbortSignal;
/**
* Session-level capabilities. The harness reads
* {@link SessionCapabilities.requestInput} to decide whether a session-limit
* continuation prompt may park a task-mode session.
*/
readonly capabilities?: SessionCapabilities;
/** Clears model-message history without running a model turn. */
readonly clearOnly?: boolean;
/** Forces one context-compaction pass without running a model turn. */
readonly compactOnly?: boolean;
readonly handleEvent?: HandleEventFn;
/** Projects raw durable history before it crosses a message-bearing boundary. */
readonly historyProjector?: HistoryViewProjector;
/** Execution-prepared view of the history supplied to the first harness step. */
readonly historyView?: PreparedHistoryView;
/**
* Internal lifecycle hooks injected into each actual model attempt.
* Omitted in production until an instrumentation runtime opts in.
*/
readonly instrumentation?: SessionInstrumentation;
/**
* 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;
/** Whether this node enables framework background-task behavior. */
readonly tasksEnabled?: boolean;
/** Resolves persisted step-scoped tools before an approval policy reads them. */
readonly resolveStepDynamicTools?: (input: {
readonly ctx: AlsContext;
readonly event: StepStartedStreamEvent;
readonly messages: readonly ModelMessage[];
}) => Promise<void>;
readonly dispatchDynamicModelEvent?: (input: {
readonly ctx: AlsContext;
readonly event: UnstampedMessageStreamEvent;
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;
}
export {};