import type { LanguageModel, ModelMessage, UserContent } from "ai"; import type { SessionCapabilities } from "#channel/types.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 { 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; /** Authored-key → opaque-value map stored on `session.state`. */ export type SessionStateMap = Readonly>; /** * 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; readonly modelReference: RuntimeModelReference; 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 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; } /** * 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; /** * 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; /** * 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; /** * 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; /** * Dependencies injected into the tool-loop harness at construction time. */ export interface ToolLoopHarnessConfig { /** * 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; /** * Routes executable tools through the sandboxed code-execution wrapper * instead of exposing them directly to the model. Resolved by the * runtime from the agent's `experimental.codeMode` flag (with the * `EVE_EXPERIMENTAL_CODE_MODE` env backstop). Defaults to `false`. */ readonly codeMode?: boolean; /** * Exposes the `Workflow` orchestration tool — a code-mode-style sandbox * whose only callable operations are this agent's subagents and remote * agents. Resolved by the runtime from the agent's `workflowEnabled` flag * (set when `agent/tools/workflow.ts` re-exports the `Workflow` marker). * Independent of {@link ToolLoopHarnessConfig.codeMode} — both may be on at * once. Defaults to `false`. */ readonly workflow?: boolean; 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 resolveModel: (reference: RuntimeModelReference) => Promise; /** * 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; }