@odla-ai/harness 0.11.13 → 0.11.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,8 +7,8 @@ import {
7
7
  createCodeRuntimeControlClient,
8
8
  createCodeRuntimeSessionSkillLoader,
9
9
  runCodeRuntimeHeartbeatLoop
10
- } from "./chunk-B2PQAORN.js";
11
- import "./chunk-OXWLPB7P.js";
10
+ } from "./chunk-ZXUN2STV.js";
11
+ import "./chunk-6T26HEWI.js";
12
12
  import {
13
13
  assertPinnedImage,
14
14
  selectContainerEngine
package/dist/index.cjs CHANGED
@@ -123,7 +123,8 @@ function codeToolRequestPresentation(request) {
123
123
  }
124
124
  function codeToolResultPresentation(request, response) {
125
125
  const started = codeToolRequestPresentation(request);
126
- if (!started || !response.ok) return started;
126
+ if (!started) return void 0;
127
+ if (!response.ok && started.kind !== "recipe") return started;
127
128
  const details = record(response.details);
128
129
  if (started.kind === "read") {
129
130
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/code-tool-presentation.ts","../src/code-runtime-observer.ts","../src/protocol.ts","../src/client.ts","../src/ai.ts"],"sourcesContent":["export * from \"./types\";\n// Runtime-neutral: pure translation of a broker call into a session event, so a\n// Worker can hold the emitter and the validator against each other.\nexport * from \"./code-runtime-observer\";\nexport * from \"./protocol\";\nexport * from \"./client\";\nexport * from \"./ai\";\n","import type { ChatInput, OracleResponse } from \"@odla-ai/ai\";\nimport type { CodeToolPresentation } from \"./code-session-event-types\";\nexport type { CodeToolLocationPreview, CodeToolPresentation } from \"./code-session-event-types\";\n\n/** Current JSONL protocol version exchanged between a runner and an agent container. */\nexport const HARNESS_PROTOCOL_VERSION = 1 as const;\n\n/** Default control-plane route used for model inference requested by coding agents. */\nexport const DEFAULT_AI_ROUTE = \"coding\" as const;\n\n/** Lifecycle state reported for a harness task and its active attempt. */\nexport type HarnessTaskStatus =\n | \"queued\"\n | \"running\"\n | \"cancel_requested\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\n/** Lifecycle state of one execution attempt for a task. */\nexport type HarnessAttemptStatus = HarnessTaskStatus;\n\n/** Trusted or untrusted participant that emitted a harness event. */\nexport type HarnessActor = \"operator\" | \"runner\" | \"agent\" | \"model\" | \"system\";\n\n/** Resource and isolation limits enforced while an untrusted task executes. */\nexport interface HarnessPolicy {\n network: \"none\";\n timeoutMs: number;\n maxOutputBytes: number;\n maxPatchBytes: number;\n}\n\n/** Immutable task instructions and execution policy delivered with a lease. */\nexport interface HarnessTaskSpec {\n taskId: string;\n attemptId: string;\n title: string;\n prompt: string;\n workspace: string;\n aiRoute: string;\n policy: HarnessPolicy;\n parentAttemptId?: string | null;\n checkpointSeq?: number | null;\n}\n\n/** Time-bound assignment authorizing a runner to execute one task attempt. */\nexport interface HarnessLease {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n leaseId: string;\n generation: number;\n expiresAt: number;\n task: HarnessTaskSpec;\n}\n\n/** Runner-supplied event before the control plane assigns sequence and task metadata. */\nexport interface HarnessEventInput {\n eventId: string;\n kind: string;\n actor: HarnessActor;\n payload: unknown;\n createdAt: number;\n}\n\n/** Persisted, ordered event associated with a specific task attempt. */\nexport interface HarnessEvent extends HarnessEventInput {\n seq: number;\n taskId: string;\n attemptId: string;\n}\n\n/** List-view metadata for a task and its current attempt. */\nexport interface HarnessTaskSummary {\n taskId: string;\n attemptId: string;\n appId: string;\n env: string;\n title: string;\n prompt: string;\n workspace: string;\n aiRoute: string;\n status: HarnessTaskStatus;\n parentAttemptId: string | null;\n checkpointSeq: number | null;\n runnerId: string | null;\n generation: number;\n createdAt: number;\n updatedAt: number;\n}\n\n/** List-view metadata for one attempt, including retry ancestry and runner ownership. */\nexport interface HarnessAttemptSummary {\n attemptId: string;\n taskId: string;\n parentAttemptId: string | null;\n checkpointSeq: number | null;\n status: HarnessAttemptStatus;\n runnerId: string | null;\n generation: number;\n createdAt: number;\n updatedAt: number;\n}\n\n/** Complete task view including attempts, events, result, and generated patch. */\nexport interface HarnessTaskDetail extends HarnessTaskSummary {\n attempts: HarnessAttemptSummary[];\n events: HarnessEvent[];\n patch: string | null;\n result: unknown;\n}\n\n/** Public control-plane view of a registered harness runner. */\nexport interface HarnessRunnerView {\n runnerId: string;\n appId: string;\n env: string;\n name: string;\n createdAt: number;\n lastSeenAt: number | null;\n revokedAt: number | null;\n}\n\n/** Credential-free normalized model request sent from an agent through the runner. */\nexport interface HarnessInferenceRequest {\n requestId: string;\n /** Exact initial, follow-up, or resume command whose budget this call consumes. */\n interactionId?: string;\n call: ChatInput;\n}\n\n/** Normalized model response plus auditable provider, policy, and token metadata. */\nexport interface HarnessInferenceResponse {\n requestId: string;\n response: OracleResponse;\n receipt: {\n provider: string;\n model: string;\n policyVersion: number;\n inputTokens: number;\n outputTokens: number;\n /**\n * USD charged for this call, priced against the model the control plane\n * actually resolved.\n *\n * ABSENT when the live catalog has no price for that model — never zero.\n * An unpriced call is unknown spend, and reporting it as free is what let\n * a goal's `maxUsd` look enforced while nothing enforced it. The runtime\n * cannot compute this itself: it asks for `brokered` and only the control\n * plane knows which model answered.\n */\n costUsd?: number;\n };\n}\n\n/** Bounded, content-minimized session activity emitted by a Code runtime.\n * Message bodies are projected separately into the app's owner-private\n * odla-db chat. `interactionId` is optional so stored v1 events remain valid. */\nexport type CodeSessionEventData = (\n | { type: \"message\"; actor: \"agent\" | \"system\"; body: string }\n | { type: \"diagnostic\"; level: \"error\"; message: string }\n | { type: \"thinking\"; available: true; durationMs: number }\n | {\n type: \"tool\";\n phase: \"started\";\n tool: HarnessToolName;\n operationId?: string;\n presentation?: CodeToolPresentation;\n }\n | {\n type: \"tool\";\n phase: \"completed\";\n tool: HarnessToolName;\n ok: boolean;\n durationMs: number;\n operationId?: string;\n /** Why the call failed, bounded. Absent when `ok`. Without this a watcher\n * saw that a tool failed and never why, which is what made an 84%\n * apply_patch failure rate impossible to diagnose (PM bug 515655ec). */\n failureReason?: string;\n presentation?: CodeToolPresentation;\n }\n | {\n type: \"collaboration\";\n phase: \"started\";\n skill: string;\n tool: string;\n operationId: string;\n }\n | {\n type: \"collaboration\";\n phase: \"completed\";\n skill: string;\n tool: string;\n ok: boolean;\n durationMs: number;\n operationId: string;\n }\n | {\n type: \"usage\"; provider: string; model: string;\n inputTokens: number; outputTokens: number; durationMs: number;\n interactionTokens?: number; interactionMaxTokens?: number;\n /** USD for this call; absent when the model is unpriced, never zero. */\n costUsd?: number;\n /** Cumulative USD for this owner interaction, when every call in it was\n * priced. Absent the moment one was not, so a partial total can never be\n * mistaken for the whole. */\n interactionCostUsd?: number;\n }\n | {\n type: \"status\"; status: \"running\" | \"idle\" | \"failed\" | \"checkpointed\";\n durationMs?: number;\n }\n) & { interactionId?: string };\n\n/** Registry-assigned cursor and timestamp for an owner-visible Code event. */\nexport type CodeSessionEvent = CodeSessionEventData & {\n eventId: string; sequence: number; createdAt: number;\n};\n\n/** Closed set of effects an agent container may request from its trusted broker. */\nexport type HarnessToolName =\n | \"sandbox.read\"\n | \"sandbox.list\"\n | \"sandbox.search\"\n | \"sandbox.overview\"\n | \"sandbox.where_is\"\n | \"sandbox.who_imports\"\n | \"sandbox.who_touches\"\n | \"sandbox.apply_patch\"\n | \"sandbox.edit\"\n | \"sandbox.write\"\n | \"sandbox.run_recipe\";\n/** Correlated, structured tool request emitted by an untrusted agent container. */\nexport interface HarnessToolRequest {\n requestId: string;\n tool: HarnessToolName;\n input: Record<string, unknown>;\n}\n/** Bounded tool result returned to an agent after trusted policy evaluation. */\nexport interface HarnessToolResponse {\n requestId: string;\n ok: boolean;\n content: string;\n details?: Record<string, unknown>;\n}\n\n/** Validated JSONL message emitted by an untrusted agent container. */\nexport type HarnessAgentOutput =\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"event\";\n kind: string;\n payload?: unknown;\n }\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"inference.request\";\n requestId: string;\n call: ChatInput;\n }\n | ({ protocolVersion: typeof HARNESS_PROTOCOL_VERSION; type: \"tool.request\" } & HarnessToolRequest)\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"attempt.complete\";\n status: \"completed\" | \"failed\" | \"cancelled\";\n result?: unknown;\n };\n\n/** JSONL command or inference result written by the trusted runner to an agent. */\nexport type HarnessAgentInput =\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"task.start\";\n task: HarnessTaskSpec;\n }\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"inference.response\";\n requestId: string;\n response: OracleResponse;\n }\n | ({ protocolVersion: typeof HARNESS_PROTOCOL_VERSION; type: \"tool.response\" } & HarnessToolResponse)\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"attempt.cancel\";\n reason: string;\n };\n\n/** Terminal attempt report submitted by a runner to the control plane. */\nexport interface HarnessCompletion {\n status: \"completed\" | \"failed\" | \"cancelled\";\n result?: unknown;\n patch?: string;\n error?: string;\n}\n\n/** Operations a credentialed runner may perform against the harness control plane. */\nexport interface HarnessControlPlane {\n lease(workspaces: string[]): Promise<HarnessLease | null>;\n heartbeat(attemptId: string, leaseId: string): Promise<{ cancelRequested: boolean; expiresAt: number }>;\n appendEvents(attemptId: string, leaseId: string, events: HarnessEventInput[]): Promise<void>;\n infer(attemptId: string, leaseId: string, request: HarnessInferenceRequest): Promise<HarnessInferenceResponse>;\n complete(attemptId: string, leaseId: string, completion: HarnessCompletion): Promise<void>;\n}\n\n/** Trusted inference bridge used to keep model credentials outside agent containers. */\nexport interface HarnessAiConnection {\n infer(request: HarnessInferenceRequest): Promise<HarnessInferenceResponse>;\n}\n\n/** Trusted tool boundary. Implementations must evaluate CaMeL policy before effects. */\nexport interface HarnessToolBroker {\n execute(\n context: { lease: HarnessLease; workspaceDir: string; signal?: AbortSignal },\n request: HarnessToolRequest,\n ): Promise<HarnessToolResponse>;\n}\n","import type {\n CodeToolLocationPreview, CodeToolPresentation, HarnessToolRequest, HarnessToolResponse,\n} from \"./types\";\n\nconst text = (value: unknown, maximum: number): string | undefined => {\n if (typeof value !== \"string\") return undefined;\n const bounded = value.replace(/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/g, \" \").trim();\n return bounded ? bounded.slice(0, maximum) : undefined;\n};\nconst integer = (value: unknown): number | undefined =>\n Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : undefined;\nconst record = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown> : undefined;\nconst excerpt = (value: unknown, tail = false): string | undefined => {\n if (typeof value !== \"string\") return undefined;\n const safe = value.replace(/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/g, \" \");\n const source = (tail ? safe.slice(-10_000) : safe.slice(0, 10_000)).trim();\n if (!source) return undefined;\n const lines = source.split(\"\\n\").filter((line) => line.trim()).map((line) => line.slice(0, 240));\n const selected = tail ? lines.slice(-10) : lines.slice(0, 10);\n return text(selected.join(\"\\n\"), 2_400);\n};\nconst paths = (value: unknown): string[] | undefined => {\n if (!Array.isArray(value)) return undefined;\n const items = value.flatMap((item) => {\n const path = text(item, 1_024);\n return path ? [path] : [];\n }).slice(0, 12);\n return items.length ? items : undefined;\n};\n\nfunction patchStats(value: unknown): { additions?: number; deletions?: number } {\n if (typeof value !== \"string\") return {};\n let additions = 0;\n let deletions = 0;\n for (const line of value.slice(0, 262_144).split(\"\\n\")) {\n if (line.startsWith(\"+++\") || line.startsWith(\"---\")) continue;\n if (line.startsWith(\"+\")) additions += 1;\n else if (line.startsWith(\"-\")) deletions += 1;\n }\n return { ...(additions ? { additions } : {}), ...(deletions ? { deletions } : {}) };\n}\n\nfunction searchResults(value: unknown): CodeToolLocationPreview[] | undefined {\n if (typeof value !== \"string\") return undefined;\n const results = value.split(\"\\n\").flatMap((line) => {\n const match = /^([^:\\n]{1,1024}):(\\d+):\\s?(.*)$/.exec(line);\n if (!match) return [];\n const lineNumber = Number(match[2]);\n const itemText = text(match[3], 240);\n if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];\n return [{ path: match[1]!, line: lineNumber, ...(itemText ? { text: itemText } : {}) }];\n }).slice(0, 5);\n return results.length ? results : undefined;\n}\n\n/** Produce the bounded presentation available as soon as a broker call starts. */\nexport function codeToolRequestPresentation(request: HarnessToolRequest): CodeToolPresentation | undefined {\n const input = request.input;\n if (request.tool === \"sandbox.read\") {\n const path = text(input.path, 1_024);\n if (!path) return undefined;\n const startLine = integer(input.startLine);\n const endLine = integer(input.endLine);\n return { kind: \"read\", path, ...(startLine ? { startLine } : {}), ...(endLine ? { endLine } : {}) };\n }\n if (request.tool === \"sandbox.list\") {\n const scope = text(input.prefix, 1_024);\n return { kind: \"list\", ...(scope ? { scope } : {}) };\n }\n if (request.tool === \"sandbox.search\" || request.tool === \"sandbox.overview\"\n || request.tool === \"sandbox.where_is\" || request.tool === \"sandbox.who_imports\"\n || request.tool === \"sandbox.who_touches\") {\n const query = text(input.query, 512);\n const scope = request.tool === \"sandbox.search\" ? text(input.prefix, 1_024) : undefined;\n if (request.tool === \"sandbox.search\" && !query) return undefined;\n return { kind: \"query\", ...(query ? { query } : {}), ...(scope ? { scope } : {}) };\n }\n if (request.tool === \"sandbox.apply_patch\") {\n return { kind: \"patch\", ...patchStats(input.patch) };\n }\n if (request.tool === \"sandbox.edit\") {\n const lines = (value: unknown) => (typeof value === \"string\" ? value.slice(0, 262_144).split(\"\\n\").length : 0);\n return { kind: \"patch\", additions: lines(input.newText), deletions: lines(input.oldText) };\n }\n if (request.tool === \"sandbox.write\") {\n const path = text(input.path, 1_024);\n const additions = typeof input.content === \"string\" ? input.content.slice(0, 262_144).split(\"\\n\").length : 0;\n return { kind: \"patch\", additions, ...(path ? { paths: [path] } : {}) };\n }\n const recipeId = text(input.recipeId, 120);\n return recipeId ? { kind: \"recipe\", recipeId } : undefined;\n}\n\n/** Enrich a started presentation with only the broker's bounded result shape. */\nexport function codeToolResultPresentation(\n request: HarnessToolRequest,\n response: HarnessToolResponse,\n): CodeToolPresentation | undefined {\n const started = codeToolRequestPresentation(request);\n if (!started || !response.ok) return started;\n const details = record(response.details);\n if (started.kind === \"read\") {\n return {\n ...started,\n ...(integer(details?.startLine) ? { startLine: integer(details?.startLine) } : {}),\n ...(integer(details?.endLine) ? { endLine: integer(details?.endLine) } : {}),\n ...(excerpt(response.content) ? { excerpt: excerpt(response.content) } : {}),\n };\n }\n if (started.kind === \"list\") {\n const listed = response.content.split(\"\\n\")\n .filter((line) => line && !line.startsWith(\"…\") && !line.startsWith(\"Workspace \"))\n .map((line) => text(line, 1_024)).filter((line): line is string => Boolean(line)).slice(0, 8);\n return {\n ...started,\n ...(integer(details?.count) !== undefined ? { count: integer(details?.count) } : {}),\n ...(listed.length ? { paths: listed } : {}),\n };\n }\n if (started.kind === \"query\") {\n const results = request.tool === \"sandbox.search\" ? searchResults(response.content) : undefined;\n const resultExcerpt = request.tool === \"sandbox.search\" ? undefined : excerpt(response.content);\n return {\n ...started,\n ...(integer(details?.count) !== undefined ? { count: integer(details?.count) } : {}),\n ...(results ? { results } : {}),\n ...(resultExcerpt ? { excerpt: resultExcerpt } : {}),\n };\n }\n if (started.kind === \"patch\") {\n return { ...started, ...(paths(details?.paths) ? { paths: paths(details?.paths) } : {}) };\n }\n const output = response.content.replace(/^Recipe [^\\n]*\\.?\\s*/u, \"\");\n return {\n ...started,\n ...(integer(details?.exitCode) !== undefined ? { exitCode: integer(details?.exitCode) } : {}),\n ...(typeof details?.timedOut === \"boolean\" ? { timedOut: details.timedOut } : {}),\n ...(typeof details?.outputLimitExceeded === \"boolean\"\n ? { outputLimitExceeded: details.outputLimitExceeded } : {}),\n ...(excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}),\n };\n}\n","// Reporting a brokered tool effect onto the session event stream.\n//\n// Split out of code-runtime-engine.ts, which was one line under the 250 LOC cap\n// and so could not absorb the failure reason below (PM bug c775485c: the same\n// two lines left PR #684 red and unlandable). The seam is real rather than\n// convenient — this is the only code in the engine that translates a broker\n// call into what a watcher sees, and it is the only code that needs to know how\n// a failure is described.\n\nimport { codeToolRequestPresentation, codeToolResultPresentation } from \"./code-tool-presentation\";\nimport type { CodeSessionEventData, HarnessToolBroker, HarnessToolResponse } from \"./types\";\n\n/** Longest failure reason forwarded onto a session event. A reason is a short\n * diagnostic for a human or an agent reading the stream, never a transcript. */\nexport const MAX_FAILURE_REASON = 240;\n\n/** The bounded reason a failed tool response carries, if it carries one.\n *\n * Only `response.ok` used to reach the stream, so a watcher saw that a call\n * failed and could never see why — which is what made an 84% apply_patch\n * failure rate undiagnosable (PM bugs 515655ec and 38d92f1d). */\nexport function toolFailureReason(response: HarnessToolResponse): string | undefined {\n if (response.ok) return undefined;\n // Guaranteed here rather than only where the response is built, because this\n // is the boundary that emits the event: a failure reaching the stream without\n // a reason is the defect, whoever constructed the response.\n const supplied = response.details?.failureReason;\n const reason = (typeof supplied === \"string\" && supplied)\n || DEFAULT_FAILURE_REASON[response.content]\n || response.content\n || \"tool request failed; inspect the tool input and workspace state\";\n if (reason.length <= MAX_FAILURE_REASON) return reason;\n // A test runner states its verdict last, so a reason that must be cut keeps\n // its first line and its tail rather than a head that ends mid-preamble.\n const head = reason.slice(0, 60); const gap = \" … \";\n return `${head}${gap}${reason.slice(-(MAX_FAILURE_REASON - head.length - gap.length))}`;\n}\n\n/** Reasons for the two refusals the broker states as bare content. */\nconst DEFAULT_FAILURE_REASON: Record<string, string> = {\n \"tool denied by CaMeL policy\": \"tool denied by CaMeL policy\",\n \"review sessions are read-only\": \"review session is read-only; workspace changes are not permitted\",\n};\n\n/** Wrap `broker` so every effect reports its start and its finish.\n *\n * `emit` is the engine's own event sink; it already swallows its own errors, so\n * reporting can never fail the effect it is reporting on.\n */\nexport function observedBroker(input: {\n broker: HarnessToolBroker;\n operationIdFor: (requestId: string) => string;\n emit: (event: CodeSessionEventData) => Promise<void>;\n now?: () => number;\n}): HarnessToolBroker {\n const now = input.now ?? Date.now;\n return {\n execute: async (context, request) => {\n const startedAt = now();\n // Stable and opaque: an older container may choose any bounded request\n // id, while the owner stream admits only a closed printable id shape.\n const operationId = input.operationIdFor(request.requestId);\n const startedPresentation = codeToolRequestPresentation(request);\n await input.emit({\n type: \"tool\", phase: \"started\", tool: request.tool, operationId,\n ...(startedPresentation ? { presentation: startedPresentation } : {}),\n });\n const response = await input.broker.execute(context, request);\n const completedPresentation = codeToolResultPresentation(request, response);\n const failureReason = toolFailureReason(response);\n await input.emit({\n type: \"tool\", phase: \"completed\", tool: request.tool,\n ok: response.ok, durationMs: now() - startedAt, operationId,\n ...(failureReason ? { failureReason } : {}),\n ...(completedPresentation ? { presentation: completedPresentation } : {}),\n });\n return response;\n },\n };\n}\n","import type { ChatInput } from \"@odla-ai/ai\";\nimport {\n HARNESS_PROTOCOL_VERSION,\n type HarnessAgentInput,\n type HarnessAgentOutput,\n type HarnessEventInput,\n} from \"./types\";\n\nconst CONTROL = /[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/;\n\n/** Error raised when an agent emits malformed, oversized, or unsupported protocol data. */\nexport class HarnessProtocolError extends Error {\n override readonly name = \"HarnessProtocolError\";\n}\n\nfunction record(value: unknown): Record<string, unknown> | null {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : null;\n}\n\nfunction boundedText(value: unknown, label: string, max: number): string {\n if (typeof value !== \"string\" || !value || value.length > max || CONTROL.test(value)) {\n throw new HarnessProtocolError(`${label} must be a non-empty string of at most ${max} characters`);\n }\n return value;\n}\n\n/** Parse and validate one newline-delimited message emitted by an agent container. */\nexport function parseAgentOutput(line: string): HarnessAgentOutput {\n if (Buffer.byteLength(line, \"utf8\") > 1_000_000) throw new HarnessProtocolError(\"agent message exceeds 1 MB\");\n let value: unknown;\n try { value = JSON.parse(line); } catch { throw new HarnessProtocolError(\"agent emitted invalid JSON\"); }\n const message = record(value);\n if (!message || message.protocolVersion !== HARNESS_PROTOCOL_VERSION) {\n throw new HarnessProtocolError(`agent protocolVersion must be ${HARNESS_PROTOCOL_VERSION}`);\n }\n if (message.type === \"event\") {\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"event\",\n kind: boundedText(message.kind, \"event.kind\", 120),\n ...(message.payload === undefined ? {} : { payload: message.payload }),\n };\n }\n if (message.type === \"inference.request\") {\n const call = record(message.call);\n if (!call || !Array.isArray(call.messages) || !Number.isSafeInteger(call.maxTokens)) {\n throw new HarnessProtocolError(\"inference.request.call requires messages and maxTokens\");\n }\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"inference.request\",\n requestId: boundedText(message.requestId, \"requestId\", 180),\n call: call as unknown as ChatInput,\n };\n }\n if (message.type === \"tool.request\") {\n const input = record(message.input);\n const tool = String(message.tool);\n if (!input || ![\"sandbox.read\", \"sandbox.apply_patch\", \"sandbox.edit\", \"sandbox.run_recipe\"].includes(tool)) {\n throw new HarnessProtocolError(\"tool.request requires a registered tool and object input\");\n }\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"tool.request\",\n requestId: boundedText(message.requestId, \"requestId\", 180),\n tool: tool as \"sandbox.read\" | \"sandbox.apply_patch\" | \"sandbox.edit\" | \"sandbox.run_recipe\",\n input,\n };\n }\n if (message.type === \"attempt.complete\") {\n if (!new Set([\"completed\", \"failed\", \"cancelled\"]).has(String(message.status))) {\n throw new HarnessProtocolError(\"attempt.complete.status is invalid\");\n }\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"attempt.complete\",\n status: message.status as \"completed\" | \"failed\" | \"cancelled\",\n ...(message.result === undefined ? {} : { result: message.result }),\n };\n }\n throw new HarnessProtocolError(\"agent message type is unsupported\");\n}\n\n/** Serialize one trusted runner message as a newline-terminated JSONL record. */\nexport function encodeAgentInput(message: HarnessAgentInput): string {\n return `${JSON.stringify(message)}\\n`;\n}\n\n/** Create a timestamped, uniquely identified event for control-plane submission. */\nexport function makeHarnessEvent(\n kind: string,\n actor: HarnessEventInput[\"actor\"],\n payload: unknown,\n now = Date.now(),\n id = crypto.randomUUID(),\n): HarnessEventInput {\n boundedText(kind, \"event.kind\", 120);\n return { eventId: id, kind, actor, payload, createdAt: now };\n}\n","import type {\n HarnessCompletion,\n HarnessControlPlane,\n HarnessEventInput,\n HarnessInferenceRequest,\n HarnessInferenceResponse,\n HarnessLease,\n} from \"./types\";\n\n/** HTTP error returned by the harness control plane, including its stable error code. */\nexport class HarnessControlError extends Error {\n override readonly name = \"HarnessControlError\";\n constructor(message: string, readonly status: number, readonly code = \"control_error\") { super(message); }\n}\n\n/** Connection, credential, cancellation, and timeout settings for a runner client. */\nexport interface HarnessControlClientOptions {\n endpoint: string;\n token: string;\n fetch?: typeof fetch;\n requestTimeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/** Create a validated HTTPS client implementing the runner control-plane operations. */\nexport function createHarnessControlClient(options: HarnessControlClientOptions): HarnessControlPlane {\n const endpoint = options.endpoint.replace(/\\/+$/, \"\");\n let endpointUrl: URL;\n try { endpointUrl = new URL(endpoint); } catch { throw new TypeError(\"endpoint must be an HTTPS URL\"); }\n const loopback = endpointUrl.hostname === \"localhost\" || endpointUrl.hostname === \"127.0.0.1\" || endpointUrl.hostname === \"[::1]\";\n if (endpointUrl.username || endpointUrl.password || (endpointUrl.protocol !== \"https:\" && !(loopback && endpointUrl.protocol === \"http:\"))) {\n throw new TypeError(\"endpoint must use HTTPS (HTTP is allowed only for loopback testing)\");\n }\n if (!/^odla_hrn_[0-9a-f]{64}$/.test(options.token)) throw new TypeError(\"invalid harness runner credential\");\n const requestTimeoutMs = options.requestTimeoutMs ?? 30_000;\n if (!Number.isSafeInteger(requestTimeoutMs) || requestTimeoutMs < 1_000 || requestTimeoutMs > 120_000) {\n throw new TypeError(\"requestTimeoutMs must be an integer from 1000 to 120000\");\n }\n const request = options.fetch ?? fetch;\n const call = async <T>(path: string, body: unknown, allowEmpty = false): Promise<T | null> => {\n const timeout = AbortSignal.timeout(requestTimeoutMs);\n const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;\n const response = await request(`${endpoint}${path}`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${options.token}`, \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n redirect: \"error\",\n signal,\n });\n if (allowEmpty && response.status === 204) return null;\n const value = await response.json().catch(() => null) as { error?: { code?: string; message?: string } } | null;\n if (!response.ok) throw new HarnessControlError(\n value?.error?.message ?? `harness control request failed (${response.status})`,\n response.status,\n value?.error?.code,\n );\n return value as T;\n };\n return {\n lease: async (workspaces) => {\n const body = await call<{ lease: HarnessLease }>(\"/registry/harness/lease\", { workspaces }, true);\n return body?.lease ?? null;\n },\n heartbeat: async (attemptId, leaseId) => {\n const body = await call<{ cancelRequested: boolean; expiresAt: number }>(\n `/registry/harness/attempts/${encodeURIComponent(attemptId)}/heartbeat`, { leaseId },\n );\n return body!;\n },\n appendEvents: async (attemptId, leaseId, events: HarnessEventInput[]) => {\n await call(`/registry/harness/attempts/${encodeURIComponent(attemptId)}/events`, { leaseId, events });\n },\n infer: async (attemptId, leaseId, inference: HarnessInferenceRequest) => {\n const body = await call<HarnessInferenceResponse>(\n `/registry/harness/attempts/${encodeURIComponent(attemptId)}/inference`, { leaseId, ...inference },\n );\n return body!;\n },\n complete: async (attemptId, leaseId, completion: HarnessCompletion) => {\n await call(`/registry/harness/attempts/${encodeURIComponent(attemptId)}/complete`, { leaseId, ...completion });\n },\n };\n}\n","import type { Ai } from \"@odla-ai/ai\";\nimport type { HarnessAiConnection, HarnessInferenceRequest, HarnessInferenceResponse } from \"./types\";\n\n/**\n * Adapt the normalized odla AI chat surface to a harness connection.\n * Provider credentials remain in the process that owns `ai`; only normalized\n * requests and responses cross the container protocol.\n */\nexport function createOdlaAiConnection(\n ai: Pick<Ai, \"chat\">,\n options: { model?: string; policyVersion?: number } = {},\n): HarnessAiConnection {\n return {\n async infer(request: HarnessInferenceRequest): Promise<HarnessInferenceResponse> {\n const response = await ai.chat({ ...request.call, ...(options.model ? { model: options.model } : {}) });\n return {\n requestId: request.requestId,\n response,\n receipt: {\n provider: response.provider,\n model: response.model,\n policyVersion: options.policyVersion ?? 1,\n inputTokens: response.usage.inputTokens ?? 0,\n outputTokens: response.usage.outputTokens ?? 0,\n },\n };\n },\n };\n}\n"],"mappings":"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","names":["record"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/code-tool-presentation.ts","../src/code-runtime-observer.ts","../src/protocol.ts","../src/client.ts","../src/ai.ts"],"sourcesContent":["export * from \"./types\";\n// Runtime-neutral: pure translation of a broker call into a session event, so a\n// Worker can hold the emitter and the validator against each other.\nexport * from \"./code-runtime-observer\";\nexport * from \"./protocol\";\nexport * from \"./client\";\nexport * from \"./ai\";\n","import type { ChatInput, OracleResponse } from \"@odla-ai/ai\";\nimport type { CodeToolPresentation } from \"./code-session-event-types\";\nexport type { CodeToolLocationPreview, CodeToolPresentation } from \"./code-session-event-types\";\n\n/** Current JSONL protocol version exchanged between a runner and an agent container. */\nexport const HARNESS_PROTOCOL_VERSION = 1 as const;\n\n/** Default control-plane route used for model inference requested by coding agents. */\nexport const DEFAULT_AI_ROUTE = \"coding\" as const;\n\n/** Lifecycle state reported for a harness task and its active attempt. */\nexport type HarnessTaskStatus =\n | \"queued\"\n | \"running\"\n | \"cancel_requested\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\n/** Lifecycle state of one execution attempt for a task. */\nexport type HarnessAttemptStatus = HarnessTaskStatus;\n\n/** Trusted or untrusted participant that emitted a harness event. */\nexport type HarnessActor = \"operator\" | \"runner\" | \"agent\" | \"model\" | \"system\";\n\n/** Resource and isolation limits enforced while an untrusted task executes. */\nexport interface HarnessPolicy {\n network: \"none\";\n timeoutMs: number;\n maxOutputBytes: number;\n maxPatchBytes: number;\n}\n\n/** Immutable task instructions and execution policy delivered with a lease. */\nexport interface HarnessTaskSpec {\n taskId: string;\n attemptId: string;\n title: string;\n prompt: string;\n workspace: string;\n aiRoute: string;\n policy: HarnessPolicy;\n parentAttemptId?: string | null;\n checkpointSeq?: number | null;\n}\n\n/** Time-bound assignment authorizing a runner to execute one task attempt. */\nexport interface HarnessLease {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n leaseId: string;\n generation: number;\n expiresAt: number;\n task: HarnessTaskSpec;\n}\n\n/** Runner-supplied event before the control plane assigns sequence and task metadata. */\nexport interface HarnessEventInput {\n eventId: string;\n kind: string;\n actor: HarnessActor;\n payload: unknown;\n createdAt: number;\n}\n\n/** Persisted, ordered event associated with a specific task attempt. */\nexport interface HarnessEvent extends HarnessEventInput {\n seq: number;\n taskId: string;\n attemptId: string;\n}\n\n/** List-view metadata for a task and its current attempt. */\nexport interface HarnessTaskSummary {\n taskId: string;\n attemptId: string;\n appId: string;\n env: string;\n title: string;\n prompt: string;\n workspace: string;\n aiRoute: string;\n status: HarnessTaskStatus;\n parentAttemptId: string | null;\n checkpointSeq: number | null;\n runnerId: string | null;\n generation: number;\n createdAt: number;\n updatedAt: number;\n}\n\n/** List-view metadata for one attempt, including retry ancestry and runner ownership. */\nexport interface HarnessAttemptSummary {\n attemptId: string;\n taskId: string;\n parentAttemptId: string | null;\n checkpointSeq: number | null;\n status: HarnessAttemptStatus;\n runnerId: string | null;\n generation: number;\n createdAt: number;\n updatedAt: number;\n}\n\n/** Complete task view including attempts, events, result, and generated patch. */\nexport interface HarnessTaskDetail extends HarnessTaskSummary {\n attempts: HarnessAttemptSummary[];\n events: HarnessEvent[];\n patch: string | null;\n result: unknown;\n}\n\n/** Public control-plane view of a registered harness runner. */\nexport interface HarnessRunnerView {\n runnerId: string;\n appId: string;\n env: string;\n name: string;\n createdAt: number;\n lastSeenAt: number | null;\n revokedAt: number | null;\n}\n\n/** Credential-free normalized model request sent from an agent through the runner. */\nexport interface HarnessInferenceRequest {\n requestId: string;\n /** Exact initial, follow-up, or resume command whose budget this call consumes. */\n interactionId?: string;\n call: ChatInput;\n}\n\n/** Normalized model response plus auditable provider, policy, and token metadata. */\nexport interface HarnessInferenceResponse {\n requestId: string;\n response: OracleResponse;\n receipt: {\n provider: string;\n model: string;\n policyVersion: number;\n inputTokens: number;\n outputTokens: number;\n /**\n * USD charged for this call, priced against the model the control plane\n * actually resolved.\n *\n * ABSENT when the live catalog has no price for that model — never zero.\n * An unpriced call is unknown spend, and reporting it as free is what let\n * a goal's `maxUsd` look enforced while nothing enforced it. The runtime\n * cannot compute this itself: it asks for `brokered` and only the control\n * plane knows which model answered.\n */\n costUsd?: number;\n };\n}\n\n/** Bounded, content-minimized session activity emitted by a Code runtime.\n * Message bodies are projected separately into the app's owner-private\n * odla-db chat. `interactionId` is optional so stored v1 events remain valid. */\nexport type CodeSessionEventData = (\n | { type: \"message\"; actor: \"agent\" | \"system\"; body: string }\n | { type: \"diagnostic\"; level: \"error\"; message: string }\n | { type: \"thinking\"; available: true; durationMs: number }\n | {\n type: \"tool\";\n phase: \"started\";\n tool: HarnessToolName;\n operationId?: string;\n presentation?: CodeToolPresentation;\n }\n | {\n type: \"tool\";\n phase: \"completed\";\n tool: HarnessToolName;\n ok: boolean;\n durationMs: number;\n operationId?: string;\n /** Why the call failed, bounded. Absent when `ok`. Without this a watcher\n * saw that a tool failed and never why, which is what made an 84%\n * apply_patch failure rate impossible to diagnose (PM bug 515655ec). */\n failureReason?: string;\n presentation?: CodeToolPresentation;\n }\n | {\n type: \"collaboration\";\n phase: \"started\";\n skill: string;\n tool: string;\n operationId: string;\n }\n | {\n type: \"collaboration\";\n phase: \"completed\";\n skill: string;\n tool: string;\n ok: boolean;\n durationMs: number;\n operationId: string;\n }\n | {\n type: \"usage\"; provider: string; model: string;\n inputTokens: number; outputTokens: number; durationMs: number;\n interactionTokens?: number; interactionMaxTokens?: number;\n /** USD for this call; absent when the model is unpriced, never zero. */\n costUsd?: number;\n /** Cumulative USD for this owner interaction, when every call in it was\n * priced. Absent the moment one was not, so a partial total can never be\n * mistaken for the whole. */\n interactionCostUsd?: number;\n }\n | {\n type: \"status\"; status: \"running\" | \"idle\" | \"failed\" | \"checkpointed\";\n durationMs?: number;\n }\n) & { interactionId?: string };\n\n/** Registry-assigned cursor and timestamp for an owner-visible Code event. */\nexport type CodeSessionEvent = CodeSessionEventData & {\n eventId: string; sequence: number; createdAt: number;\n};\n\n/** Closed set of effects an agent container may request from its trusted broker. */\nexport type HarnessToolName =\n | \"sandbox.read\"\n | \"sandbox.list\"\n | \"sandbox.search\"\n | \"sandbox.overview\"\n | \"sandbox.where_is\"\n | \"sandbox.who_imports\"\n | \"sandbox.who_touches\"\n | \"sandbox.apply_patch\"\n | \"sandbox.edit\"\n | \"sandbox.write\"\n | \"sandbox.run_recipe\";\n/** Correlated, structured tool request emitted by an untrusted agent container. */\nexport interface HarnessToolRequest {\n requestId: string;\n tool: HarnessToolName;\n input: Record<string, unknown>;\n}\n/** Bounded tool result returned to an agent after trusted policy evaluation. */\nexport interface HarnessToolResponse {\n requestId: string;\n ok: boolean;\n content: string;\n details?: Record<string, unknown>;\n}\n\n/** Validated JSONL message emitted by an untrusted agent container. */\nexport type HarnessAgentOutput =\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"event\";\n kind: string;\n payload?: unknown;\n }\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"inference.request\";\n requestId: string;\n call: ChatInput;\n }\n | ({ protocolVersion: typeof HARNESS_PROTOCOL_VERSION; type: \"tool.request\" } & HarnessToolRequest)\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"attempt.complete\";\n status: \"completed\" | \"failed\" | \"cancelled\";\n result?: unknown;\n };\n\n/** JSONL command or inference result written by the trusted runner to an agent. */\nexport type HarnessAgentInput =\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"task.start\";\n task: HarnessTaskSpec;\n }\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"inference.response\";\n requestId: string;\n response: OracleResponse;\n }\n | ({ protocolVersion: typeof HARNESS_PROTOCOL_VERSION; type: \"tool.response\" } & HarnessToolResponse)\n | {\n protocolVersion: typeof HARNESS_PROTOCOL_VERSION;\n type: \"attempt.cancel\";\n reason: string;\n };\n\n/** Terminal attempt report submitted by a runner to the control plane. */\nexport interface HarnessCompletion {\n status: \"completed\" | \"failed\" | \"cancelled\";\n result?: unknown;\n patch?: string;\n error?: string;\n}\n\n/** Operations a credentialed runner may perform against the harness control plane. */\nexport interface HarnessControlPlane {\n lease(workspaces: string[]): Promise<HarnessLease | null>;\n heartbeat(attemptId: string, leaseId: string): Promise<{ cancelRequested: boolean; expiresAt: number }>;\n appendEvents(attemptId: string, leaseId: string, events: HarnessEventInput[]): Promise<void>;\n infer(attemptId: string, leaseId: string, request: HarnessInferenceRequest): Promise<HarnessInferenceResponse>;\n complete(attemptId: string, leaseId: string, completion: HarnessCompletion): Promise<void>;\n}\n\n/** Trusted inference bridge used to keep model credentials outside agent containers. */\nexport interface HarnessAiConnection {\n infer(request: HarnessInferenceRequest): Promise<HarnessInferenceResponse>;\n}\n\n/** Trusted tool boundary. Implementations must evaluate CaMeL policy before effects. */\nexport interface HarnessToolBroker {\n execute(\n context: { lease: HarnessLease; workspaceDir: string; signal?: AbortSignal },\n request: HarnessToolRequest,\n ): Promise<HarnessToolResponse>;\n}\n","import type {\n CodeToolLocationPreview, CodeToolPresentation, HarnessToolRequest, HarnessToolResponse,\n} from \"./types\";\n\nconst text = (value: unknown, maximum: number): string | undefined => {\n if (typeof value !== \"string\") return undefined;\n const bounded = value.replace(/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/g, \" \").trim();\n return bounded ? bounded.slice(0, maximum) : undefined;\n};\nconst integer = (value: unknown): number | undefined =>\n Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : undefined;\nconst record = (value: unknown): Record<string, unknown> | undefined =>\n value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown> : undefined;\nconst excerpt = (value: unknown, tail = false): string | undefined => {\n if (typeof value !== \"string\") return undefined;\n const safe = value.replace(/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/g, \" \");\n const source = (tail ? safe.slice(-10_000) : safe.slice(0, 10_000)).trim();\n if (!source) return undefined;\n const lines = source.split(\"\\n\").filter((line) => line.trim()).map((line) => line.slice(0, 240));\n const selected = tail ? lines.slice(-10) : lines.slice(0, 10);\n return text(selected.join(\"\\n\"), 2_400);\n};\nconst paths = (value: unknown): string[] | undefined => {\n if (!Array.isArray(value)) return undefined;\n const items = value.flatMap((item) => {\n const path = text(item, 1_024);\n return path ? [path] : [];\n }).slice(0, 12);\n return items.length ? items : undefined;\n};\n\nfunction patchStats(value: unknown): { additions?: number; deletions?: number } {\n if (typeof value !== \"string\") return {};\n let additions = 0;\n let deletions = 0;\n for (const line of value.slice(0, 262_144).split(\"\\n\")) {\n if (line.startsWith(\"+++\") || line.startsWith(\"---\")) continue;\n if (line.startsWith(\"+\")) additions += 1;\n else if (line.startsWith(\"-\")) deletions += 1;\n }\n return { ...(additions ? { additions } : {}), ...(deletions ? { deletions } : {}) };\n}\n\nfunction searchResults(value: unknown): CodeToolLocationPreview[] | undefined {\n if (typeof value !== \"string\") return undefined;\n const results = value.split(\"\\n\").flatMap((line) => {\n const match = /^([^:\\n]{1,1024}):(\\d+):\\s?(.*)$/.exec(line);\n if (!match) return [];\n const lineNumber = Number(match[2]);\n const itemText = text(match[3], 240);\n if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];\n return [{ path: match[1]!, line: lineNumber, ...(itemText ? { text: itemText } : {}) }];\n }).slice(0, 5);\n return results.length ? results : undefined;\n}\n\n/** Produce the bounded presentation available as soon as a broker call starts. */\nexport function codeToolRequestPresentation(request: HarnessToolRequest): CodeToolPresentation | undefined {\n const input = request.input;\n if (request.tool === \"sandbox.read\") {\n const path = text(input.path, 1_024);\n if (!path) return undefined;\n const startLine = integer(input.startLine);\n const endLine = integer(input.endLine);\n return { kind: \"read\", path, ...(startLine ? { startLine } : {}), ...(endLine ? { endLine } : {}) };\n }\n if (request.tool === \"sandbox.list\") {\n const scope = text(input.prefix, 1_024);\n return { kind: \"list\", ...(scope ? { scope } : {}) };\n }\n if (request.tool === \"sandbox.search\" || request.tool === \"sandbox.overview\"\n || request.tool === \"sandbox.where_is\" || request.tool === \"sandbox.who_imports\"\n || request.tool === \"sandbox.who_touches\") {\n const query = text(input.query, 512);\n const scope = request.tool === \"sandbox.search\" ? text(input.prefix, 1_024) : undefined;\n if (request.tool === \"sandbox.search\" && !query) return undefined;\n return { kind: \"query\", ...(query ? { query } : {}), ...(scope ? { scope } : {}) };\n }\n if (request.tool === \"sandbox.apply_patch\") {\n return { kind: \"patch\", ...patchStats(input.patch) };\n }\n if (request.tool === \"sandbox.edit\") {\n const lines = (value: unknown) => (typeof value === \"string\" ? value.slice(0, 262_144).split(\"\\n\").length : 0);\n return { kind: \"patch\", additions: lines(input.newText), deletions: lines(input.oldText) };\n }\n if (request.tool === \"sandbox.write\") {\n const path = text(input.path, 1_024);\n const additions = typeof input.content === \"string\" ? input.content.slice(0, 262_144).split(\"\\n\").length : 0;\n return { kind: \"patch\", additions, ...(path ? { paths: [path] } : {}) };\n }\n const recipeId = text(input.recipeId, 120);\n return recipeId ? { kind: \"recipe\", recipeId } : undefined;\n}\n\n/** Enrich a started presentation with only the broker's bounded result shape. */\nexport function codeToolResultPresentation(\n request: HarnessToolRequest,\n response: HarnessToolResponse,\n): CodeToolPresentation | undefined {\n const started = codeToolRequestPresentation(request);\n if (!started) return undefined;\n // A failed read or search has nothing to show but its reason; a failed\n // recipe is the one result whose output matters most, and a bounded reason\n // showed nothing of a red test run (bug eff741ee).\n if (!response.ok && started.kind !== \"recipe\") return started;\n const details = record(response.details);\n if (started.kind === \"read\") {\n return {\n ...started,\n ...(integer(details?.startLine) ? { startLine: integer(details?.startLine) } : {}),\n ...(integer(details?.endLine) ? { endLine: integer(details?.endLine) } : {}),\n ...(excerpt(response.content) ? { excerpt: excerpt(response.content) } : {}),\n };\n }\n if (started.kind === \"list\") {\n const listed = response.content.split(\"\\n\")\n .filter((line) => line && !line.startsWith(\"…\") && !line.startsWith(\"Workspace \"))\n .map((line) => text(line, 1_024)).filter((line): line is string => Boolean(line)).slice(0, 8);\n return {\n ...started,\n ...(integer(details?.count) !== undefined ? { count: integer(details?.count) } : {}),\n ...(listed.length ? { paths: listed } : {}),\n };\n }\n if (started.kind === \"query\") {\n const results = request.tool === \"sandbox.search\" ? searchResults(response.content) : undefined;\n const resultExcerpt = request.tool === \"sandbox.search\" ? undefined : excerpt(response.content);\n return {\n ...started,\n ...(integer(details?.count) !== undefined ? { count: integer(details?.count) } : {}),\n ...(results ? { results } : {}),\n ...(resultExcerpt ? { excerpt: resultExcerpt } : {}),\n };\n }\n if (started.kind === \"patch\") {\n return { ...started, ...(paths(details?.paths) ? { paths: paths(details?.paths) } : {}) };\n }\n const output = response.content.replace(/^Recipe [^\\n]*\\.?\\s*/u, \"\");\n return {\n ...started,\n ...(integer(details?.exitCode) !== undefined ? { exitCode: integer(details?.exitCode) } : {}),\n ...(typeof details?.timedOut === \"boolean\" ? { timedOut: details.timedOut } : {}),\n ...(typeof details?.outputLimitExceeded === \"boolean\"\n ? { outputLimitExceeded: details.outputLimitExceeded } : {}),\n ...(excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}),\n };\n}\n","// Reporting a brokered tool effect onto the session event stream.\n//\n// Split out of code-runtime-engine.ts, which was one line under the 250 LOC cap\n// and so could not absorb the failure reason below (PM bug c775485c: the same\n// two lines left PR #684 red and unlandable). The seam is real rather than\n// convenient — this is the only code in the engine that translates a broker\n// call into what a watcher sees, and it is the only code that needs to know how\n// a failure is described.\n\nimport { codeToolRequestPresentation, codeToolResultPresentation } from \"./code-tool-presentation\";\nimport type { CodeSessionEventData, HarnessToolBroker, HarnessToolResponse } from \"./types\";\n\n/** Longest failure reason forwarded onto a session event. A reason is a short\n * diagnostic for a human or an agent reading the stream, never a transcript. */\nexport const MAX_FAILURE_REASON = 240;\n\n/** The bounded reason a failed tool response carries, if it carries one.\n *\n * Only `response.ok` used to reach the stream, so a watcher saw that a call\n * failed and could never see why — which is what made an 84% apply_patch\n * failure rate undiagnosable (PM bugs 515655ec and 38d92f1d). */\nexport function toolFailureReason(response: HarnessToolResponse): string | undefined {\n if (response.ok) return undefined;\n // Guaranteed here rather than only where the response is built, because this\n // is the boundary that emits the event: a failure reaching the stream without\n // a reason is the defect, whoever constructed the response.\n const supplied = response.details?.failureReason;\n const reason = (typeof supplied === \"string\" && supplied)\n || DEFAULT_FAILURE_REASON[response.content]\n || response.content\n || \"tool request failed; inspect the tool input and workspace state\";\n if (reason.length <= MAX_FAILURE_REASON) return reason;\n // A test runner states its verdict last, so a reason that must be cut keeps\n // its first line and its tail rather than a head that ends mid-preamble.\n const head = reason.slice(0, 60); const gap = \" … \";\n return `${head}${gap}${reason.slice(-(MAX_FAILURE_REASON - head.length - gap.length))}`;\n}\n\n/** Reasons for the two refusals the broker states as bare content. */\nconst DEFAULT_FAILURE_REASON: Record<string, string> = {\n \"tool denied by CaMeL policy\": \"tool denied by CaMeL policy\",\n \"review sessions are read-only\": \"review session is read-only; workspace changes are not permitted\",\n};\n\n/** Wrap `broker` so every effect reports its start and its finish.\n *\n * `emit` is the engine's own event sink; it already swallows its own errors, so\n * reporting can never fail the effect it is reporting on.\n */\nexport function observedBroker(input: {\n broker: HarnessToolBroker;\n operationIdFor: (requestId: string) => string;\n emit: (event: CodeSessionEventData) => Promise<void>;\n now?: () => number;\n}): HarnessToolBroker {\n const now = input.now ?? Date.now;\n return {\n execute: async (context, request) => {\n const startedAt = now();\n // Stable and opaque: an older container may choose any bounded request\n // id, while the owner stream admits only a closed printable id shape.\n const operationId = input.operationIdFor(request.requestId);\n const startedPresentation = codeToolRequestPresentation(request);\n await input.emit({\n type: \"tool\", phase: \"started\", tool: request.tool, operationId,\n ...(startedPresentation ? { presentation: startedPresentation } : {}),\n });\n const response = await input.broker.execute(context, request);\n const completedPresentation = codeToolResultPresentation(request, response);\n const failureReason = toolFailureReason(response);\n await input.emit({\n type: \"tool\", phase: \"completed\", tool: request.tool,\n ok: response.ok, durationMs: now() - startedAt, operationId,\n ...(failureReason ? { failureReason } : {}),\n ...(completedPresentation ? { presentation: completedPresentation } : {}),\n });\n return response;\n },\n };\n}\n","import type { ChatInput } from \"@odla-ai/ai\";\nimport {\n HARNESS_PROTOCOL_VERSION,\n type HarnessAgentInput,\n type HarnessAgentOutput,\n type HarnessEventInput,\n} from \"./types\";\n\nconst CONTROL = /[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/;\n\n/** Error raised when an agent emits malformed, oversized, or unsupported protocol data. */\nexport class HarnessProtocolError extends Error {\n override readonly name = \"HarnessProtocolError\";\n}\n\nfunction record(value: unknown): Record<string, unknown> | null {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : null;\n}\n\nfunction boundedText(value: unknown, label: string, max: number): string {\n if (typeof value !== \"string\" || !value || value.length > max || CONTROL.test(value)) {\n throw new HarnessProtocolError(`${label} must be a non-empty string of at most ${max} characters`);\n }\n return value;\n}\n\n/** Parse and validate one newline-delimited message emitted by an agent container. */\nexport function parseAgentOutput(line: string): HarnessAgentOutput {\n if (Buffer.byteLength(line, \"utf8\") > 1_000_000) throw new HarnessProtocolError(\"agent message exceeds 1 MB\");\n let value: unknown;\n try { value = JSON.parse(line); } catch { throw new HarnessProtocolError(\"agent emitted invalid JSON\"); }\n const message = record(value);\n if (!message || message.protocolVersion !== HARNESS_PROTOCOL_VERSION) {\n throw new HarnessProtocolError(`agent protocolVersion must be ${HARNESS_PROTOCOL_VERSION}`);\n }\n if (message.type === \"event\") {\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"event\",\n kind: boundedText(message.kind, \"event.kind\", 120),\n ...(message.payload === undefined ? {} : { payload: message.payload }),\n };\n }\n if (message.type === \"inference.request\") {\n const call = record(message.call);\n if (!call || !Array.isArray(call.messages) || !Number.isSafeInteger(call.maxTokens)) {\n throw new HarnessProtocolError(\"inference.request.call requires messages and maxTokens\");\n }\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"inference.request\",\n requestId: boundedText(message.requestId, \"requestId\", 180),\n call: call as unknown as ChatInput,\n };\n }\n if (message.type === \"tool.request\") {\n const input = record(message.input);\n const tool = String(message.tool);\n if (!input || ![\"sandbox.read\", \"sandbox.apply_patch\", \"sandbox.edit\", \"sandbox.run_recipe\"].includes(tool)) {\n throw new HarnessProtocolError(\"tool.request requires a registered tool and object input\");\n }\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"tool.request\",\n requestId: boundedText(message.requestId, \"requestId\", 180),\n tool: tool as \"sandbox.read\" | \"sandbox.apply_patch\" | \"sandbox.edit\" | \"sandbox.run_recipe\",\n input,\n };\n }\n if (message.type === \"attempt.complete\") {\n if (!new Set([\"completed\", \"failed\", \"cancelled\"]).has(String(message.status))) {\n throw new HarnessProtocolError(\"attempt.complete.status is invalid\");\n }\n return {\n protocolVersion: HARNESS_PROTOCOL_VERSION,\n type: \"attempt.complete\",\n status: message.status as \"completed\" | \"failed\" | \"cancelled\",\n ...(message.result === undefined ? {} : { result: message.result }),\n };\n }\n throw new HarnessProtocolError(\"agent message type is unsupported\");\n}\n\n/** Serialize one trusted runner message as a newline-terminated JSONL record. */\nexport function encodeAgentInput(message: HarnessAgentInput): string {\n return `${JSON.stringify(message)}\\n`;\n}\n\n/** Create a timestamped, uniquely identified event for control-plane submission. */\nexport function makeHarnessEvent(\n kind: string,\n actor: HarnessEventInput[\"actor\"],\n payload: unknown,\n now = Date.now(),\n id = crypto.randomUUID(),\n): HarnessEventInput {\n boundedText(kind, \"event.kind\", 120);\n return { eventId: id, kind, actor, payload, createdAt: now };\n}\n","import type {\n HarnessCompletion,\n HarnessControlPlane,\n HarnessEventInput,\n HarnessInferenceRequest,\n HarnessInferenceResponse,\n HarnessLease,\n} from \"./types\";\n\n/** HTTP error returned by the harness control plane, including its stable error code. */\nexport class HarnessControlError extends Error {\n override readonly name = \"HarnessControlError\";\n constructor(message: string, readonly status: number, readonly code = \"control_error\") { super(message); }\n}\n\n/** Connection, credential, cancellation, and timeout settings for a runner client. */\nexport interface HarnessControlClientOptions {\n endpoint: string;\n token: string;\n fetch?: typeof fetch;\n requestTimeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/** Create a validated HTTPS client implementing the runner control-plane operations. */\nexport function createHarnessControlClient(options: HarnessControlClientOptions): HarnessControlPlane {\n const endpoint = options.endpoint.replace(/\\/+$/, \"\");\n let endpointUrl: URL;\n try { endpointUrl = new URL(endpoint); } catch { throw new TypeError(\"endpoint must be an HTTPS URL\"); }\n const loopback = endpointUrl.hostname === \"localhost\" || endpointUrl.hostname === \"127.0.0.1\" || endpointUrl.hostname === \"[::1]\";\n if (endpointUrl.username || endpointUrl.password || (endpointUrl.protocol !== \"https:\" && !(loopback && endpointUrl.protocol === \"http:\"))) {\n throw new TypeError(\"endpoint must use HTTPS (HTTP is allowed only for loopback testing)\");\n }\n if (!/^odla_hrn_[0-9a-f]{64}$/.test(options.token)) throw new TypeError(\"invalid harness runner credential\");\n const requestTimeoutMs = options.requestTimeoutMs ?? 30_000;\n if (!Number.isSafeInteger(requestTimeoutMs) || requestTimeoutMs < 1_000 || requestTimeoutMs > 120_000) {\n throw new TypeError(\"requestTimeoutMs must be an integer from 1000 to 120000\");\n }\n const request = options.fetch ?? fetch;\n const call = async <T>(path: string, body: unknown, allowEmpty = false): Promise<T | null> => {\n const timeout = AbortSignal.timeout(requestTimeoutMs);\n const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;\n const response = await request(`${endpoint}${path}`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${options.token}`, \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n redirect: \"error\",\n signal,\n });\n if (allowEmpty && response.status === 204) return null;\n const value = await response.json().catch(() => null) as { error?: { code?: string; message?: string } } | null;\n if (!response.ok) throw new HarnessControlError(\n value?.error?.message ?? `harness control request failed (${response.status})`,\n response.status,\n value?.error?.code,\n );\n return value as T;\n };\n return {\n lease: async (workspaces) => {\n const body = await call<{ lease: HarnessLease }>(\"/registry/harness/lease\", { workspaces }, true);\n return body?.lease ?? null;\n },\n heartbeat: async (attemptId, leaseId) => {\n const body = await call<{ cancelRequested: boolean; expiresAt: number }>(\n `/registry/harness/attempts/${encodeURIComponent(attemptId)}/heartbeat`, { leaseId },\n );\n return body!;\n },\n appendEvents: async (attemptId, leaseId, events: HarnessEventInput[]) => {\n await call(`/registry/harness/attempts/${encodeURIComponent(attemptId)}/events`, { leaseId, events });\n },\n infer: async (attemptId, leaseId, inference: HarnessInferenceRequest) => {\n const body = await call<HarnessInferenceResponse>(\n `/registry/harness/attempts/${encodeURIComponent(attemptId)}/inference`, { leaseId, ...inference },\n );\n return body!;\n },\n complete: async (attemptId, leaseId, completion: HarnessCompletion) => {\n await call(`/registry/harness/attempts/${encodeURIComponent(attemptId)}/complete`, { leaseId, ...completion });\n },\n };\n}\n","import type { Ai } from \"@odla-ai/ai\";\nimport type { HarnessAiConnection, HarnessInferenceRequest, HarnessInferenceResponse } from \"./types\";\n\n/**\n * Adapt the normalized odla AI chat surface to a harness connection.\n * Provider credentials remain in the process that owns `ai`; only normalized\n * requests and responses cross the container protocol.\n */\nexport function createOdlaAiConnection(\n ai: Pick<Ai, \"chat\">,\n options: { model?: string; policyVersion?: number } = {},\n): HarnessAiConnection {\n return {\n async infer(request: HarnessInferenceRequest): Promise<HarnessInferenceResponse> {\n const response = await ai.chat({ ...request.call, ...(options.model ? { model: options.model } : {}) });\n return {\n requestId: request.requestId,\n response,\n receipt: {\n provider: response.provider,\n model: response.model,\n policyVersion: options.policyVersion ?? 1,\n inputTokens: response.usage.inputTokens ?? 0,\n outputTokens: response.usage.outputTokens ?? 0,\n },\n };\n },\n };\n}\n"],"mappings":"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","names":["record"]}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  MAX_FAILURE_REASON,
7
7
  observedBroker,
8
8
  toolFailureReason
9
- } from "./chunk-OXWLPB7P.js";
9
+ } from "./chunk-6T26HEWI.js";
10
10
  import {
11
11
  HarnessProtocolError,
12
12
  encodeAgentInput,
package/dist/node.cjs CHANGED
@@ -3449,7 +3449,8 @@ function codeToolRequestPresentation(request) {
3449
3449
  }
3450
3450
  function codeToolResultPresentation(request, response2) {
3451
3451
  const started = codeToolRequestPresentation(request);
3452
- if (!started || !response2.ok) return started;
3452
+ if (!started) return void 0;
3453
+ if (!response2.ok && started.kind !== "recipe") return started;
3453
3454
  const details = record4(response2.details);
3454
3455
  if (started.kind === "read") {
3455
3456
  return {
@@ -4394,7 +4395,7 @@ function validateOptions(options) {
4394
4395
  function createCodeRuntimeToolBroker(input, lease, role) {
4395
4396
  const broker = createCodeToolBroker({
4396
4397
  recipes: input.recipes,
4397
- recipeExecutor: createContainerRecipeExecutor(input.engine),
4398
+ recipeExecutor: input.recipeExecutor ?? createContainerRecipeExecutor(input.engine),
4398
4399
  recipeAuthorization: input.recipeAuthorization ?? "registered_recipe",
4399
4400
  readerId: `code-session:${lease.task.taskId}`,
4400
4401
  readOnlyPrefixes: [".odla-references"]
@@ -4412,6 +4413,31 @@ function createCodeRuntimeToolBroker(input, lease, role) {
4412
4413
  return role === "coding" ? broker : { execute: (context, request) => reviewTools.has(request.tool) ? broker.execute(context, request) : Promise.resolve({ requestId: request.requestId, ok: false, content: "review sessions are read-only" }) };
4413
4414
  }
4414
4415
 
4416
+ // src/code-runtime-events.ts
4417
+ var import_node_crypto4 = require("crypto");
4418
+ async function appendCodeRuntimeEvent(control, command, event, refs) {
4419
+ const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
4420
+ refs.push(eventId);
4421
+ const attributed = { ...event, interactionId: command.commandId };
4422
+ const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
4423
+ await control.appendSessionEvent(command.sessionId, eventId, bounded);
4424
+ }
4425
+ var digestRuntimeValue = (value) => `sha256:${(0, import_node_crypto4.createHash)("sha256").update(value).digest("hex")}`;
4426
+ var runtimeErrorMessage = (value) => value instanceof Error ? value.message : String(value);
4427
+
4428
+ // src/code-runtime-engine-report.ts
4429
+ async function recordSessionFailure(options, command, active, value) {
4430
+ active.failure = value.slice(0, 2e3);
4431
+ if (active.acknowledged) {
4432
+ await options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
4433
+ }
4434
+ }
4435
+ async function recordDiagnostic(options, command, active, value) {
4436
+ const detail = value.trim().slice(0, 2e3) || "Theseus runtime failed";
4437
+ options.onDiagnostic?.(detail);
4438
+ await appendCodeRuntimeEvent(options.control, command, { type: "diagnostic", level: "error", message: detail }, active.conversationRefs).catch(() => void 0);
4439
+ }
4440
+
4415
4441
  // src/code-memory.ts
4416
4442
  var import_graph2 = require("@odla-ai/graph");
4417
4443
  var MAX_MEMORY_BODY = 4e3;
@@ -4723,18 +4749,6 @@ async function startGoalPursuit(input) {
4723
4749
  return { status: run.met ? "completed" : "failed", finalText: "" };
4724
4750
  }
4725
4751
 
4726
- // src/code-runtime-events.ts
4727
- var import_node_crypto4 = require("crypto");
4728
- async function appendCodeRuntimeEvent(control, command, event, refs) {
4729
- const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
4730
- refs.push(eventId);
4731
- const attributed = { ...event, interactionId: command.commandId };
4732
- const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
4733
- await control.appendSessionEvent(command.sessionId, eventId, bounded);
4734
- }
4735
- var digestRuntimeValue = (value) => `sha256:${(0, import_node_crypto4.createHash)("sha256").update(value).digest("hex")}`;
4736
- var runtimeErrorMessage = (value) => value instanceof Error ? value.message : String(value);
4737
-
4738
4752
  // src/code-runtime-acknowledgement-gate.ts
4739
4753
  function codeRuntimeAcknowledgementGate(signal) {
4740
4754
  let settle;
@@ -4922,10 +4936,11 @@ var TheseusRuntimeEngine = class {
4922
4936
  this.options = options;
4923
4937
  this.#attempt = options.runAgentAttempt ?? runCodeAgentAttempt;
4924
4938
  this.#buildPolicyDigest = digestRuntimeValue(JSON.stringify(options.recipes));
4939
+ this.#recipeExecutor = options.recipeExecutor ?? createContainerRecipeExecutor(options.engine, { dependencies: options.recipeDependencies ?? null });
4925
4940
  this.#checkpoints = new CodeRuntimeCheckpointManager({
4926
4941
  control: options.control,
4927
4942
  recipes: options.recipes,
4928
- recipeExecutor: options.recipeExecutor ?? createContainerRecipeExecutor(options.engine, { dependencies: options.recipeDependencies ?? null }),
4943
+ recipeExecutor: this.#recipeExecutor,
4929
4944
  fallbackPolicyDigest: this.#buildPolicyDigest,
4930
4945
  event: (command, event, refs) => this.#event(command, event, refs)
4931
4946
  });
@@ -4935,6 +4950,8 @@ var TheseusRuntimeEngine = class {
4935
4950
  #attempt;
4936
4951
  #buildPolicyDigest;
4937
4952
  #checkpoints;
4953
+ /** One executor for the session broker, the verifier and goal pursuit, built with the host's dependency tree. */
4954
+ #recipeExecutor;
4938
4955
  execute(command) {
4939
4956
  if (command.kind === "checkpoint_stop") return this.#checkpoint(command);
4940
4957
  if (command.kind === "pursue") return this.#pursue(command);
@@ -5007,9 +5024,9 @@ var TheseusRuntimeEngine = class {
5007
5024
  active.done = startGate.ready.then((run) => run ? this.#runAttempt(command, metadata, active) : null).catch(async (cause) => {
5008
5025
  const detail = runtimeErrorMessage(cause);
5009
5026
  await this.#event(command, { type: "message", actor: "system", body: detail }, conversationRefs).catch(() => void 0);
5010
- await this.#diagnostic(command, active, detail);
5027
+ await recordDiagnostic(this.options, command, active, detail);
5011
5028
  await this.#event(command, { type: "status", status: "failed" }, conversationRefs).catch(() => void 0);
5012
- await this.#failure(command, active, detail);
5029
+ await recordSessionFailure(this.options, command, active, detail);
5013
5030
  return null;
5014
5031
  });
5015
5032
  return {
@@ -5033,7 +5050,7 @@ var TheseusRuntimeEngine = class {
5033
5050
  active.done = startGoalPursuit({
5034
5051
  spec,
5035
5052
  recipes: active.recipes,
5036
- recipeExecutor: this.options.recipeExecutor ?? createContainerRecipeExecutor(this.options.engine, { dependencies: this.options.recipeDependencies ?? null }),
5053
+ recipeExecutor: this.#recipeExecutor,
5037
5054
  workspace: active.workspace,
5038
5055
  baseCommitSha: active.baseCommitSha,
5039
5056
  trustedBaseDigest: active.trustedBaseDigest,
@@ -5055,8 +5072,8 @@ var TheseusRuntimeEngine = class {
5055
5072
  }, active)
5056
5073
  }).catch(async (cause) => {
5057
5074
  const detail = runtimeErrorMessage(cause);
5058
- await this.#diagnostic(command, active, detail);
5059
- await this.#failure(command, active, detail);
5075
+ await recordDiagnostic(this.options, command, active, detail);
5076
+ await recordSessionFailure(this.options, command, active, detail);
5060
5077
  return { status: "failed", finalText: "", error: detail };
5061
5078
  });
5062
5079
  return { status: "running", message: `Pursuing the goal, up to ${spec.budget.maxAttempts} attempt(s)` };
@@ -5103,9 +5120,9 @@ var TheseusRuntimeEngine = class {
5103
5120
  { type: "message", actor: "system", body: detail },
5104
5121
  active.conversationRefs
5105
5122
  ).catch(() => void 0);
5106
- await this.#diagnostic(command, active, detail);
5123
+ await recordDiagnostic(this.options, command, active, detail);
5107
5124
  await this.#event(command, { type: "status", status: "failed" }, active.conversationRefs).catch(() => void 0);
5108
- await this.#failure(command, active, detail);
5125
+ await recordSessionFailure(this.options, command, active, detail);
5109
5126
  return null;
5110
5127
  });
5111
5128
  return { status: "running", message: "Theseus accepted the owner prompt" };
@@ -5115,6 +5132,7 @@ var TheseusRuntimeEngine = class {
5115
5132
  const broker = this.#observed(command, active, createCodeRuntimeToolBroker({
5116
5133
  recipes: active.recipes,
5117
5134
  engine: this.options.engine,
5135
+ recipeExecutor: this.#recipeExecutor,
5118
5136
  recipeAuthorization: this.options.recipeAuthorization
5119
5137
  }, lease, metadata.role));
5120
5138
  const startedAt = Date.now();
@@ -5157,8 +5175,8 @@ var TheseusRuntimeEngine = class {
5157
5175
  durationMs: Date.now() - startedAt
5158
5176
  }, active.conversationRefs).catch(() => void 0);
5159
5177
  if (!completed) {
5160
- await this.#diagnostic(command, active, detail);
5161
- await this.#failure(command, active, detail);
5178
+ await recordDiagnostic(this.options, command, active, detail);
5179
+ await recordSessionFailure(this.options, command, active, detail);
5162
5180
  }
5163
5181
  return {
5164
5182
  ...result,
@@ -5183,21 +5201,6 @@ var TheseusRuntimeEngine = class {
5183
5201
  this.#active.delete(command.sessionId);
5184
5202
  return result;
5185
5203
  }
5186
- async #failure(command, active, value) {
5187
- active.failure = value.slice(0, 2e3);
5188
- if (active.acknowledged) {
5189
- await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
5190
- }
5191
- }
5192
- async #diagnostic(command, active, value) {
5193
- const detail = value.trim().slice(0, 2e3) || "Theseus runtime failed";
5194
- this.options.onDiagnostic?.(detail);
5195
- await this.#event(
5196
- command,
5197
- { type: "diagnostic", level: "error", message: detail },
5198
- active.conversationRefs
5199
- ).catch(() => void 0);
5200
- }
5201
5204
  async #event(command, event, refs) {
5202
5205
  await appendCodeRuntimeEvent(this.options.control, command, event, refs);
5203
5206
  }