import type { Stimulus } from "../eval/types.js"; import type { Trajectory } from "../trajectory/types.js"; import type { ReasoningEffort } from "../graders/llm/types.js"; import type { RegisterFn } from "../utils/plugin-loader.js"; /** * Notification emitted after an executor finishes or safely interrupts one * configured conversation turn. */ export interface ExecutorTurnCompletion { /** Zero-based index into {@link Stimulus.turns}. */ turn: number; /** * `completed` means the turn returned normally; `interrupted` means the * executor observed its agent work settle after a recoverable stop; and * `unavailable` means the executor could not safely establish a stable * workspace boundary. */ status: "completed" | "interrupted" | "unavailable"; /** * When true, no later configured turn will start in this execution. The * pipeline can skip refreshing the rolling workspace baseline. */ final?: boolean; } /** * Executor — produces trajectories from stimuli. * * Pluggable to support different execution backends (mock, copilot-sdk, custom). */ export interface Executor { name: string; /** When true, the pipeline may prepare a workspace once and copy it per trial. */ supportsPreparedWorkspace?: boolean; /** When true, the executor supports multi-turn stimuli (see `Stimulus.turns`). Multi-turn stimuli on an executor without this flag are rejected with a clear error. */ supportsMultiTurn?: boolean; /** * When true, the executor invokes and awaits {@link ExecutorOptions.onTurnComplete} * exactly once for every started turn on an execution path that returns a * trajectory. A rejected execution may omit its final notification because * it produces no trajectory to grade. Required for multi-turn static diff * graders that need a stable workspace boundary after each turn. */ supportsTurnCompletion?: boolean; /** When true, the executor supports tool-call simulation (see `Stimulus.simulation`). Stimuli that declare `simulation` on an executor without this flag are rejected with a clear error. */ supportsSimulation?: boolean; /** When true, the executor supports prompt attachments (see `Stimulus.attachments`). Stimuli that declare `attachments` on an executor without this flag are rejected with a clear error. */ supportsAttachments?: boolean; /** * When true, the executor applies `ExecutorOptions.env` to the agent it runs. * When absent or false and a stimulus sets `environment.env`, the pipeline * warns rather than silently dropping the variables. */ supportsEnvVars?: boolean; /** * Validate executor-specific config supplied via `defaults.executor.config`. * * Called once at plan time, before any trial runs. Implementations parse the * opaque `config` value into their own shape and throw an `Error` with an * actionable message on invalid or unsupported input. Executors that accept * no config should leave this undefined; core then rejects (fails closed) any * `config` supplied for them. */ validateConfig?(config: unknown): void; execute(stimulus: Stimulus, options: ExecutorOptions): Promise; shutdown(): Promise; } export interface ExecutorOptions { skills?: import("../skill/types.js").Skill[]; /** * Timeout, in milliseconds, for the request to complete. */ timeout: number; /** * Agent working-time limit (ms). Must be a positive, finite number — non-positive * values are rejected by `runEval` and eval-spec validation, and executors treat * them as unset. On expiry the agent is stopped cleanly and the run passes with * `endReason: "agent_timeout"`. */ maxAgentDurationMs?: number; sessionID?: string; workDir: string; model?: string; /** * Reasoning effort for the agent under test. Opaque to core — forwarded to * the executor, which passes it to the agent runtime if supported. When unset, * the agent uses the model's own default effort. */ reasoningEffort?: ReasoningEffort; /** * Executor-specific configuration from `defaults.executor.config`, opaque to * vally core. The receiving executor interprets it (see * {@link Executor.validateConfig}); executors that accept no config ignore it. * For the `copilot-sdk` executor this is a `CopilotSdkExecutorConfig` (BYOK * provider); secret fields may be supplied indirectly via `apiKeyEnv` / * `bearerTokenEnv`, which the executor resolves from the environment at run time. */ executorConfig?: unknown; /** MCP servers to attach to the executor session */ mcpServers?: Record; /** * Environment variables to set on the agent process, from the eval spec's * `environment.env`. Process-spawning executors should merge these onto the * inherited environment (see `mergeEnv`); others (e.g. `mock`) may ignore them. */ env?: Record; /** * Callback invoked for each raw SDK event during execution. * Enables real-time streaming of diagnostic events to log files, * remote collectors, or progress monitors without coupling the * executor to a specific output mechanism. */ onRawEvent?: (event: unknown) => void; /** * Called after a configured conversation turn reaches a stable completion * boundary. Executors advertising `supportsTurnCompletion` must await it * before beginning the next configured turn, and before returning when they * started a callback. Its duration is host-side grading infrastructure: * executors must not charge it to an agent working-time budget or hard * execution deadline. */ onTurnComplete?: (completion: ExecutorTurnCompletion) => Promise; /** * Optional per-run directory where executors should write authoritative * session logs such as Copilot SDK events.jsonl. */ sessionLog?: ExecutorSessionLogOptions; /** * Optional W3C trace context captured by the caller for this execution. * Executors that spawn their own traced runtimes should propagate this * context rather than sampling ambient async context later. */ traceContext?: ExecutorTraceContext; } export interface ExecutorTraceContext { traceparent?: string; tracestate?: string; } /** * Run-scoped OpenTelemetry configuration shared by every telemetry-capable * executor (the Copilot SDK executor and external executor plugins such as the * Claude CLI plugin). * * At most one delivery mode is selected per run: when {@link otlpEndpoint} is * set, runtime spans are exported to that OTLP/HTTP endpoint; when * {@link spansDir} is set, spans are written as per-incarnation JSONL files * under that directory; when neither is set, runtime telemetry is disabled. * Executors that cannot produce local span files (for example short-lived CLI * subprocesses) may treat {@link spansDir} as a no-op for their runtime spans. * * `otlpEndpoint` and `spansDir` are mutually exclusive at the type level so * call sites cannot request both delivery modes at once. */ export type ExecutorTelemetryConfig = TelemetryDelivery & { /** Whether to capture message content (prompts, responses) in spans. */ captureContent?: boolean; }; /** * Validate a telemetry delivery configuration and normalize no-delivery configs * to `undefined`. Valid delivery configs are returned unchanged. */ export declare function normalizeExecutorTelemetryConfig(config: ExecutorTelemetryConfig): ExecutorTelemetryConfig | undefined; /** The mutually exclusive delivery-mode arms of {@link ExecutorTelemetryConfig}. */ type TelemetryDelivery = { otlpEndpoint: string; spansDir?: never; } | { spansDir: string; otlpEndpoint?: never; } | { otlpEndpoint?: never; spansDir?: never; }; /** * Capability mixin for executors that accept run-scoped OpenTelemetry * configuration. The eval pipeline calls {@link configureTelemetry} once when * an executor is first resolved, before the first {@link Executor.execute}. */ export interface TelemetryConfigurableExecutor { /** * Configure run-scoped OpenTelemetry export. Must be called before the first * {@link Executor.execute}; implementations treat the config as immutable for * the lifetime of a run. */ configureTelemetry(config: ExecutorTelemetryConfig): void; } /** * Duck-typed guard for {@link TelemetryConfigurableExecutor} so callers can * configure telemetry on any executor — including external plugins — without a * concrete class import. */ export declare function isTelemetryConfigurableExecutor(executor: Executor): executor is Executor & TelemetryConfigurableExecutor; export interface ExecutorSessionLogOptions { /** Local scratch directory for authoritative executor session logs for this run. */ rootDir: string; /** Optional stable session ID for executors that support caller-provided IDs. */ sessionID?: string; /** * Optional durable directory for the executor's full per-trial artifacts * (e.g. a runner's `OUTPUT_DIR` with `process-*.log` files). Unlike * {@link ExecutorSessionLogOptions.rootDir} — a temporary scratch dir whose contents are discarded * once the native `events.jsonl` is extracted — this points inside the * persisted per-trial report directory, so anything written here is * retained and surfaced in the Vally viewer. Executors are responsible for * creating it (e.g. `mkdir(..., { recursive: true })`). * * Optional because not every caller supplies it: the CLI's session-log * manager always populates it, but other callers (and the `mock` executor) * may leave it undefined, in which case executors should not persist extra * artifacts and behavior is unchanged. */ executorArtifactsDir?: string; } export interface ExecutorRegistry { register(executor: Executor): void; get(name: string): Executor | undefined; getAll(): Executor[]; names(): string[]; } export declare function createExecutorRegistry(): ExecutorRegistry; /** Every executor plugin package exports a `registerExecutors(registry)` function. */ export interface ExecutorPluginEntry { registerExecutors: RegisterFn; } export {}; //# sourceMappingURL=types.d.ts.map