@tangle-network/agent-runtime 5.0.0 → 6.0.1
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.
- package/CHANGELOG.md +16 -0
- package/dist/{activation-DGLWxFJu.js → activation-BRfZOfwb.js} +4 -4
- package/dist/{activation-DGLWxFJu.js.map → activation-BRfZOfwb.js.map} +1 -1
- package/dist/{activation-CtLdCiH3.d.ts → activation-DEKw9CDD.d.ts} +2 -2
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -3
- package/dist/{bundle-CV4Ts0cS.js → bundle-vFFiCigS.js} +2 -2
- package/dist/{bundle-CV4Ts0cS.js.map → bundle-vFFiCigS.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +70 -3
- package/dist/candidate-execution/index.js +4 -4
- package/dist/{coordination-manager-D74AZg7m.js → coordination-manager-RSJg5GmY.js} +10 -9
- package/dist/coordination-manager-RSJg5GmY.js.map +1 -0
- package/dist/coordination-map-routing-DVjW5Gx0.js.map +1 -1
- package/dist/{delegate-BVyFJ9AX.js → delegate-C0cprMUN.js} +2 -2
- package/dist/{delegate-BVyFJ9AX.js.map → delegate-C0cprMUN.js.map} +1 -1
- package/dist/durable.d.ts +2 -2
- package/dist/durable.js +9 -9
- package/dist/{graph-r8zcRxbi.js → graph-cEg-gquv.js} +5 -5
- package/dist/{graph-r8zcRxbi.js.map → graph-cEg-gquv.js.map} +1 -1
- package/dist/{improve-D12GulmK.js → improve-DNl4_6lP.js} +7 -7
- package/dist/{improve-D12GulmK.js.map → improve-DNl4_6lP.js.map} +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +10 -10
- package/dist/intelligence.d.ts +4 -4
- package/dist/intelligence.js +7 -7
- package/dist/kernel.d.ts +3 -3
- package/dist/kernel.js +12 -12
- package/dist/{loop-runner-BHBabRIw.d.ts → loop-runner-CDad0CCY.d.ts} +2 -2
- package/dist/{loop-runner-CYcN11I4.js → loop-runner-DQJjowz0.js} +2 -2
- package/dist/{loop-runner-CYcN11I4.js.map → loop-runner-DQJjowz0.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +6 -6
- package/dist/{prepare-DutbxpWr.js → prepare-B6SQA12v.js} +3 -3
- package/dist/{prepare-DutbxpWr.js.map → prepare-B6SQA12v.js.map} +1 -1
- package/dist/{profile-ClvuI8aY.js → profile-DN8Dw2Kp.js} +2 -2
- package/dist/{profile-ClvuI8aY.js.map → profile-DN8Dw2Kp.js.map} +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{protected-model-port-DEsNIYi1.d.ts → protected-model-port-uN4M48vT.d.ts} +2 -2
- package/dist/{provision-supervisor-BiqHJ-d4.js → provision-supervisor-CtAaJCUa.js} +5 -5
- package/dist/{provision-supervisor-BiqHJ-d4.js.map → provision-supervisor-CtAaJCUa.js.map} +1 -1
- package/dist/{run-cancellation-D5R-7UQt.js → run-cancellation-BCuu6khW.js} +2 -2
- package/dist/{run-cancellation-D5R-7UQt.js.map → run-cancellation-BCuu6khW.js.map} +1 -1
- package/dist/{run-state-DRh8BOFi.js → run-state-ByHiAjUs.js} +6 -5
- package/dist/{run-state-DRh8BOFi.js.map → run-state-ByHiAjUs.js.map} +1 -1
- package/dist/{runtime-BX_9-DJB.js → runtime-9EYvBcHG.js} +13 -13
- package/dist/{runtime-BX_9-DJB.js.map → runtime-9EYvBcHG.js.map} +1 -1
- package/dist/runtime-hooks-CsW2pfFk.js.map +1 -1
- package/dist/{runtime-hooks-ZQqPw-0g.d.ts → runtime-hooks-DPghSHV7.d.ts} +11 -16
- package/dist/{scope-JcCkUy_z.js → scope-DzhBJrRN.js} +3510 -3451
- package/dist/scope-DzhBJrRN.js.map +1 -0
- package/dist/{search-executor-CdmaS5r4.js → search-executor-BJRNavck.js} +4 -4
- package/dist/{search-executor-CdmaS5r4.js.map → search-executor-BJRNavck.js.map} +1 -1
- package/dist/{server-BY6OluUf.js → server-DH0P6OY_.js} +4 -4
- package/dist/{server-BY6OluUf.js.map → server-DH0P6OY_.js.map} +1 -1
- package/dist/{structural-rollout-BjMUUXLn.js → structural-rollout-DgvJLTO0.js} +4 -4
- package/dist/{structural-rollout-BjMUUXLn.js.map → structural-rollout-DgvJLTO0.js.map} +1 -1
- package/dist/{supervise-rYEsVVcn.js → supervise-Cqhkb2Oj.js} +244 -80
- package/dist/supervise-Cqhkb2Oj.js.map +1 -0
- package/dist/{supervision-discovery-D95Ack4J.js → supervision-discovery-DI5GIFBJ.js} +3 -3
- package/dist/{supervision-discovery-D95Ack4J.js.map → supervision-discovery-DI5GIFBJ.js.map} +1 -1
- package/dist/{supervisor-B-bX69uL.js → supervisor-B6sl14OR.js} +243 -962
- package/dist/supervisor-B6sl14OR.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +13 -13
- package/dist/tool-loop.d.ts +1 -1
- package/dist/{top-web-D-wH9ipn.js → top-web-DGoXGxH8.js} +4 -4
- package/dist/{top-web-D-wH9ipn.js.map → top-web-DGoXGxH8.js.map} +1 -1
- package/dist/tui/bin.js +3 -3
- package/dist/tui/index.d.ts +2 -2
- package/dist/tui/index.js +2 -2
- package/dist/{types-DblV14Oe.d.ts → types-niKnm6ux.d.ts} +86 -242
- package/dist/{workspace-streams-DbKiDOWA.d.ts → workspace-archive-DS9E9tUr.d.ts} +2 -69
- package/dist/{workspace-streams-8ALHaZzx.js → workspace-streams-BqNM06y4.js} +34 -9
- package/dist/workspace-streams-BqNM06y4.js.map +1 -0
- package/package.json +5 -5
- package/dist/coordination-manager-D74AZg7m.js.map +0 -1
- package/dist/scope-JcCkUy_z.js.map +0 -1
- package/dist/supervise-rYEsVVcn.js.map +0 -1
- package/dist/supervisor-B-bX69uL.js.map +0 -1
- package/dist/workspace-streams-8ALHaZzx.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cancellation-D5R-7UQt.js","names":[],"sources":["../src/runtime/supervise/coordination-log.ts","../src/runtime/supervise/supervise-identity.ts","../src/runtime/supervise/run-cancellation.ts"],"sourcesContent":["/**\n * Durable side-log for coordination evidence the spawn journal does not own: questions, analyst\n * findings, answer decisions, authorized continuation receipts, delivery-attempt markers, and\n * delivery outcomes. A durable run\n * (`supervise({ runDir })`) appends them as they publish and loads them on resume, so a restarted\n * coordinator retains the exact evidence produced by prior processes.\n *\n * Answer down-events also fold status on load: a question answered before the crash reloads as\n * `answered`, not as a re-blocking `open`. Settled events are skipped (the spawn journal is their\n * ledger). A receipt followed by an attempt but no outcome proves the process died in the delivery\n * window; that outcome remains unknown and no prior instruction is auto-delivered.\n *\n * JSONL, one fsynced record per event, keyed by `runId` — several runs may share one log file\n * exactly as they share one spawn-journal file.\n *\n * @experimental\n */\n\nimport { appendCommittedJsonLine, readCommittedJsonLines } from '../../durable/jsonl-file'\nimport { captureRunWriteContext } from '../../durable/run-fence'\nimport type {\n AnalystFindingEvent,\n DefinedAnalystRecord,\n} from '../../mcp/tools/coordination-analysts'\nimport type { CoordinationEvent } from '../../mcp/tools/coordination-events'\nimport type { ContinuationInstruction } from '../../mcp/tools/coordination-messages'\nimport type {\n QuestionEscalationRecord,\n QuestionRecord,\n} from '../../mcp/tools/coordination-questions'\nimport type { BusRecord } from './event-bus'\nimport type { PeerMailEvent } from './peer-mail'\n\n/** Stable identity of the supervisor that owns one coordination stream. High-level supervision\n * derives it from the exact root/child execution identity plus its parent assignment. */\nexport type CoordinationOwnerId = string\n\n/** Durable delivery evidence retained in commit order. An attempt without a later event carrying\n * the same `receiptId` has an unknown outcome after a crash and is never replayed. */\nexport type CoordinationDeliveryEvidence = Extract<\n CoordinationEvent,\n { readonly type: 'delivery-attempt' | 'steer' | 'answer' }\n>\n\n/** Coordination evidence loaded from prior processes of one durable supervised run. */\nexport interface PriorCoordination {\n /** The owner filter used for this replay. Omitted only for the compatibility all-owner read. */\n readonly ownerId?: CoordinationOwnerId\n /** Every question the prior process raised, with answer-status folded in, raise order. */\n readonly questions: ReadonlyArray<QuestionRecord>\n /** Every analyst finding the prior process published, publish order. */\n readonly findings: ReadonlyArray<AnalystFindingEvent>\n /** Every `ask_parent` escalation the prior process made, raise order. An undelivered one names a\n * question the run raised that nothing above it received — retained so a resuming operator sees\n * it, never auto-redelivered. */\n readonly escalations: ReadonlyArray<QuestionEscalationRecord>\n /** Every lens the prior process DEFINED at run time, definition order. The exact authored bytes\n * and their digest, so an invented lens can be re-registered and any finding it produced can be\n * traced to the words that produced it. Re-registration is the owner's decision, never automatic:\n * the registry may have changed between processes. */\n readonly analystDefinitions: ReadonlyArray<DefinedAnalystRecord>\n /** Every authorized continuation, in commit order. These are evidence, never replayed to a new\n * worker automatically. */\n readonly continuations: ReadonlyArray<ContinuationInstruction>\n /** Delivery intent and result records in commit order, linked to receipts by `receiptId`. */\n readonly deliveryEvidence: ReadonlyArray<CoordinationDeliveryEvidence>\n /** Every peer-mail attempt the prior process made, delivered and refused alike, in commit order.\n * Evidence of what siblings told each other; never replayed into a new worker's inbox. */\n readonly mail: ReadonlyArray<PeerMailEvent>\n /** Exact source-bus stamps in durable append order. Bus `seq` restarts with each process; append\n * order remains the cross-process replay order. */\n readonly records: ReadonlyArray<BusRecord<CoordinationEvent>>\n}\n\n/** The durable coordination side-log seam. `append` records one bus event (kinds it does not\n * persist are ignored); `load` replays a run's prior records folded into `PriorCoordination`. */\nexport interface CoordinationLog {\n append(\n runId: string,\n record: BusRecord<CoordinationEvent>,\n ownerId?: CoordinationOwnerId,\n ): Promise<void>\n load(runId: string, ownerId?: CoordinationOwnerId): Promise<PriorCoordination>\n}\n\ntype CoordinationLogRecord = {\n readonly runId: string\n readonly ownerId?: CoordinationOwnerId\n readonly seq: number\n readonly at: number\n readonly priority: number\n readonly event: CoordinationEvent\n}\n\ntype LegacyCoordinationLogRecord = {\n readonly runId: string\n readonly ownerId?: CoordinationOwnerId\n readonly at: string\n readonly event: CoordinationEvent\n}\n\n/** Persist prior context plus exact continuation authorization, attempt, and result evidence.\n * Settlements have their own journal. */\nfunction persisted(event: CoordinationEvent): boolean {\n return event.type !== 'settled'\n}\n\n/** FS-backed `CoordinationLog`: append-only JSONL, fsynced per record. */\nexport class FileCoordinationLog implements CoordinationLog {\n private readonly writeContext = captureRunWriteContext()\n private appendTail: Promise<void> = Promise.resolve()\n\n constructor(private readonly path: string) {}\n\n async append(\n runId: string,\n record: BusRecord<CoordinationEvent>,\n ownerId?: CoordinationOwnerId,\n ): Promise<void> {\n if (!persisted(record.event)) return\n const append = this.appendTail.then(() =>\n this.writeContext(() => this.appendRecord(runId, record, ownerId)),\n )\n this.appendTail = append.catch(() => undefined)\n return append\n }\n\n private async appendRecord(\n runId: string,\n busRecord: BusRecord<CoordinationEvent>,\n ownerId?: CoordinationOwnerId,\n ): Promise<void> {\n const fs = await import('node:fs/promises')\n const { dirname } = await import('node:path')\n await fs.mkdir(dirname(this.path), { recursive: true })\n const record: CoordinationLogRecord = {\n runId,\n ...(ownerId !== undefined ? { ownerId } : {}),\n ...busRecord,\n }\n await appendCommittedJsonLine(this.path, record)\n }\n\n async load(runId: string, ownerId?: CoordinationOwnerId): Promise<PriorCoordination> {\n return foldCoordinationRecords(\n readCommittedJsonLines<CoordinationLogRecord | LegacyCoordinationLogRecord>(this.path, {\n allowMissing: true,\n }),\n runId,\n ownerId,\n )\n }\n}\n\n/** @internal Shared replay semantics for file and SQL coordination evidence. */\nexport async function foldCoordinationRecords(\n source:\n | Iterable<CoordinationLogRecord | LegacyCoordinationLogRecord>\n | AsyncIterable<CoordinationLogRecord | LegacyCoordinationLogRecord>,\n runId: string,\n ownerId?: CoordinationOwnerId,\n): Promise<PriorCoordination> {\n const byId = new Map<string, QuestionRecord>()\n const findings: AnalystFindingEvent[] = []\n const escalations: QuestionEscalationRecord[] = []\n const analystDefinitions: DefinedAnalystRecord[] = []\n const continuations: ContinuationInstruction[] = []\n const deliveryEvidence: CoordinationDeliveryEvidence[] = []\n const mail: PeerMailEvent[] = []\n const records: BusRecord<CoordinationEvent>[] = []\n let legacySeq = 0\n for await (const stored of source) {\n if (stored.runId !== runId) continue\n // Omitting ownerId preserves the historical all-run read for direct consumers. Runtime always\n // supplies one, so root and nested supervisors never receive one another's evidence.\n if (ownerId !== undefined && stored.ownerId !== ownerId) continue\n const record: BusRecord<CoordinationEvent> =\n 'seq' in stored\n ? {\n seq: stored.seq,\n at: stored.at,\n priority: stored.priority,\n event: stored.event,\n }\n : {\n seq: legacySeq++,\n at: Date.parse(stored.at),\n priority: 0,\n event: stored.event,\n }\n records.push(record)\n const ev = record.event\n if (ev.type === 'delivery-attempt' || ev.type === 'steer' || ev.type === 'answer') {\n deliveryEvidence.push(ev)\n }\n if (ev.type === 'question') {\n byId.set(ev.question.id, ev.question)\n } else if (ev.type === 'finding') {\n findings.push(ev.finding)\n } else if (ev.type === 'answer') {\n // Only accepted delivery resolves a blocking question. Authorization and an attempted\n // refusal remain evidence, but cannot turn \"worker never received the answer\" into answered\n // state on replay. `by` is not on the wire; prior-run is the honest attribution.\n const prior = byId.get(ev.questionId)\n if (prior && ev.down.delivered) {\n byId.set(ev.questionId, {\n ...prior,\n status: 'answered',\n decision: { kind: 'answer', answer: ev.down.instruction, by: 'prior-run' },\n })\n }\n } else if (ev.type === 'instruction') {\n continuations.push(ev.instruction)\n } else if (ev.type === 'mail') {\n mail.push(ev.mail)\n } else if (ev.type === 'escalation') {\n escalations.push(ev.escalation)\n } else if (ev.type === 'analyst-defined') {\n analystDefinitions.push(ev.analyst)\n }\n }\n return {\n ...(ownerId !== undefined ? { ownerId } : {}),\n questions: [...byId.values()],\n findings,\n escalations,\n analystDefinitions,\n continuations,\n deliveryEvidence,\n mail,\n records,\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { resolve } from 'node:path'\nimport {\n type AgentProfile,\n agentProfileSchema,\n canonicalCandidateDigest,\n type Sha256Digest,\n} from '@tangle-network/agent-interface'\nimport { ValidationError } from '../../errors'\nimport type { WorkerSpawnContext } from '../../mcp/tools/coordination-contracts'\nimport type { CoordinationEvent } from '../../mcp/tools/coordination-events'\nimport { deriveNodeExecutionIdentity } from './scope'\nimport { detachedSnapshot } from './snapshot'\nimport type { SupervisorNodeContext } from './supervisor-agent'\nimport type { AgentExecutionRef, NodeExecutionIdentity } from './types'\n\nexport function externalExecutionId(kind: string, identity: unknown): string {\n const digest = canonicalCandidateDigest({ kind, identity })\n return `${kind}-${digest.slice('sha256:'.length)}`\n}\n\nexport function freezeDetached<T>(value: T): T {\n return detachedSnapshot(value, 'supervise')\n}\n\nexport function freezeDetachedProfile(value: unknown): AgentProfile {\n return freezeDetached(agentProfileSchema.parse(value))\n}\n\nexport function canonicalExecution(\n profile: AgentProfile,\n task: unknown,\n rawExecution: AgentExecutionRef | undefined,\n context: string,\n): { readonly identity: NodeExecutionIdentity; readonly ref?: AgentExecutionRef } {\n const execution = rawExecution === undefined ? undefined : freezeDetached(rawExecution)\n if (execution !== undefined) {\n if (typeof execution !== 'object' || execution === null || Array.isArray(execution)) {\n throw new ValidationError(`${context}: execution must be an object`)\n }\n const unknown = Object.keys(execution).filter(\n (key) => key !== 'candidateDigest' && key !== 'correlation',\n )\n if (unknown.length > 0) {\n throw new ValidationError(`${context}: unknown execution fields: ${unknown.join(', ')}`)\n }\n }\n const identity = deriveNodeExecutionIdentity({ profile, execution }, task)\n if (!identity?.profileDigest || !identity.taskDigest) {\n throw new ValidationError(\n `${context}: profile and task must be finite, acyclic canonical JSON for durable identity`,\n )\n }\n const ref: AgentExecutionRef | undefined =\n identity.candidateDigest || identity.correlation\n ? Object.freeze({\n ...(identity.candidateDigest ? { candidateDigest: identity.candidateDigest } : {}),\n ...(identity.correlation ? { correlation: identity.correlation } : {}),\n })\n : undefined\n return { identity, ...(ref ? { ref } : {}) }\n}\n\nexport function rootCoordinationOwner(identity: NodeExecutionIdentity): string {\n return canonicalCandidateDigest({ kind: 'supervisor-root', identity })\n}\n\nexport function childCoordinationOwner(\n parentOwnerId: string,\n identity: NodeExecutionIdentity,\n context: WorkerSpawnContext,\n depth: number,\n): string {\n return canonicalCandidateDigest({\n kind: 'supervisor-child',\n parentOwnerId,\n identity,\n assignment: {\n id: context.assignmentId,\n label: context.label,\n key: context.key ?? null,\n depth,\n },\n })\n}\n\nexport function supervisionRunNamespace(runDir: string | undefined, runId: string): string {\n return canonicalCandidateDigest(\n runDir === undefined\n ? { kind: 'supervise-ephemeral-run', runId, nonce: randomUUID() }\n : { kind: 'supervise-durable-run', runId, runDir: resolve(runDir) },\n )\n}\n\nexport function workerAssignmentNamespace(\n runNamespace: string,\n parentOwnerId: string,\n assignmentId: string,\n): string {\n return canonicalCandidateDigest({\n kind: 'supervise-worker-assignment',\n runNamespace,\n parentOwnerId,\n assignmentId,\n })\n}\n\n/** Hash only durable coordination meaning. Bus sequence/timestamp are delivery metadata and a\n * resumed projection's marker describes the reader, not the original settlement. */\nexport function coordinationEventId(\n context: SupervisorNodeContext,\n event: CoordinationEvent,\n): Sha256Digest {\n const durableEvent =\n event.type === 'settled' && event.worker.resumed === true\n ? (() => {\n const { resumed: _resumed, ...worker } = event.worker\n return { type: 'settled' as const, worker }\n })()\n : event\n return canonicalCandidateDigest({\n kind: 'supervise-coordination-event',\n runNamespace: context.runNamespace,\n ownerId: context.ownerId,\n event: detachedSnapshot(durableEvent, 'supervise coordination event identity'),\n })\n}\n","import { existsSync, mkdirSync, readFileSync, watch } from 'node:fs'\nimport { join } from 'node:path'\nimport type { RetainedRunEffect } from '../retained-run-types'\nimport { assertNoSymlinkDescendant, writeAtomicDurableFile } from './durable-file'\nimport { appendWorkerControlEvent, workerCancellationsDir } from './run-layout'\n\n/** Apply a durable request through the run's existing abort controller. */\nexport function applyRunCancellation(\n dir: string,\n abortRun: (reason: string, request?: RunCancelRequest) => void,\n now: () => string,\n path: 'observer' | 'turn-boundary' | 'fallback' = 'turn-boundary',\n): RunCancellation | undefined {\n const request = readRunCancelRequest(dir)\n if (request === undefined) return undefined\n const prior = readRunCancellation(dir, request.operationId)\n // A request acknowledged only as `cancel_requested` is still owed by this run: the process\n // that issued the abort died before the run settled. Abort again; the record stands.\n if (prior?.effect === 'cancel_requested') {\n abortRun(request.reason ?? 'run cancel requested', request)\n }\n if (prior !== undefined) return prior\n abortRun(request.reason ?? 'run cancel requested', request)\n const observedAt = now()\n const appliedAfterMs = Math.max(0, Date.parse(observedAt) - Date.parse(request.at))\n const record: RunCancellation = {\n operationId: request.operationId,\n effect: 'cancel_requested',\n path,\n appliedAfterMs,\n ...(request.deadlineMs === undefined\n ? {}\n : { deadlineExceeded: appliedAfterMs > request.deadlineMs }),\n requestedAt: request.at,\n observedAt,\n ...(request.reason === undefined ? {} : { reason: request.reason }),\n ...(request.operator === undefined ? {} : { operator: request.operator }),\n detail: 'root abort issued to the whole run; termination not yet proven',\n }\n writeRunCancellation(dir, record)\n return record\n}\n\n/** External drivers may remain silent indefinitely, so turn boundaries cannot observe control. */\nexport function watchRunCancellation(\n dir: string,\n abortRun: (reason: string, request?: RunCancelRequest) => void,\n createWatch: typeof watch = watch,\n) {\n mkdirSync(workerCancellationsDir(dir), { recursive: true })\n let active = true\n let failure: unknown\n // One observer aborts its run once: a request this process already applied, or one a dead\n // process acknowledged, is not re-issued on every poll.\n let aborted = false\n const abortOnce = (reason: string, request?: RunCancelRequest): void => {\n if (aborted) return\n aborted = true\n abortRun(reason, request)\n }\n const check = (path: 'observer' | 'fallback' = 'observer'): void => {\n if (failure !== undefined) throw failure\n if (active) applyRunCancellation(dir, abortOnce, () => new Date().toISOString(), path)\n }\n const fail = (error: unknown): void => {\n if (!active) return\n failure = error\n abortRun(`durable run cancellation observer failed: ${String(error)}`)\n }\n // The watcher is an optimization over the poll loop below (instant pickup instead of ≤100 ms).\n // Creating it can fail for reasons that say NOTHING about this run: the host's inotify budget is\n // exhausted (EMFILE — a shared box with many agents held ~110 of the 128 default user instances\n // when this was measured), or the kernel caps watches (ENOSPC). Degrading to poll-only keeps\n // every durable behavior; failing the run would make a neighboring process's resource use kill\n // runs that never touched the limit. Any other creation error still fails loudly.\n let watcher: ReturnType<typeof watch> | undefined\n try {\n watcher = createWatch(workerCancellationsDir(dir), (_event, filename) => {\n if (!active || (filename !== null && filename !== 'run.request.json')) return\n try {\n check()\n } catch (error) {\n fail(error)\n }\n })\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code\n if (code !== 'EMFILE' && code !== 'ENOSPC') throw error\n }\n watcher?.on('error', fail)\n // Filesystem notifications are advisory. Scan the same durable inbox when one is dropped —\n // and carry the whole observer alone whenever the watcher above could not be created.\n const fallback = setInterval(() => {\n try {\n check('fallback')\n } catch (error) {\n fail(error)\n }\n }, 100)\n fallback.unref()\n return {\n check,\n close(): void {\n active = false\n watcher?.close()\n clearInterval(fallback)\n },\n }\n}\n\n/** One durable run-scoped cancel request: cancel the WHOLE run, not one worker. */\nexport interface RunCancelRequest {\n /** Caller-minted stable operation identifier — the idempotency key of the whole operation. */\n readonly operationId: string\n /** ISO timestamp of the write. */\n readonly at: string\n /** Who asked — 'human', a brain label, a tool name. Provenance, not authorization. */\n readonly source: string\n /** Requested observation target, measured by the acknowledgement's deadlineExceeded field.\n * The observer always cascades eagerly. This does not guarantee scheduler latency or cleanup. */\n readonly deadlineMs?: number\n /** Who stops the run. `cancelRun` requires it on every new request; it is optional here only\n * so a request written before that rule still reads. The settle record carries it. */\n readonly operator?: string\n readonly reason?: string\n}\n\n/**\n * The durable acknowledgement state for the run-scoped cancel operation, keyed by `operationId`.\n * The runtime is the ONLY writer; {@link cancelRun} only reads it.\n *\n * `effect` is the same {@link RetainedRunEffect} vocabulary the worker-scoped and retained-run\n * paths use, so the runtime has one spelling of the four cancellation states:\n * - `'unknown'` — no runtime has answered yet. Never a success.\n * - `'cancel_requested'` — the root manager issued the run's cascading abort; the run's terminal\n * state is not yet observed.\n * - `'cancelled'` — the run reached its terminal cancelled state with confirmed teardown.\n * - `'not_live'` — the run was not live to cancel: it settled on its own despite the\n * request, or it ended before the request was applied.\n */\nexport interface RunCancellation {\n /** Runtime path that issued the cascade. */\n readonly path?: 'observer' | 'turn-boundary' | 'fallback'\n /** Runtime clock elapsed between request timestamp and cascade application. */\n readonly appliedAfterMs?: number\n /** Whether application exceeded the requested deadlineMs; absent when no target was requested. */\n readonly deadlineExceeded?: boolean\n readonly operationId: string\n readonly effect: RetainedRunEffect\n /** ISO timestamp of the original request. */\n readonly requestedAt: string\n /** ISO timestamp of the runtime's most recent observation of this operation. */\n readonly observedAt: string\n /** The caller's reason, carried verbatim from the request. */\n readonly reason?: string\n /** The caller's operator identity, carried verbatim from the request. */\n readonly operator?: string\n /** The runtime's explanation of how it arrived at `effect`. */\n readonly detail?: string\n}\n\n/** The run-scoped cancel request file of one run — one {@link RunCancelRequest}. */\nexport function runCancelRequestFile(eventDir: string): string {\n return join(workerCancellationsDir(eventDir), 'run.request.json')\n}\n\n/** The run-scoped acknowledgement file of one run — one {@link RunCancellation}. */\nexport function runCancellationFile(eventDir: string): string {\n return join(workerCancellationsDir(eventDir), 'run.json')\n}\n\n/** Read the run-scoped cancel request, or `undefined` when none was written. */\nexport function readRunCancelRequest(eventDir: string): RunCancelRequest | undefined {\n const dir = workerCancellationsDir(eventDir)\n const file = runCancelRequestFile(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel request')\n assertNoSymlinkDescendant(eventDir, file, 'run cancel request')\n if (!existsSync(file)) return undefined\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as Partial<RunCancelRequest>\n if (!isRunCancelRequest(parsed)) {\n throw new Error(`run cancel request '${file}' is not a complete RunCancelRequest`)\n }\n return parsed\n}\n\n/**\n * Read the acknowledgement for the run-scoped cancel operation. `undefined` when the runtime has\n * not answered. A record holding a DIFFERENT `operationId` belongs to another operation on the\n * same run — fail loud rather than answer for it.\n */\nexport function readRunCancellation(\n eventDir: string,\n operationId: string,\n): RunCancellation | undefined {\n const dir = workerCancellationsDir(eventDir)\n const file = runCancellationFile(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel acknowledgement')\n assertNoSymlinkDescendant(eventDir, file, 'run cancel acknowledgement')\n if (!existsSync(file)) return undefined\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as RunCancellation\n if (parsed.operationId !== operationId) {\n throw new Error(\n `run cancel acknowledgement '${file}' holds operation '${parsed.operationId}', not ` +\n `'${operationId}' — one run carries one run-scoped cancel operation`,\n )\n }\n return parsed\n}\n\n/**\n * Durably write the run-scoped acknowledgement. The shared writer fsyncs the file and containing\n * directory, so a concurrent reader sees the prior complete record or the new complete record.\n *\n * @internal The runtime is the only intended writer; clients read via {@link readRunCancellation}\n * or {@link cancelRun}.\n */\nexport function writeRunCancellation(eventDir: string, record: RunCancellation): void {\n const dir = workerCancellationsDir(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel acknowledgement')\n mkdirSync(dir, { recursive: true })\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel acknowledgement')\n const file = runCancellationFile(eventDir)\n assertNoSymlinkDescendant(eventDir, file, 'run cancel acknowledgement')\n writeAtomicDurableFile(file, `${JSON.stringify(record, null, 2)}\\n`, { mode: 0o600 })\n}\n\n/**\n * Request the cancellation of the WHOLE run, idempotently, and return the operation's current\n * durable state.\n *\n * The run-scoped twin of {@link cancelWorker}: write the request into the run's cancellation\n * directory, where the run's own root manager applies it — aborting the root through the one\n * cascade controller the run already has, so every live worker comes down with it. This function\n * never applies the cancellation itself; writing a request file is not an acknowledgement.\n *\n * Idempotency is a lookup: when an acknowledgement for `operationId` already exists it is returned\n * AS-IS and nothing is written. A retry that changes the source, reason, deadline, or operator\n * fails closed. A request the runtime has not answered yet returns `effect: 'unknown'` (never a\n * success); call again with the same `operationId` — or {@link readRunCancellation} — to read the\n * acknowledged result after a reconnect.\n *\n * A run carries ONE run-scoped operation: a second request under a different `operationId` throws\n * rather than silently replacing the pending one, because both would claim the same single abort.\n * Reopening a settled run (`supervisePursuit`'s `reopen`) moves that operation aside.\n *\n * A NEW request must name its `operator`, so every stop says who made it. A replay of a request\n * or acknowledgement written before that rule is answered as it was.\n */\nexport function cancelRun(\n eventDir: string,\n operationId: string,\n options: {\n readonly reason?: string\n readonly source?: string\n readonly deadlineMs?: number\n readonly operator?: string\n } = {},\n): RunCancellation {\n if (\n options.deadlineMs !== undefined &&\n (!Number.isFinite(options.deadlineMs) || options.deadlineMs < 0)\n ) {\n throw new Error('cancelRun: deadlineMs must be a finite nonnegative number')\n }\n const opId = operationId.trim()\n if (!opId) throw new Error('cancelRun: operationId is empty')\n const pending = readRunCancelRequest(eventDir)\n if (pending !== undefined && pending.operationId !== opId) {\n throw new Error(\n `cancelRun: run cancel '${pending.operationId}' is already pending for this run; ` +\n `read it with readRunCancellation instead of issuing '${opId}'`,\n )\n }\n const candidate = {\n operationId: opId,\n source: options.source ?? 'human',\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n ...(options.deadlineMs === undefined ? {} : { deadlineMs: options.deadlineMs }),\n ...(options.operator === undefined ? {} : { operator: options.operator }),\n }\n if (pending !== undefined) assertSameRunCancelRequest(pending, candidate)\n const acknowledged = readRunCancellation(eventDir, opId)\n if (acknowledged !== undefined) {\n if (pending === undefined && options.source !== undefined) {\n throw new Error(\n `cancelRun: operation '${opId}' cannot verify source without its admitted request`,\n )\n }\n assertRunCancellationMatchesCandidate(acknowledged, candidate)\n return acknowledged\n }\n // A new request names who stops the run. A replay of a request written before this rule keeps\n // its absent operator: it was admitted above against the file it replays.\n if (pending === undefined && (options.operator === undefined || options.operator.trim() === '')) {\n throw new Error('cancelRun: operator is required; name who stops the run')\n }\n const source = options.source ?? 'human'\n const request: RunCancelRequest = pending ?? {\n operationId: opId,\n at: new Date().toISOString(),\n source,\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n ...(options.deadlineMs === undefined ? {} : { deadlineMs: options.deadlineMs }),\n ...(options.operator === undefined ? {} : { operator: options.operator }),\n }\n if (pending === undefined) {\n const dir = workerCancellationsDir(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel request')\n mkdirSync(dir, { recursive: true })\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel request')\n const file = runCancelRequestFile(eventDir)\n assertNoSymlinkDescendant(eventDir, file, 'run cancel request')\n writeAtomicDurableFile(file, `${JSON.stringify(request, null, 2)}\\n`, { mode: 0o600 })\n appendWorkerControlEvent(eventDir, 'run', {\n kind: 'run-cancel-request',\n operationId: opId,\n source,\n queued: true,\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n ...(options.deadlineMs === undefined ? {} : { deadlineMs: options.deadlineMs }),\n ...(options.operator === undefined ? {} : { operator: options.operator }),\n })\n }\n return {\n operationId: opId,\n effect: 'unknown',\n requestedAt: request.at,\n observedAt: request.at,\n ...(request.reason === undefined ? {} : { reason: request.reason }),\n ...(request.operator === undefined ? {} : { operator: request.operator }),\n detail: 'request queued; no runtime acknowledger has answered yet',\n }\n}\n\ntype RunCancelRequestCandidate = Omit<RunCancelRequest, 'at'>\n\nfunction assertSameRunCancelRequest(\n existing: RunCancelRequest,\n candidate: RunCancelRequestCandidate,\n): void {\n if (existing.operationId !== candidate.operationId) {\n throw new Error(`cancelRun: operation '${candidate.operationId}' has an id collision`)\n }\n if (existing.source !== candidate.source) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request ` +\n `(source '${existing.source}' != '${candidate.source}')`,\n )\n }\n if (existing.deadlineMs !== candidate.deadlineMs) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request (deadlineMs differs)`,\n )\n }\n if (existing.reason !== candidate.reason) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request ` +\n `(reason differs)`,\n )\n }\n if (existing.operator !== candidate.operator) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request ` +\n `(operator '${existing.operator}' != '${candidate.operator}')`,\n )\n }\n}\n\nfunction assertRunCancellationMatchesCandidate(\n existing: RunCancellation,\n candidate: RunCancelRequestCandidate,\n): void {\n if (existing.reason !== candidate.reason) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its acknowledgement ` +\n `(reason differs)`,\n )\n }\n // An acknowledgement written before acknowledgements carried the operator (0.251.0) names none\n // even when its admitted request does. The request comparator has already held the candidate\n // to that request, so a legacy record matches any candidate operator; a record that names one\n // must name the same one.\n if (existing.operator !== undefined && existing.operator !== candidate.operator) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its acknowledgement ` +\n `(operator '${existing.operator}' != '${candidate.operator}')`,\n )\n }\n}\n\nfunction isRunCancelRequest(value: Partial<RunCancelRequest>): value is RunCancelRequest {\n return (\n typeof value.operationId === 'string' &&\n value.operationId.length > 0 &&\n typeof value.at === 'string' &&\n typeof value.source === 'string' &&\n (value.deadlineMs === undefined ||\n (Number.isFinite(value.deadlineMs) && value.deadlineMs >= 0)) &&\n (value.reason === undefined || typeof value.reason === 'string') &&\n (value.operator === undefined || typeof value.operator === 'string')\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-cancellation-BCuu6khW.js","names":[],"sources":["../src/runtime/supervise/coordination-log.ts","../src/runtime/supervise/supervise-identity.ts","../src/runtime/supervise/run-cancellation.ts"],"sourcesContent":["/**\n * Durable side-log for coordination evidence the spawn journal does not own: questions, analyst\n * findings, answer decisions, authorized continuation receipts, delivery-attempt markers, and\n * delivery outcomes. A durable run\n * (`supervise({ runDir })`) appends them as they publish and loads them on resume, so a restarted\n * coordinator retains the exact evidence produced by prior processes.\n *\n * Answer down-events also fold status on load: a question answered before the crash reloads as\n * `answered`, not as a re-blocking `open`. Settled events are skipped (the spawn journal is their\n * ledger). A receipt followed by an attempt but no outcome proves the process died in the delivery\n * window; that outcome remains unknown and no prior instruction is auto-delivered.\n *\n * JSONL, one fsynced record per event, keyed by `runId` — several runs may share one log file\n * exactly as they share one spawn-journal file.\n *\n * @experimental\n */\n\nimport { appendCommittedJsonLine, readCommittedJsonLines } from '../../durable/jsonl-file'\nimport { captureRunWriteContext } from '../../durable/run-fence'\nimport type {\n AnalystFindingEvent,\n DefinedAnalystRecord,\n} from '../../mcp/tools/coordination-analysts'\nimport type { CoordinationEvent } from '../../mcp/tools/coordination-events'\nimport type { ContinuationInstruction } from '../../mcp/tools/coordination-messages'\nimport type {\n QuestionEscalationRecord,\n QuestionRecord,\n} from '../../mcp/tools/coordination-questions'\nimport type { BusRecord } from './event-bus'\nimport type { PeerMailEvent } from './peer-mail'\n\n/** Stable identity of the supervisor that owns one coordination stream. High-level supervision\n * derives it from the exact root/child execution identity plus its parent assignment. */\nexport type CoordinationOwnerId = string\n\n/** Durable delivery evidence retained in commit order. An attempt without a later event carrying\n * the same `receiptId` has an unknown outcome after a crash and is never replayed. */\nexport type CoordinationDeliveryEvidence = Extract<\n CoordinationEvent,\n { readonly type: 'delivery-attempt' | 'steer' | 'answer' }\n>\n\n/** Coordination evidence loaded from prior processes of one durable supervised run. */\nexport interface PriorCoordination {\n /** The owner filter used for this replay. Omitted only for the compatibility all-owner read. */\n readonly ownerId?: CoordinationOwnerId\n /** Every question the prior process raised, with answer-status folded in, raise order. */\n readonly questions: ReadonlyArray<QuestionRecord>\n /** Every analyst finding the prior process published, publish order. */\n readonly findings: ReadonlyArray<AnalystFindingEvent>\n /** Every `ask_parent` escalation the prior process made, raise order. An undelivered one names a\n * question the run raised that nothing above it received — retained so a resuming operator sees\n * it, never auto-redelivered. */\n readonly escalations: ReadonlyArray<QuestionEscalationRecord>\n /** Every lens the prior process DEFINED at run time, definition order. The exact authored bytes\n * and their digest, so an invented lens can be re-registered and any finding it produced can be\n * traced to the words that produced it. Re-registration is the owner's decision, never automatic:\n * the registry may have changed between processes. */\n readonly analystDefinitions: ReadonlyArray<DefinedAnalystRecord>\n /** Every authorized continuation, in commit order. These are evidence, never replayed to a new\n * worker automatically. */\n readonly continuations: ReadonlyArray<ContinuationInstruction>\n /** Delivery intent and result records in commit order, linked to receipts by `receiptId`. */\n readonly deliveryEvidence: ReadonlyArray<CoordinationDeliveryEvidence>\n /** Every peer-mail attempt the prior process made, delivered and refused alike, in commit order.\n * Evidence of what siblings told each other; never replayed into a new worker's inbox. */\n readonly mail: ReadonlyArray<PeerMailEvent>\n /** Exact source-bus stamps in durable append order. Bus `seq` restarts with each process; append\n * order remains the cross-process replay order. */\n readonly records: ReadonlyArray<BusRecord<CoordinationEvent>>\n}\n\n/** The durable coordination side-log seam. `append` records one bus event (kinds it does not\n * persist are ignored); `load` replays a run's prior records folded into `PriorCoordination`. */\nexport interface CoordinationLog {\n append(\n runId: string,\n record: BusRecord<CoordinationEvent>,\n ownerId?: CoordinationOwnerId,\n ): Promise<void>\n load(runId: string, ownerId?: CoordinationOwnerId): Promise<PriorCoordination>\n}\n\ntype CoordinationLogRecord = {\n readonly runId: string\n readonly ownerId?: CoordinationOwnerId\n readonly seq: number\n readonly at: number\n readonly priority: number\n readonly event: CoordinationEvent\n}\n\ntype LegacyCoordinationLogRecord = {\n readonly runId: string\n readonly ownerId?: CoordinationOwnerId\n readonly at: string\n readonly event: CoordinationEvent\n}\n\n/** Persist prior context plus exact continuation authorization, attempt, and result evidence.\n * Settlements have their own journal. */\nfunction persisted(event: CoordinationEvent): boolean {\n return event.type !== 'settled'\n}\n\n/** FS-backed `CoordinationLog`: append-only JSONL, fsynced per record. */\nexport class FileCoordinationLog implements CoordinationLog {\n private readonly writeContext = captureRunWriteContext()\n private appendTail: Promise<void> = Promise.resolve()\n\n constructor(private readonly path: string) {}\n\n async append(\n runId: string,\n record: BusRecord<CoordinationEvent>,\n ownerId?: CoordinationOwnerId,\n ): Promise<void> {\n if (!persisted(record.event)) return\n const append = this.appendTail.then(() =>\n this.writeContext(() => this.appendRecord(runId, record, ownerId)),\n )\n this.appendTail = append.catch(() => undefined)\n return append\n }\n\n private async appendRecord(\n runId: string,\n busRecord: BusRecord<CoordinationEvent>,\n ownerId?: CoordinationOwnerId,\n ): Promise<void> {\n const fs = await import('node:fs/promises')\n const { dirname } = await import('node:path')\n await fs.mkdir(dirname(this.path), { recursive: true })\n const record: CoordinationLogRecord = {\n runId,\n ...(ownerId !== undefined ? { ownerId } : {}),\n ...busRecord,\n }\n await appendCommittedJsonLine(this.path, record)\n }\n\n async load(runId: string, ownerId?: CoordinationOwnerId): Promise<PriorCoordination> {\n return foldCoordinationRecords(\n readCommittedJsonLines<CoordinationLogRecord | LegacyCoordinationLogRecord>(this.path, {\n allowMissing: true,\n }),\n runId,\n ownerId,\n )\n }\n}\n\n/** @internal Shared replay semantics for file and SQL coordination evidence. */\nexport async function foldCoordinationRecords(\n source:\n | Iterable<CoordinationLogRecord | LegacyCoordinationLogRecord>\n | AsyncIterable<CoordinationLogRecord | LegacyCoordinationLogRecord>,\n runId: string,\n ownerId?: CoordinationOwnerId,\n): Promise<PriorCoordination> {\n const byId = new Map<string, QuestionRecord>()\n const findings: AnalystFindingEvent[] = []\n const escalations: QuestionEscalationRecord[] = []\n const analystDefinitions: DefinedAnalystRecord[] = []\n const continuations: ContinuationInstruction[] = []\n const deliveryEvidence: CoordinationDeliveryEvidence[] = []\n const mail: PeerMailEvent[] = []\n const records: BusRecord<CoordinationEvent>[] = []\n let legacySeq = 0\n for await (const stored of source) {\n if (stored.runId !== runId) continue\n // Omitting ownerId preserves the historical all-run read for direct consumers. Runtime always\n // supplies one, so root and nested supervisors never receive one another's evidence.\n if (ownerId !== undefined && stored.ownerId !== ownerId) continue\n const record: BusRecord<CoordinationEvent> =\n 'seq' in stored\n ? {\n seq: stored.seq,\n at: stored.at,\n priority: stored.priority,\n event: stored.event,\n }\n : {\n seq: legacySeq++,\n at: Date.parse(stored.at),\n priority: 0,\n event: stored.event,\n }\n records.push(record)\n const ev = record.event\n if (ev.type === 'delivery-attempt' || ev.type === 'steer' || ev.type === 'answer') {\n deliveryEvidence.push(ev)\n }\n if (ev.type === 'question') {\n byId.set(ev.question.id, ev.question)\n } else if (ev.type === 'finding') {\n findings.push(ev.finding)\n } else if (ev.type === 'answer') {\n // Only accepted delivery resolves a blocking question. Authorization and an attempted\n // refusal remain evidence, but cannot turn \"worker never received the answer\" into answered\n // state on replay. `by` is not on the wire; prior-run is the honest attribution.\n const prior = byId.get(ev.questionId)\n if (prior && ev.down.delivered) {\n byId.set(ev.questionId, {\n ...prior,\n status: 'answered',\n decision: { kind: 'answer', answer: ev.down.instruction, by: 'prior-run' },\n })\n }\n } else if (ev.type === 'instruction') {\n continuations.push(ev.instruction)\n } else if (ev.type === 'mail') {\n mail.push(ev.mail)\n } else if (ev.type === 'escalation') {\n escalations.push(ev.escalation)\n } else if (ev.type === 'analyst-defined') {\n analystDefinitions.push(ev.analyst)\n }\n }\n return {\n ...(ownerId !== undefined ? { ownerId } : {}),\n questions: [...byId.values()],\n findings,\n escalations,\n analystDefinitions,\n continuations,\n deliveryEvidence,\n mail,\n records,\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { resolve } from 'node:path'\nimport {\n type AgentProfile,\n agentProfileSchema,\n canonicalCandidateDigest,\n type Sha256Digest,\n} from '@tangle-network/agent-interface'\nimport { ValidationError } from '../../errors'\nimport type { WorkerSpawnContext } from '../../mcp/tools/coordination-contracts'\nimport type { CoordinationEvent } from '../../mcp/tools/coordination-events'\nimport { deriveNodeExecutionIdentity } from './scope'\nimport { detachedSnapshot } from './snapshot'\nimport type { SupervisorNodeContext } from './supervisor-agent'\nimport type { AgentExecutionRef, NodeExecutionIdentity } from './types'\n\nexport function externalExecutionId(kind: string, identity: unknown): string {\n const digest = canonicalCandidateDigest({ kind, identity })\n return `${kind}-${digest.slice('sha256:'.length)}`\n}\n\nexport function freezeDetached<T>(value: T): T {\n return detachedSnapshot(value, 'supervise')\n}\n\nexport function freezeDetachedProfile(value: unknown): AgentProfile {\n return freezeDetached(agentProfileSchema.parse(value))\n}\n\nexport function canonicalExecution(\n profile: AgentProfile,\n task: unknown,\n rawExecution: AgentExecutionRef | undefined,\n context: string,\n): { readonly identity: NodeExecutionIdentity; readonly ref?: AgentExecutionRef } {\n const execution = rawExecution === undefined ? undefined : freezeDetached(rawExecution)\n if (execution !== undefined) {\n if (typeof execution !== 'object' || execution === null || Array.isArray(execution)) {\n throw new ValidationError(`${context}: execution must be an object`)\n }\n const unknown = Object.keys(execution).filter(\n (key) => key !== 'candidateDigest' && key !== 'correlation',\n )\n if (unknown.length > 0) {\n throw new ValidationError(`${context}: unknown execution fields: ${unknown.join(', ')}`)\n }\n }\n const identity = deriveNodeExecutionIdentity({ profile, execution }, task)\n if (!identity?.profileDigest || !identity.taskDigest) {\n throw new ValidationError(\n `${context}: profile and task must be finite, acyclic canonical JSON for durable identity`,\n )\n }\n const ref: AgentExecutionRef | undefined =\n identity.candidateDigest || identity.correlation\n ? Object.freeze({\n ...(identity.candidateDigest ? { candidateDigest: identity.candidateDigest } : {}),\n ...(identity.correlation ? { correlation: identity.correlation } : {}),\n })\n : undefined\n return { identity, ...(ref ? { ref } : {}) }\n}\n\nexport function rootCoordinationOwner(identity: NodeExecutionIdentity): string {\n return canonicalCandidateDigest({ kind: 'supervisor-root', identity })\n}\n\nexport function childCoordinationOwner(\n parentOwnerId: string,\n identity: NodeExecutionIdentity,\n context: WorkerSpawnContext,\n depth: number,\n): string {\n return canonicalCandidateDigest({\n kind: 'supervisor-child',\n parentOwnerId,\n identity,\n assignment: {\n id: context.assignmentId,\n label: context.label,\n key: context.key ?? null,\n depth,\n },\n })\n}\n\nexport function supervisionRunNamespace(runDir: string | undefined, runId: string): string {\n return canonicalCandidateDigest(\n runDir === undefined\n ? { kind: 'supervise-ephemeral-run', runId, nonce: randomUUID() }\n : { kind: 'supervise-durable-run', runId, runDir: resolve(runDir) },\n )\n}\n\nexport function workerAssignmentNamespace(\n runNamespace: string,\n parentOwnerId: string,\n assignmentId: string,\n): string {\n return canonicalCandidateDigest({\n kind: 'supervise-worker-assignment',\n runNamespace,\n parentOwnerId,\n assignmentId,\n })\n}\n\n/** Hash only durable coordination meaning. Bus sequence/timestamp are delivery metadata and a\n * resumed projection's marker describes the reader, not the original settlement. */\nexport function coordinationEventId(\n context: SupervisorNodeContext,\n event: CoordinationEvent,\n): Sha256Digest {\n const durableEvent =\n event.type === 'settled' && event.worker.resumed === true\n ? (() => {\n const { resumed: _resumed, ...worker } = event.worker\n return { type: 'settled' as const, worker }\n })()\n : event\n return canonicalCandidateDigest({\n kind: 'supervise-coordination-event',\n runNamespace: context.runNamespace,\n ownerId: context.ownerId,\n event: detachedSnapshot(durableEvent, 'supervise coordination event identity'),\n })\n}\n","import { existsSync, mkdirSync, readFileSync, watch } from 'node:fs'\nimport { join } from 'node:path'\nimport type { RetainedRunEffect } from '../retained-run-types'\nimport { assertNoSymlinkDescendant, writeAtomicDurableFile } from './durable-file'\nimport { appendWorkerControlEvent, workerCancellationsDir } from './run-layout'\n\n/** Apply a durable request through the run's existing abort controller. */\nexport function applyRunCancellation(\n dir: string,\n abortRun: (reason: string, request?: RunCancelRequest) => void,\n now: () => string,\n path: 'observer' | 'turn-boundary' | 'fallback' = 'turn-boundary',\n): RunCancellation | undefined {\n const request = readRunCancelRequest(dir)\n if (request === undefined) return undefined\n const prior = readRunCancellation(dir, request.operationId)\n // A request acknowledged only as `cancel_requested` is still owed by this run: the process\n // that issued the abort died before the run settled. Abort again; the record stands.\n if (prior?.effect === 'cancel_requested') {\n abortRun(request.reason ?? 'run cancel requested', request)\n }\n if (prior !== undefined) return prior\n abortRun(request.reason ?? 'run cancel requested', request)\n const observedAt = now()\n const appliedAfterMs = Math.max(0, Date.parse(observedAt) - Date.parse(request.at))\n const record: RunCancellation = {\n operationId: request.operationId,\n effect: 'cancel_requested',\n path,\n appliedAfterMs,\n ...(request.deadlineMs === undefined\n ? {}\n : { deadlineExceeded: appliedAfterMs > request.deadlineMs }),\n requestedAt: request.at,\n observedAt,\n ...(request.reason === undefined ? {} : { reason: request.reason }),\n ...(request.operator === undefined ? {} : { operator: request.operator }),\n detail: 'root abort issued to the whole run; termination not yet proven',\n }\n writeRunCancellation(dir, record)\n return record\n}\n\n/** External drivers may remain silent indefinitely, so turn boundaries cannot observe control. */\nexport function watchRunCancellation(\n dir: string,\n abortRun: (reason: string, request?: RunCancelRequest) => void,\n createWatch: typeof watch = watch,\n) {\n mkdirSync(workerCancellationsDir(dir), { recursive: true })\n let active = true\n let failure: unknown\n // One observer aborts its run once: a request this process already applied, or one a dead\n // process acknowledged, is not re-issued on every poll.\n let aborted = false\n const abortOnce = (reason: string, request?: RunCancelRequest): void => {\n if (aborted) return\n aborted = true\n abortRun(reason, request)\n }\n const check = (path: 'observer' | 'fallback' = 'observer'): void => {\n if (failure !== undefined) throw failure\n if (active) applyRunCancellation(dir, abortOnce, () => new Date().toISOString(), path)\n }\n const fail = (error: unknown): void => {\n if (!active) return\n failure = error\n abortRun(`durable run cancellation observer failed: ${String(error)}`)\n }\n // The watcher is an optimization over the poll loop below (instant pickup instead of ≤100 ms).\n // Creating it can fail for reasons that say NOTHING about this run: the host's inotify budget is\n // exhausted (EMFILE — a shared box with many agents held ~110 of the 128 default user instances\n // when this was measured), or the kernel caps watches (ENOSPC). Degrading to poll-only keeps\n // every durable behavior; failing the run would make a neighboring process's resource use kill\n // runs that never touched the limit. Any other creation error still fails loudly.\n let watcher: ReturnType<typeof watch> | undefined\n try {\n watcher = createWatch(workerCancellationsDir(dir), (_event, filename) => {\n if (!active || (filename !== null && filename !== 'run.request.json')) return\n try {\n check()\n } catch (error) {\n fail(error)\n }\n })\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code\n if (code !== 'EMFILE' && code !== 'ENOSPC') throw error\n }\n watcher?.on('error', fail)\n // Filesystem notifications are advisory. Scan the same durable inbox when one is dropped —\n // and carry the whole observer alone whenever the watcher above could not be created.\n const fallback = setInterval(() => {\n try {\n check('fallback')\n } catch (error) {\n fail(error)\n }\n }, 100)\n fallback.unref()\n return {\n check,\n close(): void {\n active = false\n watcher?.close()\n clearInterval(fallback)\n },\n }\n}\n\n/** One durable run-scoped cancel request: cancel the WHOLE run, not one worker. */\nexport interface RunCancelRequest {\n /** Caller-minted stable operation identifier — the idempotency key of the whole operation. */\n readonly operationId: string\n /** ISO timestamp of the write. */\n readonly at: string\n /** Who asked — 'human', a brain label, a tool name. Provenance, not authorization. */\n readonly source: string\n /** Requested observation target, measured by the acknowledgement's deadlineExceeded field.\n * The observer always cascades eagerly. This does not guarantee scheduler latency or cleanup. */\n readonly deadlineMs?: number\n /** Who stops the run. `cancelRun` requires it on every new request; it is optional here only\n * so a request written before that rule still reads. The settle record carries it. */\n readonly operator?: string\n readonly reason?: string\n}\n\n/**\n * The durable acknowledgement state for the run-scoped cancel operation, keyed by `operationId`.\n * The runtime is the ONLY writer; {@link cancelRun} only reads it.\n *\n * `effect` is the same {@link RetainedRunEffect} vocabulary the worker-scoped and retained-run\n * paths use, so the runtime has one spelling of the four cancellation states:\n * - `'unknown'` — no runtime has answered yet. Never a success.\n * - `'cancel_requested'` — the root manager issued the run's cascading abort; the run's terminal\n * state is not yet observed.\n * - `'cancelled'` — the run reached its terminal cancelled state with confirmed teardown.\n * - `'not_live'` — the run was not live to cancel: it settled on its own despite the\n * request, or it ended before the request was applied.\n */\nexport interface RunCancellation {\n /** Runtime path that issued the cascade. */\n readonly path?: 'observer' | 'turn-boundary' | 'fallback'\n /** Runtime clock elapsed between request timestamp and cascade application. */\n readonly appliedAfterMs?: number\n /** Whether application exceeded the requested deadlineMs; absent when no target was requested. */\n readonly deadlineExceeded?: boolean\n readonly operationId: string\n readonly effect: RetainedRunEffect\n /** ISO timestamp of the original request. */\n readonly requestedAt: string\n /** ISO timestamp of the runtime's most recent observation of this operation. */\n readonly observedAt: string\n /** The caller's reason, carried verbatim from the request. */\n readonly reason?: string\n /** The caller's operator identity, carried verbatim from the request. */\n readonly operator?: string\n /** The runtime's explanation of how it arrived at `effect`. */\n readonly detail?: string\n}\n\n/** The run-scoped cancel request file of one run — one {@link RunCancelRequest}. */\nexport function runCancelRequestFile(eventDir: string): string {\n return join(workerCancellationsDir(eventDir), 'run.request.json')\n}\n\n/** The run-scoped acknowledgement file of one run — one {@link RunCancellation}. */\nexport function runCancellationFile(eventDir: string): string {\n return join(workerCancellationsDir(eventDir), 'run.json')\n}\n\n/** Read the run-scoped cancel request, or `undefined` when none was written. */\nexport function readRunCancelRequest(eventDir: string): RunCancelRequest | undefined {\n const dir = workerCancellationsDir(eventDir)\n const file = runCancelRequestFile(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel request')\n assertNoSymlinkDescendant(eventDir, file, 'run cancel request')\n if (!existsSync(file)) return undefined\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as Partial<RunCancelRequest>\n if (!isRunCancelRequest(parsed)) {\n throw new Error(`run cancel request '${file}' is not a complete RunCancelRequest`)\n }\n return parsed\n}\n\n/**\n * Read the acknowledgement for the run-scoped cancel operation. `undefined` when the runtime has\n * not answered. A record holding a DIFFERENT `operationId` belongs to another operation on the\n * same run — fail loud rather than answer for it.\n */\nexport function readRunCancellation(\n eventDir: string,\n operationId: string,\n): RunCancellation | undefined {\n const dir = workerCancellationsDir(eventDir)\n const file = runCancellationFile(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel acknowledgement')\n assertNoSymlinkDescendant(eventDir, file, 'run cancel acknowledgement')\n if (!existsSync(file)) return undefined\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as RunCancellation\n if (parsed.operationId !== operationId) {\n throw new Error(\n `run cancel acknowledgement '${file}' holds operation '${parsed.operationId}', not ` +\n `'${operationId}' — one run carries one run-scoped cancel operation`,\n )\n }\n return parsed\n}\n\n/**\n * Durably write the run-scoped acknowledgement. The shared writer fsyncs the file and containing\n * directory, so a concurrent reader sees the prior complete record or the new complete record.\n *\n * @internal The runtime is the only intended writer; clients read via {@link readRunCancellation}\n * or {@link cancelRun}.\n */\nexport function writeRunCancellation(eventDir: string, record: RunCancellation): void {\n const dir = workerCancellationsDir(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel acknowledgement')\n mkdirSync(dir, { recursive: true })\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel acknowledgement')\n const file = runCancellationFile(eventDir)\n assertNoSymlinkDescendant(eventDir, file, 'run cancel acknowledgement')\n writeAtomicDurableFile(file, `${JSON.stringify(record, null, 2)}\\n`, { mode: 0o600 })\n}\n\n/**\n * Request the cancellation of the WHOLE run, idempotently, and return the operation's current\n * durable state.\n *\n * The run-scoped twin of {@link cancelWorker}: write the request into the run's cancellation\n * directory, where the run's own root manager applies it — aborting the root through the one\n * cascade controller the run already has, so every live worker comes down with it. This function\n * never applies the cancellation itself; writing a request file is not an acknowledgement.\n *\n * Idempotency is a lookup: when an acknowledgement for `operationId` already exists it is returned\n * AS-IS and nothing is written. A retry that changes the source, reason, deadline, or operator\n * fails closed. A request the runtime has not answered yet returns `effect: 'unknown'` (never a\n * success); call again with the same `operationId` — or {@link readRunCancellation} — to read the\n * acknowledged result after a reconnect.\n *\n * A run carries ONE run-scoped operation: a second request under a different `operationId` throws\n * rather than silently replacing the pending one, because both would claim the same single abort.\n * Reopening a settled run (`supervisePursuit`'s `reopen`) moves that operation aside.\n *\n * A NEW request must name its `operator`, so every stop says who made it. A replay of a request\n * or acknowledgement written before that rule is answered as it was.\n */\nexport function cancelRun(\n eventDir: string,\n operationId: string,\n options: {\n readonly reason?: string\n readonly source?: string\n readonly deadlineMs?: number\n readonly operator?: string\n } = {},\n): RunCancellation {\n if (\n options.deadlineMs !== undefined &&\n (!Number.isFinite(options.deadlineMs) || options.deadlineMs < 0)\n ) {\n throw new Error('cancelRun: deadlineMs must be a finite nonnegative number')\n }\n const opId = operationId.trim()\n if (!opId) throw new Error('cancelRun: operationId is empty')\n const pending = readRunCancelRequest(eventDir)\n if (pending !== undefined && pending.operationId !== opId) {\n throw new Error(\n `cancelRun: run cancel '${pending.operationId}' is already pending for this run; ` +\n `read it with readRunCancellation instead of issuing '${opId}'`,\n )\n }\n const candidate = {\n operationId: opId,\n source: options.source ?? 'human',\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n ...(options.deadlineMs === undefined ? {} : { deadlineMs: options.deadlineMs }),\n ...(options.operator === undefined ? {} : { operator: options.operator }),\n }\n if (pending !== undefined) assertSameRunCancelRequest(pending, candidate)\n const acknowledged = readRunCancellation(eventDir, opId)\n if (acknowledged !== undefined) {\n if (pending === undefined && options.source !== undefined) {\n throw new Error(\n `cancelRun: operation '${opId}' cannot verify source without its admitted request`,\n )\n }\n assertRunCancellationMatchesCandidate(acknowledged, candidate)\n return acknowledged\n }\n // A new request names who stops the run. A replay of a request written before this rule keeps\n // its absent operator: it was admitted above against the file it replays.\n if (pending === undefined && (options.operator === undefined || options.operator.trim() === '')) {\n throw new Error('cancelRun: operator is required; name who stops the run')\n }\n const source = options.source ?? 'human'\n const request: RunCancelRequest = pending ?? {\n operationId: opId,\n at: new Date().toISOString(),\n source,\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n ...(options.deadlineMs === undefined ? {} : { deadlineMs: options.deadlineMs }),\n ...(options.operator === undefined ? {} : { operator: options.operator }),\n }\n if (pending === undefined) {\n const dir = workerCancellationsDir(eventDir)\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel request')\n mkdirSync(dir, { recursive: true })\n assertNoSymlinkDescendant(eventDir, dir, 'run cancel request')\n const file = runCancelRequestFile(eventDir)\n assertNoSymlinkDescendant(eventDir, file, 'run cancel request')\n writeAtomicDurableFile(file, `${JSON.stringify(request, null, 2)}\\n`, { mode: 0o600 })\n appendWorkerControlEvent(eventDir, 'run', {\n kind: 'run-cancel-request',\n operationId: opId,\n source,\n queued: true,\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n ...(options.deadlineMs === undefined ? {} : { deadlineMs: options.deadlineMs }),\n ...(options.operator === undefined ? {} : { operator: options.operator }),\n })\n }\n return {\n operationId: opId,\n effect: 'unknown',\n requestedAt: request.at,\n observedAt: request.at,\n ...(request.reason === undefined ? {} : { reason: request.reason }),\n ...(request.operator === undefined ? {} : { operator: request.operator }),\n detail: 'request queued; no runtime acknowledger has answered yet',\n }\n}\n\ntype RunCancelRequestCandidate = Omit<RunCancelRequest, 'at'>\n\nfunction assertSameRunCancelRequest(\n existing: RunCancelRequest,\n candidate: RunCancelRequestCandidate,\n): void {\n if (existing.operationId !== candidate.operationId) {\n throw new Error(`cancelRun: operation '${candidate.operationId}' has an id collision`)\n }\n if (existing.source !== candidate.source) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request ` +\n `(source '${existing.source}' != '${candidate.source}')`,\n )\n }\n if (existing.deadlineMs !== candidate.deadlineMs) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request (deadlineMs differs)`,\n )\n }\n if (existing.reason !== candidate.reason) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request ` +\n `(reason differs)`,\n )\n }\n if (existing.operator !== candidate.operator) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its admitted request ` +\n `(operator '${existing.operator}' != '${candidate.operator}')`,\n )\n }\n}\n\nfunction assertRunCancellationMatchesCandidate(\n existing: RunCancellation,\n candidate: RunCancelRequestCandidate,\n): void {\n if (existing.reason !== candidate.reason) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its acknowledgement ` +\n `(reason differs)`,\n )\n }\n // An acknowledgement written before acknowledgements carried the operator (0.251.0) names none\n // even when its admitted request does. The request comparator has already held the candidate\n // to that request, so a legacy record matches any candidate operator; a record that names one\n // must name the same one.\n if (existing.operator !== undefined && existing.operator !== candidate.operator) {\n throw new Error(\n `cancelRun: operation '${candidate.operationId}' conflicts with its acknowledgement ` +\n `(operator '${existing.operator}' != '${candidate.operator}')`,\n )\n }\n}\n\nfunction isRunCancelRequest(value: Partial<RunCancelRequest>): value is RunCancelRequest {\n return (\n typeof value.operationId === 'string' &&\n value.operationId.length > 0 &&\n typeof value.at === 'string' &&\n typeof value.source === 'string' &&\n (value.deadlineMs === undefined ||\n (Number.isFinite(value.deadlineMs) && value.deadlineMs >= 0)) &&\n (value.reason === undefined || typeof value.reason === 'string') &&\n (value.operator === undefined || typeof value.operator === 'string')\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { H as spawnJournalRecordEvents } from "./scope-DzhBJrRN.js";
|
|
2
2
|
import { a as readCommittedJsonLines, t as isNoEntError } from "./jsonl-file-CeVYTIQJ.js";
|
|
3
|
-
import { s as readRunParking } from "./supervisor-
|
|
3
|
+
import { s as readRunParking } from "./supervisor-B6sl14OR.js";
|
|
4
4
|
import { a as writeAtomicDurableFile, c as mutateRunClaim, l as runGenerationPath, r as publishExclusiveDurableFile, u as runWithWriteClaim } from "./durable-file-DstVeHcj.js";
|
|
5
|
-
import { r as readRunCancelRequest } from "./run-cancellation-
|
|
5
|
+
import { r as readRunCancelRequest } from "./run-cancellation-BCuu6khW.js";
|
|
6
6
|
import { a as readFailureRecord, o as readSettleRecord } from "./settle-record-BSDDf9Z4.js";
|
|
7
7
|
import { isRecord } from "@tangle-network/agent-core";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
@@ -320,7 +320,8 @@ async function readRunState(runDir) {
|
|
|
320
320
|
if (!settle && !failure && !parking && !holder.holder && !cancelRequest && journal.records.length === 0) return;
|
|
321
321
|
const holderLive = holder.unknown ? void 0 : holder.live;
|
|
322
322
|
const phase = settle ? "settled" : cancelRequest ? "cancelling" : parking ? "parked" : holderLive === true ? "running" : holderLive === false ? "down" : void 0;
|
|
323
|
-
const
|
|
323
|
+
const root = settle?.tree.nodes?.find((node) => node.id === settle.tree.root);
|
|
324
|
+
const failureCode = (settle?.kind === "no-winner" && settle.reason === "driver-failed" ? settle.error?.failure?.code : void 0) ?? root?.failure?.code;
|
|
324
325
|
let latest;
|
|
325
326
|
const observe = (at) => {
|
|
326
327
|
const timestamp = at === void 0 ? void 0 : new Date(at).getTime();
|
|
@@ -347,4 +348,4 @@ async function readRunState(runDir) {
|
|
|
347
348
|
}
|
|
348
349
|
export { readRunDirectoryLock as a, acquireRunDirectoryLock as i, readSpawnJournal as n, runDirectoryHolderIsLive as o, RunDirectoryLockedError as r, readRunState as t };
|
|
349
350
|
|
|
350
|
-
//# sourceMappingURL=run-state-
|
|
351
|
+
//# sourceMappingURL=run-state-ByHiAjUs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-state-DRh8BOFi.js","names":["delay"],"sources":["../src/durable/run-lock.ts","../src/durable/spawn-journal/read.ts","../src/durable/run-state.ts"],"sourcesContent":["import {\n closeSync,\n existsSync,\n fstatSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n} from 'node:fs'\nimport { resolve } from 'node:path'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport {\n type LockHolderRecord,\n type LockIdentity,\n lockHolderVerdict,\n lockIdentity,\n parseLockHolderRecord,\n readLockHolderIdentity,\n} from '@tangle-network/agent-eval/lock-holder'\nimport {\n publishExclusiveDurableFile,\n writeAtomicDurableFile,\n} from '../runtime/supervise/durable-file'\nimport { isNoEntError } from './jsonl-file'\nimport { mutateRunClaim, runGenerationPath, runWithWriteClaim } from './run-fence'\n\n/*\n * Exclusive ownership of one durable run directory for the life of one `supervisePursuit` call.\n *\n * Measured motive (discovery-lab recursive smoke r1): the recovery protocol is\n * `SIGKILL` the runner while a child is live, then resume on the same directory. PID 1527 was\n * killed at 06:20:27Z and PID 2058 resumed at 06:24:59Z. Nothing refused a second process while\n * the first was still alive; two processes on one directory both append to `spawn-journal.jsonl`\n * and `observer.jsonl`, and the recorded assignment keys and settlements stop being one sequence.\n * The operator relied on timing. This lock makes the second process refuse and name the holder.\n *\n * The holder is identified by its pid and the OS's start token for that pid. r1 ran in a\n * container whose pids are small (1527, 2058) and restart from 1, so a pid alone names the wrong\n * process after enough spawns: a lock left by a killed run would then match an unrelated live\n * process and hold the directory until an operator removed the file. Whether a holder is dead is\n * agent-eval's one dead-owner rule (`@tangle-network/agent-eval/lock-holder`): the record carries\n * the start token, host, boot id, pid namespace and the lock file's own inode identity, and a\n * holder is reclaimed only when those prove it gone or its pid reused. A record that cannot prove\n * that, such as one written before these fields existed, is refused and is removed by hand.\n *\n * The lock is operational state, not evidence: replay, projection, and the settle record ignore\n * it. A holder whose process is gone is reclaimed through Eval's crash-recoverable mutation lock.\n */\n\n/** The lock file `supervisePursuit` holds inside a run directory for the life of one call. */\nexport const RUN_DIRECTORY_LOCK_FILE = 'supervise.lock'\n\n/** What the lock file records about its holder. */\nexport interface RunDirectoryLockHolder {\n readonly pid: number\n /** Monotonic acquisition generation; absent on legacy lock records. */\n readonly generation?: number\n /** ISO instant the holder took the lock. */\n readonly startedAt: string\n readonly runId: string\n /** The OS's start token for `pid` when the host reports one. A holder without one is never proved dead. */\n readonly processStart?: string\n /** Hostname of the holder. Records written before it existed are never proved dead. */\n readonly host?: string\n readonly bootId?: string\n readonly pidNamespace?: string\n /** Inode identity of the lock file this record was written into. */\n readonly lock?: LockIdentity\n}\n\n/** A held lock. `release()` removes the file; it is safe to call more than once. */\nexport interface RunDirectoryLock extends RunDirectoryLockHolder {\n readonly generation: number\n readonly path: string\n /** Bind durable writes to this acquisition, including work queued before release. */\n run<T>(operation: () => T): T\n release(): Promise<void>\n}\n\n/** The directory is held by a live process. `holder` is what that process recorded. */\nexport class RunDirectoryLockedError extends Error {\n readonly path: string\n readonly holder: RunDirectoryLockHolder\n\n constructor(path: string, holder: RunDirectoryLockHolder) {\n super(\n `supervisePursuit: ${path} is held by pid ${holder.pid} (run '${holder.runId}', since ${holder.startedAt}); one process drives a run directory at a time`,\n )\n this.name = 'RunDirectoryLockedError'\n this.path = path\n this.holder = holder\n }\n}\n\n/**\n * Take `runDir/supervise.lock`, or refuse.\n *\n * The file is published with its full content or not at all, so a contender never reads a\n * half-written holder. A lock whose holder is proved dead (its pid no longer exists, the pid now\n * belongs to a process with a different start token, or the host rebooted) is stale and is removed\n * under the mutation guard; a holder that is alive or cannot be proved dead refuses. An empty file\n * names no holder and is reclaimed. A file with unreadable content is left in place and refused:\n * reclaiming it could evict a live holder written by something other than this module.\n */\nexport async function acquireRunDirectoryLock(\n runDir: string,\n runId: string,\n now: () => number = Date.now,\n): Promise<RunDirectoryLock> {\n const dir = resolve(runDir)\n const path = resolve(dir, RUN_DIRECTORY_LOCK_FILE)\n mkdirSync(dir, { recursive: true })\n const { pid, ...identity } = readLockHolderIdentity(process.pid)\n const owner = { pid, startedAt: new Date(now()).toISOString(), runId, ...identity }\n return mutateRunClaim(path, () => {\n const existing = readLockFile(path)\n if (existing.state === 'holder' && !holderIsDead(existing)) {\n throw new RunDirectoryLockedError(path, existing.holder)\n }\n let previousGeneration = 0\n try {\n previousGeneration = Number(readFileSync(runGenerationPath(dir), 'utf8'))\n if (!Number.isSafeInteger(previousGeneration) || previousGeneration < 1) {\n throw new Error('invalid run directory generation counter')\n }\n } catch (error) {\n if (!isNoEntError(error)) throw error\n }\n const generation =\n Math.max(\n previousGeneration,\n existing.state === 'holder' ? (existing.holder.generation ?? 0) : 0,\n ) + 1\n if (!Number.isSafeInteger(generation)) throw new Error('run directory generation exhausted')\n writeAtomicDurableFile(runGenerationPath(dir), `${generation}\\n`)\n if (existing.state !== 'missing') removeIfPresent(path)\n const written: { holder?: RunDirectoryLockHolder } = {}\n // The lock file is a hard link of the temporary file, so the temporary file's inode identity\n // is the lock's, and a later verdict can prove this record was written for this very lock.\n const published = publishExclusiveDurableFile(path, (file) => {\n written.holder = Object.freeze({ ...owner, generation, lock: lockIdentity(file) })\n return `${JSON.stringify(written.holder)}\\n`\n })\n const holder = written.holder\n if (!published || holder === undefined) {\n throw new Error(`supervisePursuit: could not take ${path}`)\n }\n let released = false\n return Object.freeze({\n ...holder,\n generation,\n path,\n run: <T>(operation: () => T): T => {\n if (holder.lock === undefined) throw new Error('run lock has no inode identity')\n return runWithWriteClaim({ path, generation, lock: holder.lock }, operation)\n },\n release: async () => {\n if (released) return\n await releaseHolder(path, holder)\n released = true\n },\n })\n })\n}\n\n/** Read the holder a lock file names, or `undefined` when no lock file names one. */\nexport async function readRunDirectoryLock(\n runDir: string,\n): Promise<RunDirectoryLockHolder | undefined> {\n const existing = await readLockFile(resolve(runDir, RUN_DIRECTORY_LOCK_FILE))\n return existing.state === 'holder' ? existing.holder : undefined\n}\n\n/** What {@link runDirectoryHolderIsLive} proved about a run directory's recorded holder. */\nexport interface RunDirectoryHolderLiveness {\n /** False only when the holder that took the lock is proved dead; a holder that cannot be proved dead reads as live. */\n readonly live: boolean\n /** The holder could not be verified on this host. `live` stays conservative for exclusion. */\n readonly unknown?: true\n /** The holder the lock file names. Absent when no lock file names one, which reads as not live. */\n readonly holder?: RunDirectoryLockHolder\n}\n\n/**\n * Whether a run directory is still held by the live process that took its lock.\n *\n * The same rule `acquireRunDirectoryLock` applies to decide whether a lock is stale, exposed so a\n * caller — a supervisor picking up an abandoned directory, an operator tool listing runs — asks\n * the question instead of hand-rolling `process.kill(pid, 0)`. A bare signal probe cannot tell a\n * live holder from an unrelated process that later took the same pid, which is the failure this\n * lock's start token exists to prevent.\n *\n * The answer is ADVISORY: it is read outside the mutation guard `acquireRunDirectoryLock` holds,\n * so a `false` can be stale by the time the caller acts on it and a concurrent acquire can take\n * the directory in between. Reporting and listing are what this is for. A caller that intends to\n * TAKE the directory calls `acquireRunDirectoryLock`, which evaluates the same rule under the\n * guard and refuses atomically.\n */\nexport async function runDirectoryHolderIsLive(\n runDir: string,\n): Promise<RunDirectoryHolderLiveness> {\n const existing = await readLockFile(resolve(runDir, RUN_DIRECTORY_LOCK_FILE))\n if (existing.state !== 'holder') return { live: false }\n const verdict = lockHolderVerdict(existing.record, existing.current)\n return {\n live: verdict.liveness !== 'dead',\n holder: existing.holder,\n ...(verdict.liveness === 'unknown' ? { unknown: true as const } : {}),\n }\n}\n\ntype LockFileState =\n | { readonly state: 'missing' }\n | { readonly state: 'empty' }\n | {\n readonly state: 'holder'\n readonly holder: RunDirectoryLockHolder\n /** The holder as agent-eval's rule reads it; absent when the record names no host. */\n readonly record: LockHolderRecord | undefined\n /** Inode identity of the file the holder was read from. */\n readonly current: LockIdentity\n }\n\nfunction readLockFile(path: string): LockFileState {\n let text: string\n let current: LockIdentity\n try {\n const file = openSync(path, 'r')\n try {\n current = lockIdentity(fstatSync(file, { bigint: true }))\n text = readFileSync(file, 'utf8')\n } finally {\n closeSync(file)\n }\n } catch (error) {\n if (isNoEntError(error)) return { state: 'missing' }\n throw error\n }\n // This module publishes the file with its full content or not at all, so an empty file was\n // not left by a live holder.\n if (text.trim().length === 0) return { state: 'empty' }\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch (cause) {\n throw new Error(`supervisePursuit: ${path} is not a readable lock file; remove it by hand`, {\n cause,\n })\n }\n const record = parsed as Partial<RunDirectoryLockHolder> | null\n if (\n typeof record !== 'object' ||\n record === null ||\n typeof record.pid !== 'number' ||\n !Number.isInteger(record.pid) ||\n record.pid <= 0 ||\n typeof record.startedAt !== 'string' ||\n typeof record.runId !== 'string' ||\n (record.processStart !== undefined && typeof record.processStart !== 'string') ||\n (record.generation !== undefined &&\n (!Number.isSafeInteger(record.generation) || record.generation < 1))\n ) {\n throw new Error(`supervisePursuit: ${path} is not a readable lock file; remove it by hand`)\n }\n const { pid, startedAt, runId, processStart } = record\n // A missing or malformed identity field is dropped, which leaves the holder never provably dead.\n const verdictRecord = parseLockHolderRecord(parsed)\n const { pid: _pid, ...identity } = verdictRecord ?? { pid }\n return {\n state: 'holder',\n holder: Object.freeze({\n pid,\n startedAt,\n runId,\n ...(record.generation === undefined ? {} : { generation: record.generation }),\n ...(processStart === undefined ? {} : { processStart }),\n ...identity,\n }),\n record: verdictRecord,\n current,\n }\n}\n\n/** agent-eval's dead-owner rule: only a holder proved dead is stale; alive or unknown stays held. */\nfunction holderIsDead(existing: Extract<LockFileState, { state: 'holder' }>): boolean {\n return lockHolderVerdict(existing.record, existing.current).liveness === 'dead'\n}\n\n/** Remove the lock only while it still names this holder; a reclaimed lock belongs to its new owner. */\nasync function releaseHolder(path: string, holder: RunDirectoryLockHolder): Promise<void> {\n const deadline = performance.now() + 1_000\n while (existsSync(`${path}.guard`) && performance.now() < deadline) await delay(10)\n mutateRunClaim(path, () => {\n const existing = readLockFile(path)\n if (existing.state !== 'holder') return\n if (\n existing.holder.pid !== holder.pid ||\n existing.holder.startedAt !== holder.startedAt ||\n existing.holder.runId !== holder.runId ||\n existing.holder.processStart !== holder.processStart ||\n existing.holder.generation !== holder.generation ||\n existing.holder.lock?.dev !== holder.lock?.dev ||\n existing.holder.lock?.ino !== holder.lock?.ino ||\n existing.holder.lock?.birthtimeNs !== holder.lock?.birthtimeNs\n )\n return\n removeIfPresent(path)\n })\n}\n\nfunction removeIfPresent(path: string): void {\n try {\n unlinkSync(path)\n } catch (error) {\n if (!isNoEntError(error)) throw error\n }\n}\n","import { createHash } from 'node:crypto'\nimport type { BigIntStats } from 'node:fs'\nimport { type FileHandle, open, stat } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { isRecord } from '@tangle-network/agent-core'\nimport type { NodeId, SpawnEvent } from '../../runtime/supervise/types'\nimport { isNoEntError, readCommittedJsonLines } from '../jsonl-file'\nimport { spawnJournalRecordEvents } from './record-events'\n\n/** Serializable checkpoint of a committed byte boundary, bound to one file and its bytes. */\nexport interface SpawnJournalCursor {\n readonly file: string\n readonly offset: number\n readonly boundary: string\n}\n\n/** Physical groups expand to event records; the owning tree is preserved for every event. */\nexport type SpawnJournalReadRecord =\n | { readonly kind: 'begin'; readonly root: NodeId; readonly at: string }\n | { readonly kind: 'event'; readonly root: NodeId; readonly event: SpawnEvent }\n\nexport interface SpawnJournalReadOptions {\n readonly after?: SpawnJournalCursor\n /** Initial opening-and-tail window, or an incremental page's byte budget. A crossing record\n * is read whole, so one large record can exceed this budget. Omit for complete history. */\n readonly tailBytes?: number\n}\n\nexport interface SpawnJournalReadResult {\n readonly records: ReadonlyArray<SpawnJournalReadRecord>\n /** Absent only when the journal does not exist. Treat as opaque and persist unchanged. */\n readonly cursor?: SpawnJournalCursor\n /** The supplied cursor no longer matches; this page starts over. */\n readonly reset: boolean\n /** An initial opening-and-tail window omitted records between its two windows. */\n readonly truncated: boolean\n /** Bytes after the committed cursor in this snapshot, including an incomplete final write. */\n readonly remainingBytes: number\n}\n\n/** Read a fixed journal prefix, with historical envelopes and framing owned by Runtime.\n * Missing journals return an empty page. Malformed committed records fail; incomplete final\n * writes remain unread for the next call. Cursors detect replacement, truncation and edits at\n * their sampled opening/boundary; they are not integrity proofs against arbitrary file edits.\n */\nexport async function readSpawnJournal(\n runDir: string,\n options: SpawnJournalReadOptions = {},\n): Promise<SpawnJournalReadResult> {\n const { after, tailBytes } = options\n if (tailBytes !== undefined && (!Number.isSafeInteger(tailBytes) || tailBytes < 1)) {\n throw new RangeError('readSpawnJournal: tailBytes must be a positive safe integer')\n }\n const path = join(runDir, 'spawn-journal.jsonl')\n let handle: FileHandle\n try {\n handle = await open(path, 'r')\n } catch (error) {\n if (isNoEntError(error)) {\n return { records: [], reset: after !== undefined, truncated: false, remainingBytes: 0 }\n }\n throw error\n }\n try {\n const snapshot = await handle.stat({ bigint: true })\n if (!snapshot.isFile()) throw new Error(`${path}: expected a regular file`)\n const size = Number(snapshot.size)\n const file = identity(snapshot)\n const resumed =\n after !== undefined &&\n after.file === file &&\n Number.isSafeInteger(after.offset) &&\n after.offset >= 0 &&\n after.offset <= size &&\n after.boundary === (await boundary(handle, after.offset))\n let offset = resumed ? after.offset : 0\n const records: SpawnJournalReadRecord[] = []\n const read = async (start: number, end: number, firstOnly = false): Promise<void> => {\n offset = start\n for await (const record of readCommittedJsonLines<unknown>(path, {\n handle,\n start,\n end,\n strictUtf8: true,\n onCommit: (committed) => {\n offset = committed\n },\n })) {\n if (!isRecord(record) || typeof record.root !== 'string') {\n throw new Error(`${path}: spawn journal record has no root`)\n }\n if (record.kind === 'begin') {\n if (typeof record.at !== 'string') throw new Error(`${path}: begin record has no at`)\n records.push({ kind: 'begin', root: record.root, at: record.at })\n } else {\n for (const event of spawnJournalRecordEvents(record)) {\n if (\n !isRecord(event) ||\n typeof event.kind !== 'string' ||\n typeof event.id !== 'string'\n ) {\n throw new Error(`${path}: spawn journal record has no event identity`)\n }\n records.push({ kind: 'event', root: record.root, event })\n }\n }\n if (firstOnly) break\n }\n }\n let truncated = false\n if (!resumed && tailBytes !== undefined && size > tailBytes) {\n await read(0, size, true)\n const openingEnd = offset\n const tailStart = await lineBoundary(handle, size - tailBytes, size, -1)\n truncated = tailStart > openingEnd\n await read(Math.max(openingEnd, tailStart), size)\n // A long torn tail must not hide the latest committed activity before it.\n if (offset === tailStart && tailStart > openingEnd) {\n const previous = await lineBoundary(handle, tailStart - 1, size, -1)\n truncated = previous > openingEnd\n await read(Math.max(openingEnd, previous), tailStart)\n }\n } else {\n const end =\n resumed && tailBytes !== undefined && size - offset > tailBytes\n ? await lineBoundary(handle, offset + tailBytes, size, 1)\n : size\n await read(offset, end)\n }\n if (identity(await stat(path, { bigint: true })) !== file || (await handle.stat()).size < size)\n throw new Error(`${path}: journal changed while reading its committed prefix`)\n return {\n records,\n cursor: { file, offset, boundary: await boundary(handle, offset) },\n reset: after !== undefined && !resumed,\n truncated,\n remainingBytes: size - offset,\n }\n } finally {\n await handle.close()\n }\n}\n\nfunction identity(info: BigIntStats): string {\n return `${info.dev}:${info.ino}:${info.birthtimeNs}`\n}\n\nasync function bytes(handle: FileHandle, start: number, length: number): Promise<Buffer> {\n const buffer = Buffer.alloc(length)\n const { bytesRead } = await handle.read(buffer, 0, length, start)\n if (bytesRead !== length) throw new Error('spawn journal changed while reading its boundary')\n return buffer\n}\n\nasync function boundary(handle: FileHandle, offset: number): Promise<string> {\n const length = Math.min(offset, 128)\n return createHash('sha256')\n .update(await bytes(handle, 0, length))\n .update(await bytes(handle, offset - length, length))\n .digest('hex')\n}\n\n/** Include the record crossing a tail window or incremental page boundary. */\nasync function lineBoundary(\n handle: FileHandle,\n position: number,\n size: number,\n direction: -1 | 1,\n): Promise<number> {\n while (position > 0 && position < size) {\n const start = direction === -1 ? Math.max(0, position - 65_536) : position\n const end = direction === -1 ? position : Math.min(size, position + 65_536)\n const part = await bytes(handle, start, end - start)\n const newline = direction === -1 ? part.lastIndexOf(10) : part.indexOf(10)\n if (newline !== -1) return start + newline + 1\n position = direction === -1 ? start : end\n }\n return position\n}\n","import type { RuntimeFailureCause } from '../runtime/failure-cause'\nimport { type RunCancelRequest, readRunCancelRequest } from '../runtime/supervise/run-cancellation'\nimport { readRunParking } from '../runtime/supervise/run-parking'\nimport type { SupervisedResult } from '../runtime/supervise/types'\nimport { runDirectoryHolderIsLive } from './run-lock'\nimport { readFailureRecord, readSettleRecord } from './settle-record'\nimport { readSpawnJournal } from './spawn-journal/read'\n\n/** Runtime evidence only. Product-specific launch, checks and trace completeness belong to callers. */\nexport interface RunState {\n /** Absent when a recorded holder cannot be verified on this host. */\n readonly phase?: 'running' | 'parked' | 'cancelling' | 'settled' | 'down'\n /** A persisted typed root failure; legacy failure messages do not establish a code. */\n readonly failureCode?: RuntimeFailureCause['code']\n readonly settle?: SupervisedResult<unknown>\n readonly cancelRequest?: RunCancelRequest\n /** Absent when holder liveness is unknown. This is advisory, never ownership authorization. */\n readonly holderLive?: boolean\n /** Latest explicit Runtime timestamp observed, as ISO UTC; never a filesystem mtime. */\n readonly lastActivityAt?: string\n}\n\n/** Compose maintained record readers. Terminal settlement outranks cancellation and parking;\n * a request remains cancelling until settlement. An unheld run with evidence is down.\n * No Runtime evidence (including a missing or empty directory) returns undefined. Reads are\n * advisory snapshots across independently published files, not a transaction or a resume gate.\n */\nexport async function readRunState(runDir: string): Promise<RunState | undefined> {\n const [settle, failure, parking, holder, journal] = await Promise.all([\n readSettleRecord(runDir),\n readFailureRecord(runDir),\n readRunParking(runDir),\n runDirectoryHolderIsLive(runDir),\n readSpawnJournal(runDir, { tailBytes: 65_536 }),\n ])\n const cancelRequest = readRunCancelRequest(runDir)\n if (\n !settle &&\n !failure &&\n !parking &&\n !holder.holder &&\n !cancelRequest &&\n journal.records.length === 0\n ) {\n return undefined\n }\n const holderLive = holder.unknown ? undefined : holder.live\n const phase = settle\n ? 'settled'\n : cancelRequest\n ? 'cancelling'\n : parking\n ? 'parked'\n : holderLive === true\n ? 'running'\n : holderLive === false\n ? 'down'\n : undefined\n const root = settle?.tree.nodes?.find((node) => node.id === settle.tree.root)\n const failureCode = root?.failure?.code\n let latest: number | undefined\n const observe = (at: string | number | undefined): void => {\n const timestamp = at === undefined ? undefined : new Date(at).getTime()\n if (timestamp !== undefined && Number.isFinite(timestamp)) {\n latest = latest === undefined ? timestamp : Math.max(latest, timestamp)\n }\n }\n observe(failure?.at)\n observe(parking?.since)\n observe(cancelRequest?.at)\n observe(holder.holder?.startedAt)\n for (const record of journal.records)\n observe(record.kind === 'begin' ? record.at : record.event.at)\n for (const node of settle?.tree.nodes ?? []) {\n observe(node.spawnedAt)\n observe(node.settledAt)\n }\n const lastActivityAt = latest === undefined ? undefined : new Date(latest).toISOString()\n return {\n ...(phase === undefined ? {} : { phase }),\n ...(failureCode === undefined ? {} : { failureCode }),\n ...(settle === undefined ? {} : { settle }),\n ...(cancelRequest === undefined ? {} : { cancelRequest }),\n ...(holderLive === undefined ? {} : { holderLive }),\n ...(lastActivityAt === undefined ? {} : { lastActivityAt }),\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-state-ByHiAjUs.js","names":["delay"],"sources":["../src/durable/run-lock.ts","../src/durable/spawn-journal/read.ts","../src/durable/run-state.ts"],"sourcesContent":["import {\n closeSync,\n existsSync,\n fstatSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n} from 'node:fs'\nimport { resolve } from 'node:path'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport {\n type LockHolderRecord,\n type LockIdentity,\n lockHolderVerdict,\n lockIdentity,\n parseLockHolderRecord,\n readLockHolderIdentity,\n} from '@tangle-network/agent-eval/lock-holder'\nimport {\n publishExclusiveDurableFile,\n writeAtomicDurableFile,\n} from '../runtime/supervise/durable-file'\nimport { isNoEntError } from './jsonl-file'\nimport { mutateRunClaim, runGenerationPath, runWithWriteClaim } from './run-fence'\n\n/*\n * Exclusive ownership of one durable run directory for the life of one `supervisePursuit` call.\n *\n * Measured motive (discovery-lab recursive smoke r1): the recovery protocol is\n * `SIGKILL` the runner while a child is live, then resume on the same directory. PID 1527 was\n * killed at 06:20:27Z and PID 2058 resumed at 06:24:59Z. Nothing refused a second process while\n * the first was still alive; two processes on one directory both append to `spawn-journal.jsonl`\n * and `observer.jsonl`, and the recorded assignment keys and settlements stop being one sequence.\n * The operator relied on timing. This lock makes the second process refuse and name the holder.\n *\n * The holder is identified by its pid and the OS's start token for that pid. r1 ran in a\n * container whose pids are small (1527, 2058) and restart from 1, so a pid alone names the wrong\n * process after enough spawns: a lock left by a killed run would then match an unrelated live\n * process and hold the directory until an operator removed the file. Whether a holder is dead is\n * agent-eval's one dead-owner rule (`@tangle-network/agent-eval/lock-holder`): the record carries\n * the start token, host, boot id, pid namespace and the lock file's own inode identity, and a\n * holder is reclaimed only when those prove it gone or its pid reused. A record that cannot prove\n * that, such as one written before these fields existed, is refused and is removed by hand.\n *\n * The lock is operational state, not evidence: replay, projection, and the settle record ignore\n * it. A holder whose process is gone is reclaimed through Eval's crash-recoverable mutation lock.\n */\n\n/** The lock file `supervisePursuit` holds inside a run directory for the life of one call. */\nexport const RUN_DIRECTORY_LOCK_FILE = 'supervise.lock'\n\n/** What the lock file records about its holder. */\nexport interface RunDirectoryLockHolder {\n readonly pid: number\n /** Monotonic acquisition generation; absent on legacy lock records. */\n readonly generation?: number\n /** ISO instant the holder took the lock. */\n readonly startedAt: string\n readonly runId: string\n /** The OS's start token for `pid` when the host reports one. A holder without one is never proved dead. */\n readonly processStart?: string\n /** Hostname of the holder. Records written before it existed are never proved dead. */\n readonly host?: string\n readonly bootId?: string\n readonly pidNamespace?: string\n /** Inode identity of the lock file this record was written into. */\n readonly lock?: LockIdentity\n}\n\n/** A held lock. `release()` removes the file; it is safe to call more than once. */\nexport interface RunDirectoryLock extends RunDirectoryLockHolder {\n readonly generation: number\n readonly path: string\n /** Bind durable writes to this acquisition, including work queued before release. */\n run<T>(operation: () => T): T\n release(): Promise<void>\n}\n\n/** The directory is held by a live process. `holder` is what that process recorded. */\nexport class RunDirectoryLockedError extends Error {\n readonly path: string\n readonly holder: RunDirectoryLockHolder\n\n constructor(path: string, holder: RunDirectoryLockHolder) {\n super(\n `supervisePursuit: ${path} is held by pid ${holder.pid} (run '${holder.runId}', since ${holder.startedAt}); one process drives a run directory at a time`,\n )\n this.name = 'RunDirectoryLockedError'\n this.path = path\n this.holder = holder\n }\n}\n\n/**\n * Take `runDir/supervise.lock`, or refuse.\n *\n * The file is published with its full content or not at all, so a contender never reads a\n * half-written holder. A lock whose holder is proved dead (its pid no longer exists, the pid now\n * belongs to a process with a different start token, or the host rebooted) is stale and is removed\n * under the mutation guard; a holder that is alive or cannot be proved dead refuses. An empty file\n * names no holder and is reclaimed. A file with unreadable content is left in place and refused:\n * reclaiming it could evict a live holder written by something other than this module.\n */\nexport async function acquireRunDirectoryLock(\n runDir: string,\n runId: string,\n now: () => number = Date.now,\n): Promise<RunDirectoryLock> {\n const dir = resolve(runDir)\n const path = resolve(dir, RUN_DIRECTORY_LOCK_FILE)\n mkdirSync(dir, { recursive: true })\n const { pid, ...identity } = readLockHolderIdentity(process.pid)\n const owner = { pid, startedAt: new Date(now()).toISOString(), runId, ...identity }\n return mutateRunClaim(path, () => {\n const existing = readLockFile(path)\n if (existing.state === 'holder' && !holderIsDead(existing)) {\n throw new RunDirectoryLockedError(path, existing.holder)\n }\n let previousGeneration = 0\n try {\n previousGeneration = Number(readFileSync(runGenerationPath(dir), 'utf8'))\n if (!Number.isSafeInteger(previousGeneration) || previousGeneration < 1) {\n throw new Error('invalid run directory generation counter')\n }\n } catch (error) {\n if (!isNoEntError(error)) throw error\n }\n const generation =\n Math.max(\n previousGeneration,\n existing.state === 'holder' ? (existing.holder.generation ?? 0) : 0,\n ) + 1\n if (!Number.isSafeInteger(generation)) throw new Error('run directory generation exhausted')\n writeAtomicDurableFile(runGenerationPath(dir), `${generation}\\n`)\n if (existing.state !== 'missing') removeIfPresent(path)\n const written: { holder?: RunDirectoryLockHolder } = {}\n // The lock file is a hard link of the temporary file, so the temporary file's inode identity\n // is the lock's, and a later verdict can prove this record was written for this very lock.\n const published = publishExclusiveDurableFile(path, (file) => {\n written.holder = Object.freeze({ ...owner, generation, lock: lockIdentity(file) })\n return `${JSON.stringify(written.holder)}\\n`\n })\n const holder = written.holder\n if (!published || holder === undefined) {\n throw new Error(`supervisePursuit: could not take ${path}`)\n }\n let released = false\n return Object.freeze({\n ...holder,\n generation,\n path,\n run: <T>(operation: () => T): T => {\n if (holder.lock === undefined) throw new Error('run lock has no inode identity')\n return runWithWriteClaim({ path, generation, lock: holder.lock }, operation)\n },\n release: async () => {\n if (released) return\n await releaseHolder(path, holder)\n released = true\n },\n })\n })\n}\n\n/** Read the holder a lock file names, or `undefined` when no lock file names one. */\nexport async function readRunDirectoryLock(\n runDir: string,\n): Promise<RunDirectoryLockHolder | undefined> {\n const existing = await readLockFile(resolve(runDir, RUN_DIRECTORY_LOCK_FILE))\n return existing.state === 'holder' ? existing.holder : undefined\n}\n\n/** What {@link runDirectoryHolderIsLive} proved about a run directory's recorded holder. */\nexport interface RunDirectoryHolderLiveness {\n /** False only when the holder that took the lock is proved dead; a holder that cannot be proved dead reads as live. */\n readonly live: boolean\n /** The holder could not be verified on this host. `live` stays conservative for exclusion. */\n readonly unknown?: true\n /** The holder the lock file names. Absent when no lock file names one, which reads as not live. */\n readonly holder?: RunDirectoryLockHolder\n}\n\n/**\n * Whether a run directory is still held by the live process that took its lock.\n *\n * The same rule `acquireRunDirectoryLock` applies to decide whether a lock is stale, exposed so a\n * caller — a supervisor picking up an abandoned directory, an operator tool listing runs — asks\n * the question instead of hand-rolling `process.kill(pid, 0)`. A bare signal probe cannot tell a\n * live holder from an unrelated process that later took the same pid, which is the failure this\n * lock's start token exists to prevent.\n *\n * The answer is ADVISORY: it is read outside the mutation guard `acquireRunDirectoryLock` holds,\n * so a `false` can be stale by the time the caller acts on it and a concurrent acquire can take\n * the directory in between. Reporting and listing are what this is for. A caller that intends to\n * TAKE the directory calls `acquireRunDirectoryLock`, which evaluates the same rule under the\n * guard and refuses atomically.\n */\nexport async function runDirectoryHolderIsLive(\n runDir: string,\n): Promise<RunDirectoryHolderLiveness> {\n const existing = await readLockFile(resolve(runDir, RUN_DIRECTORY_LOCK_FILE))\n if (existing.state !== 'holder') return { live: false }\n const verdict = lockHolderVerdict(existing.record, existing.current)\n return {\n live: verdict.liveness !== 'dead',\n holder: existing.holder,\n ...(verdict.liveness === 'unknown' ? { unknown: true as const } : {}),\n }\n}\n\ntype LockFileState =\n | { readonly state: 'missing' }\n | { readonly state: 'empty' }\n | {\n readonly state: 'holder'\n readonly holder: RunDirectoryLockHolder\n /** The holder as agent-eval's rule reads it; absent when the record names no host. */\n readonly record: LockHolderRecord | undefined\n /** Inode identity of the file the holder was read from. */\n readonly current: LockIdentity\n }\n\nfunction readLockFile(path: string): LockFileState {\n let text: string\n let current: LockIdentity\n try {\n const file = openSync(path, 'r')\n try {\n current = lockIdentity(fstatSync(file, { bigint: true }))\n text = readFileSync(file, 'utf8')\n } finally {\n closeSync(file)\n }\n } catch (error) {\n if (isNoEntError(error)) return { state: 'missing' }\n throw error\n }\n // This module publishes the file with its full content or not at all, so an empty file was\n // not left by a live holder.\n if (text.trim().length === 0) return { state: 'empty' }\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch (cause) {\n throw new Error(`supervisePursuit: ${path} is not a readable lock file; remove it by hand`, {\n cause,\n })\n }\n const record = parsed as Partial<RunDirectoryLockHolder> | null\n if (\n typeof record !== 'object' ||\n record === null ||\n typeof record.pid !== 'number' ||\n !Number.isInteger(record.pid) ||\n record.pid <= 0 ||\n typeof record.startedAt !== 'string' ||\n typeof record.runId !== 'string' ||\n (record.processStart !== undefined && typeof record.processStart !== 'string') ||\n (record.generation !== undefined &&\n (!Number.isSafeInteger(record.generation) || record.generation < 1))\n ) {\n throw new Error(`supervisePursuit: ${path} is not a readable lock file; remove it by hand`)\n }\n const { pid, startedAt, runId, processStart } = record\n // A missing or malformed identity field is dropped, which leaves the holder never provably dead.\n const verdictRecord = parseLockHolderRecord(parsed)\n const { pid: _pid, ...identity } = verdictRecord ?? { pid }\n return {\n state: 'holder',\n holder: Object.freeze({\n pid,\n startedAt,\n runId,\n ...(record.generation === undefined ? {} : { generation: record.generation }),\n ...(processStart === undefined ? {} : { processStart }),\n ...identity,\n }),\n record: verdictRecord,\n current,\n }\n}\n\n/** agent-eval's dead-owner rule: only a holder proved dead is stale; alive or unknown stays held. */\nfunction holderIsDead(existing: Extract<LockFileState, { state: 'holder' }>): boolean {\n return lockHolderVerdict(existing.record, existing.current).liveness === 'dead'\n}\n\n/** Remove the lock only while it still names this holder; a reclaimed lock belongs to its new owner. */\nasync function releaseHolder(path: string, holder: RunDirectoryLockHolder): Promise<void> {\n const deadline = performance.now() + 1_000\n while (existsSync(`${path}.guard`) && performance.now() < deadline) await delay(10)\n mutateRunClaim(path, () => {\n const existing = readLockFile(path)\n if (existing.state !== 'holder') return\n if (\n existing.holder.pid !== holder.pid ||\n existing.holder.startedAt !== holder.startedAt ||\n existing.holder.runId !== holder.runId ||\n existing.holder.processStart !== holder.processStart ||\n existing.holder.generation !== holder.generation ||\n existing.holder.lock?.dev !== holder.lock?.dev ||\n existing.holder.lock?.ino !== holder.lock?.ino ||\n existing.holder.lock?.birthtimeNs !== holder.lock?.birthtimeNs\n )\n return\n removeIfPresent(path)\n })\n}\n\nfunction removeIfPresent(path: string): void {\n try {\n unlinkSync(path)\n } catch (error) {\n if (!isNoEntError(error)) throw error\n }\n}\n","import { createHash } from 'node:crypto'\nimport type { BigIntStats } from 'node:fs'\nimport { type FileHandle, open, stat } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { isRecord } from '@tangle-network/agent-core'\nimport type { NodeId, SpawnEvent } from '../../runtime/supervise/types'\nimport { isNoEntError, readCommittedJsonLines } from '../jsonl-file'\nimport { spawnJournalRecordEvents } from './record-events'\n\n/** Serializable checkpoint of a committed byte boundary, bound to one file and its bytes. */\nexport interface SpawnJournalCursor {\n readonly file: string\n readonly offset: number\n readonly boundary: string\n}\n\n/** Physical groups expand to event records; the owning tree is preserved for every event. */\nexport type SpawnJournalReadRecord =\n | { readonly kind: 'begin'; readonly root: NodeId; readonly at: string }\n | { readonly kind: 'event'; readonly root: NodeId; readonly event: SpawnEvent }\n\nexport interface SpawnJournalReadOptions {\n readonly after?: SpawnJournalCursor\n /** Initial opening-and-tail window, or an incremental page's byte budget. A crossing record\n * is read whole, so one large record can exceed this budget. Omit for complete history. */\n readonly tailBytes?: number\n}\n\nexport interface SpawnJournalReadResult {\n readonly records: ReadonlyArray<SpawnJournalReadRecord>\n /** Absent only when the journal does not exist. Treat as opaque and persist unchanged. */\n readonly cursor?: SpawnJournalCursor\n /** The supplied cursor no longer matches; this page starts over. */\n readonly reset: boolean\n /** An initial opening-and-tail window omitted records between its two windows. */\n readonly truncated: boolean\n /** Bytes after the committed cursor in this snapshot, including an incomplete final write. */\n readonly remainingBytes: number\n}\n\n/** Read a fixed journal prefix, with historical envelopes and framing owned by Runtime.\n * Missing journals return an empty page. Malformed committed records fail; incomplete final\n * writes remain unread for the next call. Cursors detect replacement, truncation and edits at\n * their sampled opening/boundary; they are not integrity proofs against arbitrary file edits.\n */\nexport async function readSpawnJournal(\n runDir: string,\n options: SpawnJournalReadOptions = {},\n): Promise<SpawnJournalReadResult> {\n const { after, tailBytes } = options\n if (tailBytes !== undefined && (!Number.isSafeInteger(tailBytes) || tailBytes < 1)) {\n throw new RangeError('readSpawnJournal: tailBytes must be a positive safe integer')\n }\n const path = join(runDir, 'spawn-journal.jsonl')\n let handle: FileHandle\n try {\n handle = await open(path, 'r')\n } catch (error) {\n if (isNoEntError(error)) {\n return { records: [], reset: after !== undefined, truncated: false, remainingBytes: 0 }\n }\n throw error\n }\n try {\n const snapshot = await handle.stat({ bigint: true })\n if (!snapshot.isFile()) throw new Error(`${path}: expected a regular file`)\n const size = Number(snapshot.size)\n const file = identity(snapshot)\n const resumed =\n after !== undefined &&\n after.file === file &&\n Number.isSafeInteger(after.offset) &&\n after.offset >= 0 &&\n after.offset <= size &&\n after.boundary === (await boundary(handle, after.offset))\n let offset = resumed ? after.offset : 0\n const records: SpawnJournalReadRecord[] = []\n const read = async (start: number, end: number, firstOnly = false): Promise<void> => {\n offset = start\n for await (const record of readCommittedJsonLines<unknown>(path, {\n handle,\n start,\n end,\n strictUtf8: true,\n onCommit: (committed) => {\n offset = committed\n },\n })) {\n if (!isRecord(record) || typeof record.root !== 'string') {\n throw new Error(`${path}: spawn journal record has no root`)\n }\n if (record.kind === 'begin') {\n if (typeof record.at !== 'string') throw new Error(`${path}: begin record has no at`)\n records.push({ kind: 'begin', root: record.root, at: record.at })\n } else {\n for (const event of spawnJournalRecordEvents(record)) {\n if (\n !isRecord(event) ||\n typeof event.kind !== 'string' ||\n typeof event.id !== 'string'\n ) {\n throw new Error(`${path}: spawn journal record has no event identity`)\n }\n records.push({ kind: 'event', root: record.root, event })\n }\n }\n if (firstOnly) break\n }\n }\n let truncated = false\n if (!resumed && tailBytes !== undefined && size > tailBytes) {\n await read(0, size, true)\n const openingEnd = offset\n const tailStart = await lineBoundary(handle, size - tailBytes, size, -1)\n truncated = tailStart > openingEnd\n await read(Math.max(openingEnd, tailStart), size)\n // A long torn tail must not hide the latest committed activity before it.\n if (offset === tailStart && tailStart > openingEnd) {\n const previous = await lineBoundary(handle, tailStart - 1, size, -1)\n truncated = previous > openingEnd\n await read(Math.max(openingEnd, previous), tailStart)\n }\n } else {\n const end =\n resumed && tailBytes !== undefined && size - offset > tailBytes\n ? await lineBoundary(handle, offset + tailBytes, size, 1)\n : size\n await read(offset, end)\n }\n if (identity(await stat(path, { bigint: true })) !== file || (await handle.stat()).size < size)\n throw new Error(`${path}: journal changed while reading its committed prefix`)\n return {\n records,\n cursor: { file, offset, boundary: await boundary(handle, offset) },\n reset: after !== undefined && !resumed,\n truncated,\n remainingBytes: size - offset,\n }\n } finally {\n await handle.close()\n }\n}\n\nfunction identity(info: BigIntStats): string {\n return `${info.dev}:${info.ino}:${info.birthtimeNs}`\n}\n\nasync function bytes(handle: FileHandle, start: number, length: number): Promise<Buffer> {\n const buffer = Buffer.alloc(length)\n const { bytesRead } = await handle.read(buffer, 0, length, start)\n if (bytesRead !== length) throw new Error('spawn journal changed while reading its boundary')\n return buffer\n}\n\nasync function boundary(handle: FileHandle, offset: number): Promise<string> {\n const length = Math.min(offset, 128)\n return createHash('sha256')\n .update(await bytes(handle, 0, length))\n .update(await bytes(handle, offset - length, length))\n .digest('hex')\n}\n\n/** Include the record crossing a tail window or incremental page boundary. */\nasync function lineBoundary(\n handle: FileHandle,\n position: number,\n size: number,\n direction: -1 | 1,\n): Promise<number> {\n while (position > 0 && position < size) {\n const start = direction === -1 ? Math.max(0, position - 65_536) : position\n const end = direction === -1 ? position : Math.min(size, position + 65_536)\n const part = await bytes(handle, start, end - start)\n const newline = direction === -1 ? part.lastIndexOf(10) : part.indexOf(10)\n if (newline !== -1) return start + newline + 1\n position = direction === -1 ? start : end\n }\n return position\n}\n","import type { RuntimeFailureCause } from '../runtime/failure-cause'\nimport { type RunCancelRequest, readRunCancelRequest } from '../runtime/supervise/run-cancellation'\nimport { readRunParking } from '../runtime/supervise/run-parking'\nimport type { SupervisedResult } from '../runtime/supervise/types'\nimport { runDirectoryHolderIsLive } from './run-lock'\nimport { readFailureRecord, readSettleRecord } from './settle-record'\nimport { readSpawnJournal } from './spawn-journal/read'\n\n/** Runtime evidence only. Product-specific launch, checks and trace completeness belong to callers. */\nexport interface RunState {\n /** Absent when a recorded holder cannot be verified on this host. */\n readonly phase?: 'running' | 'parked' | 'cancelling' | 'settled' | 'down'\n /** A persisted typed root failure; legacy failure messages do not establish a code. */\n readonly failureCode?: RuntimeFailureCause['code']\n readonly settle?: SupervisedResult<unknown>\n readonly cancelRequest?: RunCancelRequest\n /** Absent when holder liveness is unknown. This is advisory, never ownership authorization. */\n readonly holderLive?: boolean\n /** Latest explicit Runtime timestamp observed, as ISO UTC; never a filesystem mtime. */\n readonly lastActivityAt?: string\n}\n\n/** Compose maintained record readers. Terminal settlement outranks cancellation and parking;\n * a request remains cancelling until settlement. An unheld run with evidence is down.\n * No Runtime evidence (including a missing or empty directory) returns undefined. Reads are\n * advisory snapshots across independently published files, not a transaction or a resume gate.\n */\nexport async function readRunState(runDir: string): Promise<RunState | undefined> {\n const [settle, failure, parking, holder, journal] = await Promise.all([\n readSettleRecord(runDir),\n readFailureRecord(runDir),\n readRunParking(runDir),\n runDirectoryHolderIsLive(runDir),\n readSpawnJournal(runDir, { tailBytes: 65_536 }),\n ])\n const cancelRequest = readRunCancelRequest(runDir)\n if (\n !settle &&\n !failure &&\n !parking &&\n !holder.holder &&\n !cancelRequest &&\n journal.records.length === 0\n ) {\n return undefined\n }\n const holderLive = holder.unknown ? undefined : holder.live\n const phase = settle\n ? 'settled'\n : cancelRequest\n ? 'cancelling'\n : parking\n ? 'parked'\n : holderLive === true\n ? 'running'\n : holderLive === false\n ? 'down'\n : undefined\n const root = settle?.tree.nodes?.find((node) => node.id === settle.tree.root)\n const failureCode =\n (settle?.kind === 'no-winner' && settle.reason === 'driver-failed'\n ? settle.error?.failure?.code\n : undefined) ?? root?.failure?.code\n let latest: number | undefined\n const observe = (at: string | number | undefined): void => {\n const timestamp = at === undefined ? undefined : new Date(at).getTime()\n if (timestamp !== undefined && Number.isFinite(timestamp)) {\n latest = latest === undefined ? timestamp : Math.max(latest, timestamp)\n }\n }\n observe(failure?.at)\n observe(parking?.since)\n observe(cancelRequest?.at)\n observe(holder.holder?.startedAt)\n for (const record of journal.records)\n observe(record.kind === 'begin' ? record.at : record.event.at)\n for (const node of settle?.tree.nodes ?? []) {\n observe(node.spawnedAt)\n observe(node.settledAt)\n }\n const lastActivityAt = latest === undefined ? undefined : new Date(latest).toISOString()\n return {\n ...(phase === undefined ? {} : { phase }),\n ...(failureCode === undefined ? {} : { failureCode }),\n ...(settle === undefined ? {} : { settle }),\n ...(cancelRequest === undefined ? {} : { cancelRequest }),\n ...(holderLive === undefined ? {} : { holderLive }),\n ...(lastActivityAt === undefined ? {} : { lastActivityAt }),\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as isTraceAnalysisStore, Br as executableAgentProfileSnapshot, G as settledToIteration, Mt as coordinationProfileToolPrefix, Ui as createSandboxTurnEventCollector, Vr as executableAgentSpecSnapshot, X as rollingDispatch, _i as contentAddress, qi as notifySandboxEventObserver, qr as runtimeFailureCauseSchema, rn as insideCursorNamespace, ua as runAbortable } from "./scope-DzhBJrRN.js";
|
|
2
2
|
import { i as ConfigError, m as ValidationError, n as AnalystError, s as PlannerError } from "./errors-AzSuGI23.js";
|
|
3
|
-
import { D as runAgentic, E as refine, M as renderReport, N as profileChatClient, O as sample, j as observe, k as ObservationError, v as loadAuthoredStrategy, x as strategyAuthorContract, y as requestStrategySource } from "./structural-rollout-
|
|
4
|
-
import { $ as
|
|
3
|
+
import { D as runAgentic, E as refine, M as renderReport, N as profileChatClient, O as sample, j as observe, k as ObservationError, v as loadAuthoredStrategy, x as strategyAuthorContract, y as requestStrategySource } from "./structural-rollout-DgvJLTO0.js";
|
|
4
|
+
import { $ as mapWithConcurrency, G as cloneSpend, H as addSpend, I as immutableCandidateValue, J as errorMessage, M as canonicalCandidateDigest$1, Q as isAsyncIterable, R as sha256Bytes$1, S as captureMaterializedWorkspace, St as armDeadlineTimer, W as chargedTokens, X as hasCompleteCacheBreakdown, Y as fnv1a32Hex, Z as isAbortError, at as stringifySafe, dt as zeroSpend, it as sleep, k as markPutStreamVerified, tt as randomSuffix, y as WorkspaceScanLimitError } from "./workspace-streams-BqNM06y4.js";
|
|
5
5
|
import { a as readCommittedJsonLines, c as appendCommittedJsonLine, d as detachedSnapshot, i as readCommittedJsonFile, o as upsertCommittedJsonLine, s as withJsonlFileLock, t as isNoEntError, u as detachedFrozen } from "./jsonl-file-CeVYTIQJ.js";
|
|
6
|
-
import { C as createExecutor, D as runAgentRounds, O as assertBoxlessPromptOptions, P as defaultSelectWinner, V as routerBrain, _ as withDriverExecutor, _t as CheckUnavailableError, b as createExecutorRegistry, bt as mapExecutorResult, j as createSandboxLineage, k as readPromptOptions, n as createSupervisor, q as createWorktreeCliExecutor, v as InMemoryResultBlobStore, xt as verdictFromJudgeScore, y as InMemorySpawnJournal, yt as gateOnDeliverable } from "./supervisor-
|
|
6
|
+
import { C as createExecutor, D as runAgentRounds, O as assertBoxlessPromptOptions, P as defaultSelectWinner, V as routerBrain, _ as withDriverExecutor, _t as CheckUnavailableError, b as createExecutorRegistry, bt as mapExecutorResult, j as createSandboxLineage, k as readPromptOptions, n as createSupervisor, q as createWorktreeCliExecutor, v as InMemoryResultBlobStore, xt as verdictFromJudgeScore, y as InMemorySpawnJournal, yt as gateOnDeliverable } from "./supervisor-B6sl14OR.js";
|
|
7
7
|
import { a as concreteProfileModel, c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, p as canonicalObservedModelParts, t as assertExecutableAgentProfile, v as harnessRunsAgent } from "./model-policy-JOcg3NRs.js";
|
|
8
8
|
import { a as writeAtomicDurableFile } from "./durable-file-DstVeHcj.js";
|
|
9
9
|
import { i as notifyRuntimeHookEvent } from "./runtime-hooks-CsW2pfFk.js";
|
|
10
|
-
import { a as reconcileInterruptedSearchCalls, c as searchExecutor, r as dedicatedLane, x as runtimeShipDecision } from "./search-executor-
|
|
11
|
-
import { y as foldCoordinationRecords } from "./run-cancellation-
|
|
12
|
-
import { a as downMessageRefusalReasons, p as createInMemoryRunContext } from "./coordination-manager-
|
|
13
|
-
import { M as kernelPromptRegistry, S as validateFlowGraph, T as validateGraphTopology, h as runBrainLoop, p as coordinationControlToolNames, t as supervise } from "./supervise-
|
|
10
|
+
import { a as reconcileInterruptedSearchCalls, c as searchExecutor, r as dedicatedLane, x as runtimeShipDecision } from "./search-executor-BJRNavck.js";
|
|
11
|
+
import { y as foldCoordinationRecords } from "./run-cancellation-BCuu6khW.js";
|
|
12
|
+
import { a as downMessageRefusalReasons, p as createInMemoryRunContext } from "./coordination-manager-RSJg5GmY.js";
|
|
13
|
+
import { M as kernelPromptRegistry, S as validateFlowGraph, T as validateGraphTopology, h as runBrainLoop, p as coordinationControlToolNames, t as supervise } from "./supervise-Cqhkb2Oj.js";
|
|
14
14
|
import { _ as compileGraphParameters, a as graphRegistry, b as graphRouteWhenSchema, d as recordGraphRun, g as bindGraphParameters, h as assertGraphTriggerBindings, i as graphFromStored, l as lookupGraph, m as taskShapeDigest, o as graphRunsFor, r as graphDigest, t as digestOfGraph, v as graphTriggerBindingsSchema, y as graphFileSchema } from "./graph-registry-B25FxBZN.js";
|
|
15
|
-
import "./run-state-
|
|
15
|
+
import "./run-state-ByHiAjUs.js";
|
|
16
16
|
import { i as redactProtectedValue, r as redactProtectedReason } from "./protected-redaction-DilFZch5.js";
|
|
17
|
-
import "./provision-supervisor-
|
|
18
|
-
import "./delegate-
|
|
19
|
-
import "./graph-
|
|
17
|
+
import "./provision-supervisor-CtAaJCUa.js";
|
|
18
|
+
import "./delegate-C0cprMUN.js";
|
|
19
|
+
import "./graph-cEg-gquv.js";
|
|
20
20
|
import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, sha256Bytes, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
|
|
21
21
|
import { CODING_HARNESSES, DEFAULT_TRACE_ANALYST_KINDS, InMemoryTraceStore, OUTPUT_VALUE, benjaminiHochberg, buildTrajectory, computeFindingId as computeFindingId$1, confidenceInterval, createTraceAnalyst, expandProfileAxes, makeFinding as makeFinding$1, pairedBootstrap, paretoFrontier, wilcoxonSignedRank, wilson } from "@tangle-network/agent-eval";
|
|
22
22
|
import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
|
|
@@ -10096,4 +10096,4 @@ function tail(s) {
|
|
|
10096
10096
|
}
|
|
10097
10097
|
export { runBenchmark as $, renderLeaderboardHtml as $t, searchPresets as A, sanitizeMcpToolSchema as At, graphFromSessionFacts as B, assertDeclaredCheck as Bt, withUntrackedArtifacts as C, harvestCorpus as Ct, SEARCH_SPEC_CORRELATION_KEY as D, connectStdioMcp as Dt, createFencedSqlRunContext as E, McpSpawnFault as Et, loadProfile as F, secretEnvOfMcpServer as Ft, chatWorkerSeam as G, readDeclaredCheck as Gt, loadGraphFile as H, declaredCheckDeliverable as Ht, pickBestProfile as I, inlineSandboxClient as It, strategyTournament as J, deterministicCompletion as Jt, createChatSessionStore as K, runIsolatedCheck as Kt, profileRegistry as L, loopCampaignDispatch as Lt, connectRemoteSupervisor as M, mcpSecretEnvMetadataKey as Mt, connectRemoteSupervisorControl as N, resolveMcpServerLaunch as Nt, assertSearchSpec as O, materializeLocalMcp as Ot, bestProfileFor as P, resolveSecretEnv as Pt, printBenchmarkReport as Q, pairwiseSignificance as Qt, profileRunsForName as R, loopDispatch as Rt, copyUntrackedIntoClone as S, HarvestError as St, validateStoredGraph as T, resolveSandboxClient as Tt, graphDesignerExtraTools as U, declaredCheckDigest as Ut, GraphFileResolutionError as V, checkProgramDigest as Vt, chatTransportExecutor as W, declaredCheckJudge as Wt, openSandboxRun as X, stopSentinel as Xt, SandboxRunAbortError as Y, sentinelCompletion as Yt, createS3PrivateCasStore as Z, leaderboard as Zt, NOTE_MAX_CHARS as _, buildSteerContext as _t, localShell as a, FileCorpus as at, composeWorkerEvidence as b, observationFromRegistry as bt, createVerifierEnvironment as c, fanout as ct, harvestSurfaceDiffs as d, panel as dt, renderLeaderboardMarkdown as en, createPrivateCasArtifactPort as et, analystsFromRegistry as f, pipeline as ft, EVIDENCE_MAX_CHARS as g, assertTraceDerivedFindings as gt, runCoderChecks as h, widen as ht, jjWorkspace as i, openSqlRunStore as in, runPersonified as it, searchSpecDigest as j, envKeyProvider as jt, compileSearchSpec as k, createMcpEnvironment as kt, boxSurfaceReader as l, flatWidenGate as lt, worktreeFanout as m, verify as mt, makeFinding$1 as n, renderPairwiseMarkdown as nn, trajectoryReport as nt, runInWorkspace as o, InMemoryCorpus as ot, failuresAnalyst as p, selectValidWinner as pt, runStrategyEvolution as q, completionAuthorizes as qt, gitWorkspace as r, SqlRunOwnershipError as rn, definePersona as rt, createWaterfallCollector as s, renderCorpusToInstructions as st, computeFindingId$1 as t, renderLeaderboardSvg as tn, equalKOnCost as tt, fsSurfaceReader as u, loopUntil as ut, VERIFY_TAIL_CHARS as v, createScopeAnalyst as vt, analyzeTrace as w, defineLeaderboard as wt, settledWorkerOut as x, inProcessSandboxClient as xt, closingWorkerNote as y, registryScopeAnalyst as yt, recordProfileRun as z, superviseDispatch as zt };
|
|
10098
10098
|
|
|
10099
|
-
//# sourceMappingURL=runtime-
|
|
10099
|
+
//# sourceMappingURL=runtime-9EYvBcHG.js.map
|