// Completion sidecar protocol: publish, parse, clear, and read of terminal // evidence for one Completion operation. Each Fresh attempt has its own // operation-specific sidecar. import { rmSync } from "node:fs"; import type { OperationArtifacts } from "./operation-artifacts.ts"; import { isValidOperationId } from "./operation-identity.ts"; import { isTransientFileError, publishAtomicFile, readJsonFileWithRetry, retryFileOperation, } from "./file-retry.ts"; import { isThinkingLevel, type ThinkingLevel } from "./runtime-routing.ts"; export const COMPLETION_SIDECAR_VERSION = 1 as const; /** Runtime facts observed by the child while producing its Completion result. */ export interface CompletionSidecarRuntime { provider?: string; modelId?: string; thinking?: ThinkingLevel; } /** Structured data needed for parent delivery without reading a transcript. */ export interface CompletionSidecarResult { summary: string; runtime?: CompletionSidecarRuntime; } /** Terminal publication input. `result` stays optional for legacy sidecars. */ export type CompletionSidecarOutcome = | { type: "done"; result?: CompletionSidecarResult } | { type: "error"; errorMessage: string; stopReason: "error"; result?: CompletionSidecarResult; }; /** Terminal evidence and its optional self-contained delivery data. */ export type CompletionSidecar = | { version: typeof COMPLETION_SIDECAR_VERSION; operationId: string; type: "done"; result?: CompletionSidecarResult; } | { version: typeof COMPLETION_SIDECAR_VERSION; operationId: string; type: "error"; errorMessage: string; stopReason: "error"; result?: CompletionSidecarResult; }; export interface CompletionOperation { operationId: string; /** Private protocol namespace for this operation. */ artifacts: OperationArtifacts; } export type CompletionSidecarReadResult = | { kind: "missing" } | { kind: "valid"; sidecar: CompletionSidecar } | { kind: "invalid"; error: string } /** A transient Windows handle/AV lock is not malformed evidence. */ | { kind: "transient"; error: string }; export type CompletionSidecarErrorCode = | "malformed" | "unknown_version" | "missing_identity" | "mismatched_identity"; export class CompletionSidecarValidationError extends Error { readonly code: CompletionSidecarErrorCode; constructor(code: CompletionSidecarErrorCode, message: string) { super(message); this.name = "CompletionSidecarValidationError"; this.code = code; } } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function hasOnlyKeys( value: Record, keys: readonly string[], optionalKeys: readonly string[] = [], ): boolean { const allowed = new Set([...keys, ...optionalKeys]); return Object.keys(value).every((key) => allowed.has(key)) && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key)); } function hasOwn(value: Record, key: string): boolean { return Object.prototype.hasOwnProperty.call(value, key); } function requireNonEmptyString(value: unknown, message: string): string { if (typeof value !== "string" || value.trim() === "") { throw new CompletionSidecarValidationError("malformed", message); } return value; } function parseCompletionSidecarRuntime(value: unknown): CompletionSidecarRuntime { if (!isRecord(value) || !hasOnlyKeys(value, [], ["provider", "modelId", "thinking"])) { throw new CompletionSidecarValidationError( "malformed", "Completion sidecar result runtime is malformed.", ); } const runtime: CompletionSidecarRuntime = {}; if (hasOwn(value, "provider")) { runtime.provider = requireNonEmptyString( value.provider, "Completion sidecar result runtime provider is malformed.", ); } if (hasOwn(value, "modelId")) { runtime.modelId = requireNonEmptyString( value.modelId, "Completion sidecar result runtime model is malformed.", ); } if (hasOwn(value, "thinking")) { if (typeof value.thinking !== "string" || !isThinkingLevel(value.thinking)) { throw new CompletionSidecarValidationError( "malformed", "Completion sidecar result runtime thinking level is malformed.", ); } runtime.thinking = value.thinking; } if (Object.keys(runtime).length === 0) { throw new CompletionSidecarValidationError( "malformed", "Completion sidecar result runtime is empty.", ); } return runtime; } function parseCompletionSidecarResult(value: unknown): CompletionSidecarResult { if (!isRecord(value) || !hasOnlyKeys(value, ["summary"], ["runtime"])) { throw new CompletionSidecarValidationError( "malformed", "Completion sidecar result is malformed.", ); } const result: CompletionSidecarResult = { summary: requireNonEmptyString( value.summary, "Completion sidecar result summary is malformed.", ), }; if (hasOwn(value, "runtime")) result.runtime = parseCompletionSidecarRuntime(value.runtime); return result; } export function validateOperationId(operationId: unknown): asserts operationId is string { if (!isValidOperationId(operationId)) { throw new CompletionSidecarValidationError( "missing_identity", "Completion sidecar is missing a valid operation identity.", ); } } export function validateOperation(operation: CompletionOperation): void { if (!operation || typeof operation !== "object") { throw new CompletionSidecarValidationError( "malformed", "Completion operation identity is malformed.", ); } if (typeof operation.operationId !== "string" || operation.operationId.length === 0) { throw new CompletionSidecarValidationError( "missing_identity", "Completion supervision requires an operation identity.", ); } if (operation.artifacts == null) { throw new CompletionSidecarValidationError( "malformed", "Completion operation identity requires operation artifacts.", ); } if (operation.artifacts.operationId !== operation.operationId) { throw new CompletionSidecarValidationError( "mismatched_identity", "Completion operation artifacts do not match the operation identity.", ); } validateOperationId(operation.operationId); } /** Return the operation-isolated Completion evidence path. */ export function getCompletionSidecarPath(ref: CompletionOperation): string { validateOperation(ref); return ref.artifacts.path("completion"); } function payloadFor(ref: CompletionOperation, outcome: CompletionSidecarOutcome): CompletionSidecar { validateOperation(ref); const { result, ...terminal } = outcome; const payload = isRecord(outcome) ? { version: COMPLETION_SIDECAR_VERSION, operationId: ref.operationId, ...terminal, ...(result !== undefined ? { result } : {}), } : outcome; return parseCompletionSidecar(payload, ref.operationId); } /** Parse and strictly validate one sidecar payload. */ export function parseCompletionSidecar( data: unknown, expectedOperationId?: string, ): CompletionSidecar { if (!isRecord(data)) { throw new CompletionSidecarValidationError( "malformed", "Completion sidecar payload must be an object.", ); } if (data.version !== COMPLETION_SIDECAR_VERSION) { throw new CompletionSidecarValidationError( "unknown_version", "Completion sidecar has an unsupported protocol version.", ); } validateOperationId(data.operationId); if (expectedOperationId !== undefined && data.operationId !== expectedOperationId) { throw new CompletionSidecarValidationError( "mismatched_identity", "Completion sidecar operation identity does not match the supervised operation.", ); } const result = hasOwn(data, "result") ? parseCompletionSidecarResult(data.result) : undefined; if (data.type === "done") { if (!hasOnlyKeys(data, ["version", "operationId", "type"], ["result"])) { throw new CompletionSidecarValidationError( "malformed", "Completed Completion sidecar has unexpected fields.", ); } return { version: COMPLETION_SIDECAR_VERSION, operationId: data.operationId, type: "done", ...(result ? { result } : {}), }; } if (data.type === "error") { if ( !hasOnlyKeys( data, ["version", "operationId", "type", "errorMessage", "stopReason"], ["result"], ) || typeof data.errorMessage !== "string" || data.errorMessage.trim() === "" || data.stopReason !== "error" ) { throw new CompletionSidecarValidationError( "malformed", "Failed Completion sidecar has malformed fields.", ); } return { version: COMPLETION_SIDECAR_VERSION, operationId: data.operationId, type: "error", errorMessage: data.errorMessage, stopReason: "error", ...(result ? { result } : {}), }; } throw new CompletionSidecarValidationError( "malformed", "Completion sidecar has an unsupported terminal type.", ); } /** Read terminal evidence without consuming it. */ export function readCompletionSidecar(ref: CompletionOperation): CompletionSidecarReadResult { const path = getCompletionSidecarPath(ref); try { const data = readJsonFileWithRetry(path); if (data === undefined) return { kind: "missing" }; return { kind: "valid", sidecar: parseCompletionSidecar(data, ref.operationId) }; } catch (error) { if (error instanceof CompletionSidecarValidationError) { return { kind: "invalid", error: error.message }; } if (isTransientFileError(error)) { return { kind: "transient", error: error instanceof Error ? error.message : String(error), }; } return { kind: "invalid", error: "Completion sidecar could not be read or parsed." }; } } /** Remove one operation's terminal evidence after its accepted handoff. */ export function clearCompletionSidecar(ref: CompletionOperation): void { retryFileOperation( () => rmSync(getCompletionSidecarPath(ref), { force: true, maxRetries: 3, retryDelay: 25 }), { shouldRetry: isTransientFileError }, ); } /** Publish evidence atomically so readers never observe a partial JSON document. */ export function publishCompletionSidecar( ref: CompletionOperation, outcome: CompletionSidecarOutcome, ): string { const path = getCompletionSidecarPath(ref); const payload = payloadFor(ref, outcome); // Link creation is exclusive and atomic. The shared publisher retries only // transient Windows/AV contention and never replaces an existing outcome, // preserving first-writer-wins semantics. return publishAtomicFile(path, JSON.stringify(payload) + "\n", { createParentDirectory: false, }); }