@tangle-network/agent-runtime 0.337.2 → 0.338.0
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/dist/{activation-DRHM55Oo.d.ts → activation-CsbNax2X.d.ts} +92 -4
- package/dist/activation-kbkAuSmY.js +889 -0
- package/dist/activation-kbkAuSmY.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -6
- package/dist/agent.js.map +1 -1
- package/dist/{bundle-BPGjESee.js → bundle-DM60AI2B.js} +2 -2
- package/dist/{bundle-BPGjESee.js.map → bundle-DM60AI2B.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +2 -2
- package/dist/candidate-execution/index.js +4 -5
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/content-digest-sBTLujlK.js +9 -0
- package/dist/content-digest-sBTLujlK.js.map +1 -0
- package/dist/{delegate-B-T_ZB50.js → delegate-Se1YZKMb.js} +2 -2
- package/dist/{delegate-B-T_ZB50.js.map → delegate-Se1YZKMb.js.map} +1 -1
- package/dist/{coordination-driver-BHkFVqIq.js → driver-control-acknowledgers-T2a1Ouay.js} +4514 -4440
- package/dist/driver-control-acknowledgers-T2a1Ouay.js.map +1 -0
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +223 -227
- package/dist/durable.js.map +1 -1
- package/dist/{graph-C4RFlWAJ.js → graph-CY0wH838.js} +65 -18
- package/dist/graph-CY0wH838.js.map +1 -0
- package/dist/{graph-registry-DAI6KNXB.js → graph-registry-By0tUj4S.js} +16 -15
- package/dist/graph-registry-By0tUj4S.js.map +1 -0
- package/dist/{improvement-cycle-D1I4hQvf.js → improve-CWGBT13K.js} +75 -1220
- package/dist/improve-CWGBT13K.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +10 -13
- package/dist/index.js.map +1 -1
- package/dist/{integrations-DopfCC2a.d.ts → integrations-6xttbPi9.d.ts} +3 -3
- package/dist/integrations-dFi-ALk7.js.map +1 -1
- package/dist/intelligence.d.ts +7 -94
- package/dist/intelligence.js +505 -13
- package/dist/intelligence.js.map +1 -1
- package/dist/kernel.d.ts +2 -2
- package/dist/kernel.js +13 -12
- package/dist/{loop-runner-bin-DOuBIJ2O.d.ts → loop-runner-bin-CFnrAHpl.d.ts} +2 -2
- package/dist/{loop-runner-bin-Dv5QvYDH.js → loop-runner-bin-CdPlhy9g.js} +3 -3
- package/dist/{loop-runner-bin-Dv5QvYDH.js.map → loop-runner-bin-CdPlhy9g.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/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +7 -3
- package/dist/mcp/index.js +6 -8
- package/dist/mcp/index.js.map +1 -1
- package/dist/{openai-tools-Oxk4KQrY.d.ts → openai-tools-zh2I_uD7.d.ts} +2 -2
- package/dist/platform.d.ts +7 -2
- package/dist/platform.js +16 -8
- package/dist/platform.js.map +1 -1
- package/dist/{prepare-CER-ZkPp.js → prepare-Bt0IouPq.js} +1241 -586
- package/dist/prepare-Bt0IouPq.js.map +1 -0
- package/dist/{profile-gNUsHNIJ.js → profile-Do-5xO_D.js} +89 -3
- package/dist/profile-Do-5xO_D.js.map +1 -0
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +1 -3
- package/dist/profiles.js.map +1 -1
- package/dist/{protected-model-port-BhpQRTw-.d.ts → protected-model-port-DGxQ8_YM.d.ts} +3 -3
- package/dist/{provision-supervisor-DGegCUH4.js → provision-supervisor-0jMufp4h.js} +12 -9
- package/dist/provision-supervisor-0jMufp4h.js.map +1 -0
- package/dist/record-value-B6bwJxLa.js +12 -0
- package/dist/record-value-B6bwJxLa.js.map +1 -0
- package/dist/{run-layout-Cu8H7aeh.js → run-cancellation-BoW5Sg9Y.js} +174 -95
- package/dist/run-cancellation-BoW5Sg9Y.js.map +1 -0
- package/dist/{runtime-BOGpotnH.js → runtime-D37zRSs7.js} +431 -621
- package/dist/runtime-D37zRSs7.js.map +1 -0
- package/dist/{sandbox-profile-compat-QTkLe1Z6.js → sandbox-profile-compat-xSoVtdWw.js} +690 -697
- package/dist/sandbox-profile-compat-xSoVtdWw.js.map +1 -0
- package/dist/search-executor-DmgUm5p7.js +1916 -0
- package/dist/search-executor-DmgUm5p7.js.map +1 -0
- package/dist/{server-hZWM-G8w.js → server-DQHJszfk.js} +4 -4
- package/dist/server-DQHJszfk.js.map +1 -0
- package/dist/{search-executor-Cm1WZmL-.js → structural-rollout-DAvIE8mw.js} +2261 -3984
- package/dist/structural-rollout-DAvIE8mw.js.map +1 -0
- package/dist/{supervise-CvAKVfue.js → supervise-WuPAwfPh.js} +7793 -5338
- package/dist/supervise-WuPAwfPh.js.map +1 -0
- package/dist/{supervisor-Rz8AGpYb.js → supervisor-CPG1I9UN.js} +26590 -27196
- package/dist/supervisor-CPG1I9UN.js.map +1 -0
- package/dist/testing.d.ts +226 -1
- package/dist/testing.js +13 -14
- package/dist/testing.js.map +1 -1
- package/dist/{top-app-BaMw1W2z.js → top-app-C55Wa7uy.js} +339 -337
- package/dist/top-app-C55Wa7uy.js.map +1 -0
- package/dist/tui/bin.js +1 -1
- package/dist/tui/index.d.ts +17 -15
- package/dist/tui/index.js +2 -2
- package/dist/{types-Dl5L4r8Z.d.ts → types-CrNWif8-.d.ts} +17410 -17173
- package/dist/{workspace-streams-JLjh5DC6.d.ts → workspace-streams-BZZds1Fw.d.ts} +18 -16
- package/package.json +2 -2
- package/skills/agent-graphs/SKILL.md +10 -3
- package/skills/agent-graphs/references/authoring.md +17 -0
- package/skills/profile-authoring/SKILL.md +3 -3
- package/skills/supervise/SKILL.md +2 -2
- package/dist/activation-BDP6Eivv.js +0 -234
- package/dist/activation-BDP6Eivv.js.map +0 -1
- package/dist/coordination-driver-BHkFVqIq.js.map +0 -1
- package/dist/graph-C4RFlWAJ.js.map +0 -1
- package/dist/graph-registry-DAI6KNXB.js.map +0 -1
- package/dist/improvement-cycle-D1I4hQvf.js.map +0 -1
- package/dist/prepare-CER-ZkPp.js.map +0 -1
- package/dist/profile-gNUsHNIJ.js.map +0 -1
- package/dist/protected-model-port-BuRsviSL.js +0 -766
- package/dist/protected-model-port-BuRsviSL.js.map +0 -1
- package/dist/provision-supervisor-DGegCUH4.js.map +0 -1
- package/dist/run-layout-Cu8H7aeh.js.map +0 -1
- package/dist/runtime-BOGpotnH.js.map +0 -1
- package/dist/sandbox-profile-compat-QTkLe1Z6.js.map +0 -1
- package/dist/search-executor-Cm1WZmL-.js.map +0 -1
- package/dist/server-hZWM-G8w.js.map +0 -1
- package/dist/supervise-CvAKVfue.js.map +0 -1
- package/dist/supervisor-Rz8AGpYb.js.map +0 -1
- package/dist/top-app-BaMw1W2z.js.map +0 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { A as verifyMaterializedWorkspace, C as candidateWorkspaceManifest, D as scanMaterializedWorkspaceManifest, E as readVerifiedArtifact, L as deepFreezeCandidate, N as verifiedArtifactChunks, P as canonicalCandidateBytes$1, R as embeddedCandidateArtifact, a as materializeAgentCandidateWorkspaceFromArtifacts, c as verifyAgentCandidateWorkspaceTree,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
5
|
-
import { n as exactProcessProviderAsCandidateExecutor, t as createProtectedAgentCandidateModelPort } from "../protected-model-port-BuRsviSL.js";
|
|
1
|
+
import { A as verifyMaterializedWorkspace, C as candidateWorkspaceManifest, D as scanMaterializedWorkspaceManifest, E as readVerifiedArtifact, L as deepFreezeCandidate, N as verifiedArtifactChunks, P as canonicalCandidateBytes$1, R as embeddedCandidateArtifact, _ as workspaceLimits, a as materializeAgentCandidateWorkspaceFromArtifacts, c as verifyAgentCandidateWorkspaceTree, h as captureAgentCandidateWorkspaceFiles, i as captureAgentCandidateWorkspaceTreeToArtifacts, l as captureAgentCandidateWorkspace, r as captureAgentCandidateWorkspaceToArtifacts, s as verifyAgentCandidateWorkspaceArtifacts, u as createAgentCandidateWorkspacePort, v as persistCandidateOutputArtifact } from "../sandbox-profile-compat-xSoVtdWw.js";
|
|
2
|
+
import { a as applyExactAgentProfileDiff, b as parseExactCandidateProfile, g as omitUndefinedObjectFields, i as agentCandidateProfileAsAgentProfile, o as assertCandidateProfileBinding, p as freezeGenericAgentCandidateProfile, v as parseExactAgentProfile, y as parseExactAgentProfileDiff } from "../profile-Do-5xO_D.js";
|
|
3
|
+
import { t as sealAgentCandidateBundle } from "../bundle-DM60AI2B.js";
|
|
4
|
+
import { A as candidateKnowledgeExecutionPaths, C as sealTerminalDigest, D as exactProcessProviderAsCandidateExecutor, E as sealAgentCandidateModelSettlement, F as CANDIDATE_TRACE_TAGS, N as verifyAgentCandidateBundle, O as CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV, P as CANDIDATE_TRACE_ENV, S as requireStagedTerminal, T as createProtectedAgentCandidateModelPort, _ as assertTerminalMatchesClaim, a as sealAgentCandidateExecutorStopAcknowledgement, b as rejectedFinish, c as beginPreparedCandidateDisposal, d as candidateClaimFileInternals, f as candidateCleanupDeadline, g as assertTerminalAllowedInPhase, h as assertRecoveryMatchesStaged, i as persistCandidateModelSettlementEvidence, j as AGENT_CANDIDATE_EXECUTION_SUPPORT, k as CANDIDATE_KNOWLEDGE_ROOT_ENV, l as consumePreparedCandidateExecution, m as withinCandidateCleanupDeadline, n as executePreparedAgentCandidate, o as candidateExecutionClaim, p as candidateCleanupTimeout, r as RecoveryAgentCandidateTraceStore, s as assertPreparedCandidateIntegrity, t as prepareAgentCandidateExecution, u as InMemoryAgentCandidateExecutionClaimStore, v as assertTerminalMatchesStaged, w as terminalRecord, x as rejectedStage, y as recoveredTerminalRecord } from "../prepare-Bt0IouPq.js";
|
|
6
5
|
import { agentCandidateArtifactRefSchema, agentCandidateExecutionPlanMaterialSchema, agentCandidateMaterializationReceiptSchema, agentCandidateWorkspaceManifestMaterialSchema, agentCandidateWorkspaceSnapshotEvidenceSchema } from "@tangle-network/agent-interface";
|
|
7
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
8
7
|
import { constants, linkSync } from "node:fs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["canonicalCandidateBytes","canonicalCandidateBytes","canonicalCandidateBytes","fsConstants"],"sources":["../../src/candidate-execution/builder.ts","../../src/candidate-execution/claim-file-store.ts","../../src/candidate-execution/dispose.ts","../../src/candidate-execution/protected-model-grant.ts","../../src/candidate-execution/recover.ts","../../src/candidate-execution/workspace-transfer.ts","../../src/candidate-execution/workspace-tree.ts"],"sourcesContent":["import type { CodeSurface } from '@tangle-network/agent-eval/campaign'\nimport { verifyCodeSurface } from '@tangle-network/agent-eval/campaign'\nimport type {\n AgentCandidateCodeDisabled,\n AgentCandidateCodeNoOp,\n AgentCandidateExecution,\n AgentCandidateGitHubRepository,\n AgentCandidateKnowledge,\n AgentCandidateMemoryPolicy,\n AgentCandidateProfile,\n AgentProfile,\n AgentProfileDiff,\n} from '@tangle-network/agent-interface'\nimport { type AgentCandidateBundleInput, sealAgentCandidateBundle } from './bundle'\nimport { embeddedCandidateArtifact } from './digest'\nimport {\n applyExactAgentProfileDiff,\n freezeGenericAgentCandidateProfile,\n parseExactAgentProfile,\n parseExactAgentProfileDiff,\n parseExactCandidateProfile,\n} from './profile'\n\n/** A complete profile that can be frozen without losing behavior. */\nexport type AgentCandidateProfileSource =\n | {\n kind: 'profile'\n profile: AgentProfile\n }\n | {\n kind: 'profile-diffs'\n base: AgentProfile\n /** Applied in order before the resulting profile is frozen into the bundle. */\n diffs: readonly AgentProfileDiff[]\n }\n | {\n kind: 'candidate-profile'\n /** Already converted to the closed, secret-free candidate profile contract. */\n profile: AgentCandidateProfile\n }\n\n/** The only accepted path from an agent-eval code candidate to executable bytes. */\nexport interface AgentCandidateCodeSurfaceSource {\n kind: 'code-surface'\n surface: CodeSurface\n repository: AgentCandidateGitHubRepository\n /** Optional parent directory used to resolve a relative `surface.worktreeRef`. */\n worktreeDir?: string\n}\n\n/** Explicit control/no-op code or one finalized CodeSurface whose bytes must still verify. */\nexport type AgentCandidateCodeSource =\n | AgentCandidateCodeDisabled\n | AgentCandidateCodeNoOp\n | AgentCandidateCodeSurfaceSource\n\n/** Complete measured surfaces and execution policy compiled into one candidate bundle. */\nexport interface BuildAgentCandidateBundleInput {\n profile: AgentCandidateProfileSource\n code: AgentCandidateCodeSource\n execution: AgentCandidateExecution\n knowledge?: AgentCandidateKnowledge\n memory: AgentCandidateMemoryPolicy\n}\n\n/**\n * Compile one measured profile/code candidate into the immutable execution\n * contract. Code bytes are re-read and verified by agent-eval before they are\n * embedded. The returned bundle is schema-validated, canonically digested, and\n * deeply immutable; call `verifyAgentCandidateBundle` at the execution boundary\n * to re-read external memory, repository, and workspace artifacts.\n */\nexport function buildAgentCandidateBundle(\n input: BuildAgentCandidateBundleInput,\n): ReturnType<typeof sealAgentCandidateBundle> {\n const bundle: AgentCandidateBundleInput = {\n kind: 'agent-candidate-bundle',\n digestAlgorithm: 'rfc8785-sha256',\n profile: compileCandidateProfile(input.profile),\n code: compileCandidateCode(input.code),\n execution: input.execution,\n ...(input.knowledge !== undefined ? { knowledge: input.knowledge } : {}),\n memory: input.memory,\n }\n return sealAgentCandidateBundle(bundle)\n}\n\nfunction compileCandidateProfile(source: AgentCandidateProfileSource): AgentCandidateProfile {\n if (source.kind === 'candidate-profile') {\n return parseExactCandidateProfile(source.profile)\n }\n\n if (source.kind === 'profile') {\n return freezeGenericAgentCandidateProfile(source.profile)\n }\n\n if (source.kind !== 'profile-diffs') {\n throw new Error(\n `unsupported candidate profile source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n if (source.diffs.length === 0) {\n throw new Error('profile-diffs source requires at least one AgentProfileDiff')\n }\n let profile = parseExactAgentProfile(source.base, 'base profile')\n for (const [index, inputDiff] of source.diffs.entries()) {\n const diff = parseExactAgentProfileDiff(inputDiff, `profile diff ${index}`)\n profile = applyExactAgentProfileDiff(profile, diff, `profile diff ${index}`)\n }\n return freezeGenericAgentCandidateProfile(profile)\n}\n\nfunction compileCandidateCode(source: AgentCandidateCodeSource): AgentCandidateBundleInput['code'] {\n if (source.kind === 'disabled' || source.kind === 'no-op') return source\n if (source.kind !== 'code-surface') {\n throw new Error(\n `unsupported candidate code source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n\n const verified = verifyCodeSurface(source.surface, source.worktreeDir)\n const patch = embeddedCandidateArtifact(verified.patchBytes)\n if (\n patch.sha256 !== source.surface.patch.sha256 ||\n patch.byteLength !== source.surface.patch.byteLength\n ) {\n throw new Error('verified CodeSurface patch bytes do not match its content identity')\n }\n return {\n kind: 'git-patch',\n repository: source.repository,\n baseCommit: source.surface.baseCommit,\n baseTree: source.surface.baseTree,\n candidateTree: source.surface.candidateTree,\n patch: { format: 'git-diff-binary', artifact: patch },\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { linkSync } from 'node:fs'\nimport { mkdir, open, unlink } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\nimport {\n type AgentCandidateExecutionAttemptRecord,\n type AgentCandidateExecutionAttemptRef,\n type AgentCandidateExecutionClaim,\n type AgentCandidateExecutionClaimResult,\n type AgentCandidateExecutionClaimStore,\n type AgentCandidateExecutionFinishResult,\n type AgentCandidateExecutionLease,\n type AgentCandidateExecutionPhase,\n type AgentCandidateExecutionPhaseResult,\n type AgentCandidateExecutionRecoveryEvidence,\n type AgentCandidateExecutionStageResult,\n type AgentCandidateExecutionTerminalRecord,\n type AgentCandidateExecutionTerminalResult,\n type AgentCandidateRetryRejection,\n candidateClaimFileInternals,\n} from './claim'\nimport {\n assertRecoveryMatchesStaged,\n assertTerminalAllowedInPhase,\n assertTerminalMatchesClaim,\n assertTerminalMatchesStaged,\n recoveredTerminalRecord,\n rejectedFinish,\n rejectedStage,\n requireStagedTerminal,\n sealTerminalDigest,\n terminalRecord,\n} from './claim-terminal'\nimport { canonicalCandidateBytes } from './digest'\n\nconst {\n assertExpiredLease,\n assertLease,\n assertSameSlot,\n assertUnexpiredLease,\n attemptRecord,\n claimSlot,\n leaseDigest,\n newLease,\n readClaim,\n readClaimIfPresent,\n readTerminal,\n readTerminalIfPresent,\n readTransitionIfPresent,\n rejectedExistingClaim,\n rejectedRetry,\n retryRejection,\n sealAttemptRef,\n sealClaim,\n sealLease,\n} = candidateClaimFileInternals\n\nexport interface FileAgentCandidateExecutionClaimStoreOptions {\n /** Evaluator-owned directory shared by every process allowed to execute candidates. */\n directory: string\n /** Testable evaluator clock; defaults to `Date.now`. */\n now?: () => number\n}\n\n/** Cross-process lifecycle implemented as fsynced, create-if-absent records. */\nexport class FileAgentCandidateExecutionClaimStore implements AgentCandidateExecutionClaimStore {\n private readonly directory: string\n private readonly now: () => number\n\n constructor(options: FileAgentCandidateExecutionClaimStoreOptions) {\n if (options.directory.length === 0) {\n throw new Error('candidate execution claim directory must not be empty')\n }\n this.directory = options.directory\n this.now = options.now ?? Date.now\n }\n\n async tryClaim(\n requested: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateExecutionClaimResult> {\n const claim = sealClaim(requested)\n await mkdir(this.directory, { recursive: true })\n const claimPath = this.claimPath(claim)\n const existing = await readClaimIfPresent(claimPath)\n if (existing) {\n assertSameSlot(existing.claim, claim, claimPath)\n return rejectedExistingClaim(existing.claim, claim)\n }\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n const retryFailure = await this.retryFailure(claim)\n if (retryFailure) return rejectedRetry(claim, retryFailure)\n\n const lease = newLease(claim)\n const acquired = await writeRecordIfAbsent(this.directory, claimPath, {\n ...claim,\n phase: 'claimed',\n leaseDigest: leaseDigest(lease),\n })\n if (acquired) return Object.freeze({ acquired: true, claim, lease })\n\n const winner = await readClaim(claimPath)\n assertSameSlot(winner.claim, claim, claimPath)\n return rejectedExistingClaim(winner.claim, claim)\n }\n\n async getAttempt(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n return await this.storedAttempt(sealAttemptRef(requestedAttempt))\n }\n\n async markCandidateMayRun(\n requestedLease: AgentCandidateExecutionLease,\n ): Promise<AgentCandidateExecutionPhaseResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n if (state.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n if (state.staged) {\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const marked = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, 1),\n {\n kind: 'candidate-execution-phase',\n executionId: stored.claim.executionId,\n attempt: stored.claim.attempt,\n executionPlanDigest: stored.claim.executionPlanDigest,\n phase: 'candidate-may-run',\n },\n this.ownerPublication(stored.claim),\n )\n if (marked) return Object.freeze({ marked: true, phase: 'candidate-may-run' })\n const winner = await this.transitionState(stored.claim)\n if (winner.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n\n async stageTerminal(\n requestedLease: AgentCandidateExecutionLease,\n result: AgentCandidateExecutionTerminalResult,\n ): Promise<AgentCandidateExecutionStageResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const terminal = terminalRecord(stored.claim, result)\n const state = await this.transitionState(stored.claim)\n if (state.staged) return rejectedStage(state.staged, terminal)\n assertTerminalAllowedInPhase(state.phase, terminal)\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const transition = state.phase === 'claimed' ? 1 : 2\n const staged = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal,\n },\n this.ownerPublication(stored.claim),\n )\n if (staged) return Object.freeze({ staged: true, terminal })\n const winner = await this.transitionState(stored.claim)\n if (!winner.staged) {\n throw new Error('candidate execution phase transition won while staging terminal')\n }\n return rejectedStage(winner.staged, terminal)\n }\n\n async finish(\n requestedLease: AgentCandidateExecutionLease,\n requestedTerminalDigest: Sha256Digest,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const lease = sealLease(requestedLease)\n const terminalDigest = sealTerminalDigest(requestedTerminalDigest)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n const staged = requireStagedTerminal(state.staged, terminalDigest)\n const terminalPath = this.terminalPath(lease)\n const existing = await readTerminalIfPresent(terminalPath)\n if (existing) {\n assertTerminalMatchesClaim(existing, stored.claim, terminalPath)\n assertTerminalMatchesStaged(existing, staged, terminalPath)\n return rejectedFinish(existing, terminalDigest)\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const finished = await writeRecordIfAbsent(\n this.directory,\n terminalPath,\n {\n terminal: staged,\n },\n this.ownerPublication(stored.claim),\n )\n if (finished) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, lease, terminalPath)\n assertTerminalMatchesClaim(winner, stored.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, terminalDigest)\n }\n\n async recoverExpired(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n evidence: AgentCandidateExecutionRecoveryEvidence,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const attempt = sealAttemptRef(requestedAttempt)\n const record = await this.storedAttempt(attempt)\n if (!record) throw new Error('candidate execution recovery does not name an acquired attempt')\n const recovered = recoveredTerminalRecord(record.claim, record.phase, evidence)\n if (record.staged) assertRecoveryMatchesStaged(record.staged, recovered)\n const requestedDigest = record.staged?.terminalDigest ?? recovered.terminalDigest\n if (record.terminal) return rejectedFinish(record.terminal, requestedDigest)\n assertExpiredLease(record.claim.leaseExpiresAtMs, this.now())\n\n let staged = record.staged\n if (!staged) {\n const transition = record.phase === 'claimed' ? 1 : 2\n const didStage = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(record.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal: recovered,\n },\n )\n if (didStage) {\n staged = recovered\n } else {\n const winner = await this.transitionState(record.claim)\n if (!winner.staged) {\n throw new Error(\n 'candidate execution recovery lost terminal staging to a phase transition',\n )\n }\n assertRecoveryMatchesStaged(winner.staged, recovered)\n staged = winner.staged\n }\n }\n\n const terminalPath = this.terminalPath(attempt)\n const didFinish = await writeRecordIfAbsent(this.directory, terminalPath, {\n terminal: staged,\n })\n if (didFinish) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, attempt, terminalPath)\n assertTerminalMatchesClaim(winner, record.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, staged.terminalDigest)\n }\n\n private async storedAttempt(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n const claimPath = this.claimPath(claim)\n const stored = await readClaimIfPresent(claimPath)\n if (!stored) return undefined\n assertSameSlot(stored.claim, claim, claimPath)\n const terminalPath = this.terminalPath(claim)\n const terminal = await readTerminalIfPresent(terminalPath)\n // Terminal publication follows its immutable staged outbox, so read that prerequisite later.\n const state = await this.transitionState(stored.claim)\n if (terminal) {\n assertTerminalMatchesClaim(terminal, stored.claim, terminalPath)\n if (!state.staged) {\n throw new Error(\n `candidate execution terminal record at ${terminalPath} has no staged outbox`,\n )\n }\n assertTerminalMatchesStaged(terminal, state.staged, terminalPath)\n }\n return attemptRecord(stored.claim, state.phase, state.staged, terminal)\n }\n\n private async transitionState(claim: AgentCandidateExecutionClaim): Promise<{\n phase: AgentCandidateExecutionPhase\n staged?: AgentCandidateExecutionTerminalRecord\n }> {\n const firstPath = this.transitionPath(claim, 1)\n const first = await readTransitionIfPresent(firstPath, claim)\n if (!first) return { phase: 'claimed' }\n if (first.kind === 'pending') return { phase: 'claimed', staged: first.terminal }\n const secondPath = this.transitionPath(claim, 2)\n const second = await readTransitionIfPresent(secondPath, claim)\n if (!second) return { phase: 'candidate-may-run' }\n if (second.kind !== 'pending') {\n throw new Error(`candidate execution transition at ${secondPath} repeats the phase marker`)\n }\n return { phase: 'candidate-may-run', staged: second.terminal }\n }\n\n private async retryFailure(\n claim: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateRetryRejection | undefined> {\n if (claim.attempt === 1) return undefined\n return retryRejection(\n claim,\n await this.storedAttempt({\n executionId: claim.executionId,\n attempt: claim.attempt - 1,\n }),\n )\n }\n\n private ownerPublication(claim: AgentCandidateExecutionClaim): {\n authorizePublish: () => true\n } {\n return {\n authorizePublish: () => {\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n return true\n },\n }\n }\n\n private claimPath(claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>): string {\n return join(this.directory, `${claimSlot(claim)}.claim.json`)\n }\n\n private terminalPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.terminal.json`)\n }\n\n private transitionPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ordinal: 1 | 2,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.transition-${ordinal}.json`)\n }\n}\n\n/**\n * Candidate records keep this async writer because lease authorization must run after the\n * asynchronous temp-file fsync and immediately before synchronous link publication. The\n * supervisor durability helper is synchronous and has no lease hook, so combining them would\n * either move authorization earlier or add an async race to the claim boundary.\n */\nasync function writeRecordIfAbsent(\n directory: string,\n destination: string,\n record: object,\n options: {\n /** Synchronous authorization checked after temp fsync, immediately before atomic publication. */\n authorizePublish?: () => true\n } = {},\n): Promise<boolean> {\n const temporaryPath = join(directory, `.candidate-execution-${process.pid}-${randomUUID()}.tmp`)\n const handle = await open(temporaryPath, 'wx', 0o600)\n try {\n await handle.writeFile(\n Buffer.concat([Buffer.from(canonicalCandidateBytes(record)), Buffer.from('\\n')]),\n )\n await handle.sync()\n } finally {\n await handle.close()\n }\n\n let written = false\n try {\n if (options.authorizePublish && options.authorizePublish() !== true) {\n throw new Error('candidate execution record publication was not authorized')\n }\n // Authorization and the atomic filesystem call are one synchronous critical\n // section so the event loop cannot advance an injected lease clock between them.\n linkSync(temporaryPath, destination)\n written = true\n await syncDirectory(directory)\n } catch (error) {\n if (!isNodeError(error, 'EEXIST')) throw error\n } finally {\n await unlink(temporaryPath).catch((error: unknown) => {\n if (!isNodeError(error, 'ENOENT')) throw error\n })\n }\n return written\n}\n\nasync function syncDirectory(directory: string): Promise<void> {\n const handle = await open(directory, 'r')\n try {\n await handle.sync()\n } finally {\n await handle.close()\n }\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n (error as { code?: unknown }).code === code\n )\n}\n","import { candidateCleanupDeadline, withinCandidateCleanupDeadline } from './cleanup'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport {\n assertPreparedCandidateIntegrity,\n beginPreparedCandidateDisposal,\n consumePreparedCandidateExecution,\n} from './prepared-state'\nimport type { PreparedAgentCandidateExecution } from './types'\n\nexport interface DisposePreparedAgentCandidateOptions {\n cleanupTimeoutMs?: number\n}\n\n/** Revoke reservations held by a prepared candidate that will not be executed. */\nexport async function disposePreparedAgentCandidateExecution(\n prepared: PreparedAgentCandidateExecution,\n options: DisposePreparedAgentCandidateOptions = {},\n): Promise<{ disposed: true }> {\n const initialState = assertPreparedCandidateIntegrity(prepared)\n const cleanupTimeoutMs = options.cleanupTimeoutMs ?? initialState.cleanupTimeoutMs\n if (cleanupTimeoutMs > initialState.cleanupTimeoutMs) {\n throw new Error('disposal cleanup timeout exceeds the frozen preparation bound')\n }\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const state = beginPreparedCandidateDisposal(prepared)\n const cleanup: Array<Promise<unknown>> = []\n\n if (state.memory.mode === 'isolated') {\n const reservation = state.memoryReservation\n if (!reservation) throw new Error('isolated memory reservation is missing')\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const closed = await state.ports.memory.close({\n executionId: state.executionId,\n preparationId: reservation.preparationId,\n accessDigest: reservation.accessDigest,\n effectiveNamespace: reservation.effectiveNamespace,\n reason: 'abandoned',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('abandoned isolated memory access did not acknowledge closure')\n }\n },\n cleanupDeadlineAtMs,\n 'isolated memory disposal',\n ),\n )\n }\n\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const settlement = sealAgentCandidateModelSettlement(\n await state.ports.models.settleGrant({\n executionId: state.executionId,\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n resolved: state.resolvedModel,\n reason: 'abandoned',\n }),\n {\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n model: state.resolvedModel.model,\n },\n )\n if (settlement.usage.modelCalls !== 0) {\n throw new Error('unexecuted model reservation unexpectedly contains calls')\n }\n },\n cleanupDeadlineAtMs,\n 'model reservation disposal',\n ),\n )\n\n const results = await Promise.allSettled(cleanup)\n const failures = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason)\n if (failures.length > 0) {\n consumePreparedCandidateExecution(prepared, 'disposal-failed')\n throw new AggregateError(failures, 'candidate preparation disposal failed')\n }\n\n consumePreparedCandidateExecution(prepared, 'disposed')\n return Object.freeze({ disposed: true as const })\n}\n","import type { AgentCandidateResolvedModel } from '@tangle-network/agent-interface'\n\nimport type {\n AgentCandidateModelGrantActivateInput,\n AgentCandidateModelGrantReserveInput,\n AgentCandidateModelGrantSettleInput,\n} from './protected-model-port'\nimport type {\n AgentCandidateModelPort,\n AgentCandidateProtectedModelActivation,\n AgentCandidateProtectedModelReservation,\n AgentCandidateProtectedModelSettlement,\n} from './types'\n\n/** Reservation fields supplied by a caller before Runtime resolves the model. */\nexport type AgentCandidateModelGrantRunReservationInput = Omit<\n AgentCandidateModelGrantReserveInput,\n 'resolved'\n>\n\n/** Values available only while one protected model grant is active. */\nexport interface ProtectedAgentCandidateModelGrantContext {\n readonly activation: AgentCandidateProtectedModelActivation\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly resolved: AgentCandidateResolvedModel\n}\n\n/** Inputs for one protected grant scoped to one bounded caller unit. */\nexport interface RunProtectedAgentCandidateModelGrantOptions<TResult> {\n /** Runtime port that validates and settles the evaluator-owned grant. */\n readonly port: AgentCandidateModelPort\n /** Provider-neutral model request resolved before any grant is reserved. */\n readonly resolve: Parameters<AgentCandidateModelPort['resolve']>[0]\n /** One bounded unit's immutable identity, attempt, expiry, and limits. */\n readonly reserve: AgentCandidateModelGrantRunReservationInput\n /** Must be no later than the reservation expiry. */\n readonly deadlineAtMs: AgentCandidateModelGrantActivateInput['deadlineAtMs']\n /** Execute exactly one bounded unit while the activated environment is valid. */\n readonly execute: (context: ProtectedAgentCandidateModelGrantContext) => Promise<TResult>\n}\n\n/** Result and sealed settlement returned after one protected grant closes. */\nexport interface RunProtectedAgentCandidateModelGrantResult<TResult> {\n readonly value: TResult\n readonly resolved: AgentCandidateResolvedModel\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly settlement: AgentCandidateProtectedModelSettlement\n}\n\nconst SETTLEMENT_RETRY_INITIAL_DELAY_MS = 25\nconst SETTLEMENT_RETRY_MAX_DELAY_MS = 1_000\n\n/**\n * Run one bounded unit under a protected model grant.\n *\n * Runtime owns the grant lifecycle; callers own the unit boundary and any\n * durable scheduling or accounting around it. A reserved grant is settled\n * after activation failure or callback failure, and the callback error is\n * preserved when settlement also fails.\n */\nexport async function runProtectedAgentCandidateModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n): Promise<RunProtectedAgentCandidateModelGrantResult<TResult>> {\n if (typeof options.execute !== 'function') {\n throw new TypeError('protected model grant execute callback is required')\n }\n\n const resolved = await options.port.resolve(options.resolve)\n const reservation = await options.port.reserveGrant({\n ...options.reserve,\n resolved,\n })\n\n let value!: TResult\n let executionError: unknown\n let executionFailed = false\n let activated = false\n let reason: AgentCandidateModelGrantSettleInput['reason'] = 'preparation-failed'\n\n try {\n const activation = await options.port.activateGrant({\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n deadlineAtMs: options.deadlineAtMs,\n })\n activated = true\n value = await options.execute({ activation, reservation, resolved })\n reason = 'completed'\n } catch (error) {\n executionError = error\n executionFailed = true\n if (activated) reason = 'failed'\n }\n\n let settlement: AgentCandidateProtectedModelSettlement\n try {\n settlement = await settleProtectedModelGrant(options, {\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n reason,\n })\n } catch (settlementError) {\n if (executionFailed) {\n throw new AggregateError(\n [executionError, settlementError],\n 'protected model execution failed and its grant did not settle',\n )\n }\n throw settlementError\n }\n\n if (executionFailed) throw executionError\n return { value, resolved, reservation, settlement }\n}\n\nasync function settleProtectedModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n input: AgentCandidateModelGrantSettleInput,\n): Promise<AgentCandidateProtectedModelSettlement> {\n let delayMs = SETTLEMENT_RETRY_INITIAL_DELAY_MS\n for (;;) {\n try {\n return await options.port.settleGrant(input)\n } catch (error) {\n if (!isCandidateGrantDrainingError(error)) throw error\n const remainingMs = options.deadlineAtMs - Date.now()\n if (remainingMs <= 0) throw error\n await waitForSettlementRetry(Math.min(delayMs, remainingMs))\n if (Date.now() >= options.deadlineAtMs) throw error\n delayMs = Math.min(delayMs * 2, SETTLEMENT_RETRY_MAX_DELAY_MS)\n }\n }\n}\n\nfunction waitForSettlementRetry(delayMs: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, delayMs))\n}\n\n/** Only the gateway's explicit draining state is retryable; auth and ledger errors fail closed. */\nfunction isCandidateGrantDrainingError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false\n const candidate = error as { code?: unknown; message?: unknown }\n if (candidate.code === 'candidate_grant_draining') return true\n return (\n typeof candidate.message === 'string' && /\\bcandidate_grant_draining\\b/u.test(candidate.message)\n )\n}\n","import type { TraceStore } from '@tangle-network/agent-eval'\nimport type {\n AgentCandidateExecutionPlanMaterial,\n AgentCandidateMaterializationReceipt,\n} from '@tangle-network/agent-interface'\nimport {\n agentCandidateExecutionPlanMaterialSchema,\n agentCandidateMaterializationReceiptSchema,\n} from '@tangle-network/agent-interface'\n\nimport { readVerifiedArtifact } from './artifacts'\nimport type {\n AgentCandidateExecutionAttemptRef,\n AgentCandidateExecutionClaim,\n AgentCandidateExecutionClaimStore,\n AgentCandidateExecutionFinishResult,\n} from './claim'\nimport {\n candidateCleanupDeadline,\n candidateCleanupTimeout,\n withinCandidateCleanupDeadline,\n} from './cleanup'\nimport { canonicalCandidateBytes } from './digest'\nimport { sealAgentCandidateExecutorStopAcknowledgement } from './executor-capture'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport { persistCandidateModelSettlementEvidence } from './outcome-evidence'\nimport { persistCandidateOutputArtifact } from './output-artifacts'\nimport { RecoveryAgentCandidateTraceStore } from './protected-trace-store'\nimport type {\n AgentCandidateExecutionPorts,\n AgentCandidateExecutorPort,\n AgentCandidateOutputArtifactPort,\n} from './types'\n\nexport interface RecoverExpiredAgentCandidateOptions {\n attempt: AgentCandidateExecutionAttemptRef\n claimStore: AgentCandidateExecutionClaimStore\n executor: AgentCandidateExecutorPort\n traceStore: TraceStore\n ports: Pick<AgentCandidateExecutionPorts, 'models' | 'memory'>\n outputArtifacts: AgentCandidateOutputArtifactPort\n cleanupTimeoutMs?: number\n /** Evaluator clock; must be the same clock used by the claim store. */\n now?: () => number\n}\n\n/** Close an expired crashed attempt from persisted non-secret handles, then record failure. */\nexport async function recoverExpiredAgentCandidateExecution(\n options: RecoverExpiredAgentCandidateOptions,\n): Promise<AgentCandidateExecutionFinishResult> {\n const record = await options.claimStore.getAttempt(options.attempt)\n if (!record) throw new Error('candidate execution recovery attempt is missing')\n if (record.terminal) {\n return Object.freeze({ finished: false, terminal: record.terminal, exactReplay: true })\n }\n const cleanupTimeoutMs = candidateCleanupTimeout(\n options.cleanupTimeoutMs ?? record.claim.cleanup.cleanupTimeoutMs,\n )\n if (cleanupTimeoutMs > record.claim.cleanup.cleanupTimeoutMs) {\n throw new Error('recovery cleanup timeout exceeds the frozen preparation bound')\n }\n\n const now = options.now ?? Date.now\n if (now() < record.claim.leaseExpiresAtMs) {\n throw new Error('candidate execution lease has not expired')\n }\n\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const recoveryTraceStore = new RecoveryAgentCandidateTraceStore(options.traceStore)\n const preparation = withinCandidateCleanupDeadline(\n () => readRecoveryPreparation(record.claim, options.outputArtifacts),\n cleanupDeadlineAtMs,\n 'expired candidate preparation evidence read',\n )\n const processClosure = withinCandidateCleanupDeadline(\n async (cleanupSignal) => {\n const stopped = await options.executor.stop(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n {\n traceStore: recoveryTraceStore,\n reason: 'failed',\n signal: cleanupSignal,\n deadlineAtMs: cleanupDeadlineAtMs,\n },\n )\n sealAgentCandidateExecutorStopAcknowledgement(stopped)\n if (options.executor.dispose) {\n const disposed = await options.executor.dispose(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n { signal: cleanupSignal },\n )\n if (disposed.disposed !== true || Object.keys(disposed).some((key) => key !== 'disposed')) {\n throw new Error('expired candidate executor did not acknowledge resource disposal')\n }\n }\n return { stopped: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate process termination',\n )\n\n const modelClosure = withinCandidateCleanupDeadline(\n async () =>\n sealAgentCandidateModelSettlement(\n await options.ports.models.settleGrant({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n resolved: record.claim.cleanup.resolvedModel,\n reason: 'failed',\n }),\n {\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n model: record.claim.cleanup.resolvedModel.model,\n },\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model settlement',\n )\n\n const memoryClosure = record.claim.cleanup.memory\n ? withinCandidateCleanupDeadline(\n async () => {\n const memory = record.claim.cleanup.memory\n if (!memory) throw new Error('expired candidate memory handle is missing')\n const closed = await options.ports.memory.close({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n reason: 'failed',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('expired candidate memory did not acknowledge closure')\n }\n return { closed: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate memory closure',\n )\n : undefined\n\n const closureOutcomes = Promise.allSettled([\n modelClosure,\n memoryClosure ?? Promise.resolve(undefined),\n ] as const)\n const [preparationOutcome, processOutcome] = await Promise.allSettled([\n preparation,\n processClosure,\n ] as const)\n const failures: unknown[] = [preparationOutcome, processOutcome]\n .filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected')\n .map((outcome) => outcome.reason)\n const [modelOutcome, memoryOutcome] = await closureOutcomes\n for (const outcome of [modelOutcome, memoryOutcome]) {\n if (outcome.status === 'rejected') failures.push(outcome.reason)\n }\n if (failures.length > 0) {\n throw new AggregateError(failures, 'expired candidate cleanup could not be proven')\n }\n\n if (modelOutcome.status !== 'fulfilled') {\n throw new Error('expired candidate model settlement was not recovered')\n }\n const model = modelOutcome.value\n const modelSettlement = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateModelSettlementEvidence(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n resolvedModel: record.claim.cleanup.resolvedModel,\n },\n model,\n options.outputArtifacts,\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model-settlement persistence',\n )\n const failureClass =\n record.phase === 'claimed' && model.usage.modelCalls === 0\n ? 'pre-model-infrastructure'\n : 'unknown'\n const failureEvidence = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateOutputArtifact(options.outputArtifacts, {\n executionId: record.claim.executionId,\n purpose: 'failure-evidence',\n bytes: canonicalCandidateBytes({\n kind: 'agent-candidate-recovery-failure',\n executionId: record.claim.executionId,\n attempt: record.claim.attempt,\n bundleDigest: record.claim.bundleDigest,\n executionPlanDigest: record.claim.executionPlanDigest,\n materializationReceiptDigest:\n record.claim.preparationEvidence.materializationReceipt.sha256,\n failureClass,\n processStopped: true,\n modelSettlementDigest: modelSettlement.digest,\n memoryClosed: record.claim.cleanup.memory !== undefined,\n }),\n }),\n cleanupDeadlineAtMs,\n 'expired candidate failure-evidence persistence',\n )\n const memory = record.claim.cleanup.memory\n return await options.claimStore.recoverExpired(options.attempt, {\n failureClass,\n usage: model.usage,\n modelSettlement: modelSettlement.artifact,\n failureEvidence,\n process: {\n stopped: true,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n model: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n },\n ...(memory\n ? {\n memory: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n },\n }\n : {}),\n })\n}\n\nasync function readRecoveryPreparation(\n claim: AgentCandidateExecutionClaim,\n artifacts: AgentCandidateOutputArtifactPort,\n): Promise<{\n plan: AgentCandidateExecutionPlanMaterial\n receipt: AgentCandidateMaterializationReceipt\n}> {\n const [planBytes, receiptBytes] = await Promise.all([\n readVerifiedArtifact(claim.preparationEvidence.executionPlan, artifacts),\n readVerifiedArtifact(claim.preparationEvidence.materializationReceipt, artifacts),\n ])\n const plan = agentCandidateExecutionPlanMaterialSchema.parse(\n parseCanonicalBytes(planBytes, 'plan'),\n )\n if (claim.preparationEvidence.executionPlan.sha256 !== claim.executionPlanDigest) {\n throw new Error('recovery execution plan artifact does not match the claimed digest')\n }\n const receiptMaterial = parseCanonicalBytes(receiptBytes, 'materialization receipt')\n const receipt = agentCandidateMaterializationReceiptSchema.parse({\n ...receiptMaterial,\n digest: claim.preparationEvidence.materializationReceipt.sha256,\n })\n if (\n receipt.bundleDigest !== claim.bundleDigest ||\n receipt.executionPlan.digest !== claim.executionPlanDigest ||\n plan.runCell.bundleDigest !== claim.bundleDigest ||\n plan.executionId !== claim.executionId\n ) {\n throw new Error('recovery preparation evidence does not match the durable claim')\n }\n return { plan, receipt }\n}\n\nfunction parseCanonicalBytes(bytes: Uint8Array, label: string): Record<string, unknown> {\n let parsed: unknown\n try {\n parsed = JSON.parse(Buffer.from(bytes).toString('utf8'))\n } catch (error) {\n throw new Error(`candidate recovery ${label} is not JSON`, { cause: error })\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`candidate recovery ${label} must be an object`)\n }\n if (!Buffer.from(canonicalCandidateBytes(parsed)).equals(Buffer.from(bytes))) {\n throw new Error(`candidate recovery ${label} bytes are not canonical`)\n }\n return parsed as Record<string, unknown>\n}\n","import { lstat } from 'node:fs/promises'\nimport { isAbsolute, resolve } from 'node:path'\nimport {\n type AgentCandidateArtifactRef,\n type AgentCandidateWorkspaceSnapshotEvidence,\n agentCandidateArtifactRefSchema,\n agentCandidateWorkspaceManifestMaterialSchema,\n agentCandidateWorkspaceSnapshotEvidenceSchema,\n} from '@tangle-network/agent-interface'\nimport { verifiedArtifactChunks } from './artifact-streams'\nimport { canonicalCandidateBytes, deepFreezeCandidate } from './digest'\nimport type { AgentCandidateArtifactPort } from './types'\nimport {\n type AgentCandidateWorkspaceArchiveLimits,\n type CaptureAgentCandidateWorkspaceOptions,\n captureAgentCandidateWorkspace,\n createAgentCandidateWorkspacePort,\n workspaceLimits,\n} from './workspace-archive'\n\n/** The canonical workspace evidence without manifest material or embedded file bytes. */\nexport type AgentCandidateWorkspaceSnapshotReferences = Pick<\n AgentCandidateWorkspaceSnapshotEvidence,\n 'kind' | 'digest'\n> & {\n readonly manifest: AgentCandidateArtifactRef\n readonly archive: AgentCandidateArtifactRef\n}\n\nexport type CaptureAgentWorkspaceSnapshotOptions = Omit<\n CaptureAgentCandidateWorkspaceOptions,\n 'artifactPersistence'\n> & {\n artifactPersistence: NonNullable<CaptureAgentCandidateWorkspaceOptions['artifactPersistence']>\n}\n\n/**\n * Capture through the canonical archive owner and return references only.\n * The caller holds its existing private source workspace lease throughout capture, and binds\n * its public source provenance at the SDK boundary. Choose includeRepository and working-tree\n * explicitly when staged, dirty, deleted and unignored untracked Git files must travel.\n */\nexport async function captureAgentWorkspaceSnapshot(\n root: string,\n options: CaptureAgentWorkspaceSnapshotOptions,\n): Promise<AgentCandidateWorkspaceSnapshotReferences> {\n if (!options?.artifactPersistence) {\n throw new Error('portable workspace capture requires artifactPersistence')\n }\n const captured = await captureAgentCandidateWorkspace(root, {\n ...options,\n ...(options.limits ? { limits: { ...options.limits } } : {}),\n artifactPersistence: { ...options.artifactPersistence },\n })\n return workspaceReferences(captured.snapshot)\n}\n\nexport interface MaterializeAgentWorkspaceSnapshotOptions {\n snapshot: AgentCandidateWorkspaceSnapshotReferences\n /** Authorizes each immutable reference for the accepted transfer owner; must stream reads. */\n artifacts: AgentCandidateArtifactPort\n /** Absent destination inside a caller-owned private allocation scope. */\n destination: string\n limits?: Partial<AgentCandidateWorkspaceArchiveLimits>\n signal?: AbortSignal\n}\n\n/**\n * Restore canonical workspace references before an agent starts.\n * The SDK boundary validates source provenance and the accepted snapshot digest before this\n * byte-level composition runs. Artifact references identify content; the injected port owns\n * authorization. The archive owner verifies all files and Git state before publishing fresh\n * staging. Destinations present before or during artifact reads are refused. The caller owns\n * the allocation scope against other writers; Node directory rename is not atomic no-replace.\n */\nexport async function materializeAgentWorkspaceSnapshot(\n input: MaterializeAgentWorkspaceSnapshotOptions,\n): Promise<void> {\n input.signal?.throwIfAborted()\n const snapshot = workspaceReferences(input.snapshot)\n const limits = workspaceLimits(input.limits)\n if (!input.artifacts.readStream) {\n throw new Error('portable workspace restore requires an authorized readStream')\n }\n if (!isAbsolute(input.destination)) {\n throw new Error('portable workspace destination must be absolute')\n }\n const destination = resolve(input.destination)\n await assertAbsentDestination(destination)\n for (const artifact of [snapshot.manifest, snapshot.archive]) {\n if (artifact.byteLength > limits.maxArchiveBytes) {\n throw new Error('portable workspace artifact exceeds maxArchiveBytes')\n }\n }\n const manifest = await readArtifact(snapshot.manifest, input.artifacts, input.signal)\n const material = agentCandidateWorkspaceManifestMaterialSchema.parse(\n JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(manifest)),\n )\n if (!Buffer.from(canonicalCandidateBytes(material)).equals(manifest)) {\n throw new Error('workspace manifest artifact is not the exact canonical manifest material')\n }\n const evidence = agentCandidateWorkspaceSnapshotEvidenceSchema.parse({ ...snapshot, material })\n const archive = await readArtifact(snapshot.archive, input.artifacts, input.signal)\n input.signal?.throwIfAborted()\n // The artifact resolver may await remote storage. A destination that appeared while waiting\n // belongs to its creator, even when it is empty.\n await assertAbsentDestination(destination)\n input.signal?.throwIfAborted()\n await createAgentCandidateWorkspacePort({ limits }).materialize({\n role: 'task',\n snapshot: evidence,\n archive,\n destination,\n ...(input.signal ? { signal: input.signal } : {}),\n })\n}\n\nfunction workspaceReferences(\n snapshot: Pick<\n AgentCandidateWorkspaceSnapshotEvidence,\n 'kind' | 'digest' | 'manifest' | 'archive'\n >,\n): AgentCandidateWorkspaceSnapshotReferences {\n if (snapshot.kind !== 'agent-candidate-workspace-snapshot') {\n throw new Error('portable workspace snapshot kind is invalid')\n }\n const manifest = agentCandidateArtifactRefSchema.parse(snapshot.manifest)\n const archive = agentCandidateArtifactRefSchema.parse(snapshot.archive)\n for (const artifact of [manifest, archive]) {\n if (!Number.isSafeInteger(artifact.byteLength) || artifact.byteLength < 1) {\n throw new Error('portable workspace artifacts require positive safe byte lengths')\n }\n }\n if (snapshot.digest !== manifest.sha256) {\n throw new Error('workspace digest must equal the canonical manifest hash')\n }\n return deepFreezeCandidate({ kind: snapshot.kind, digest: snapshot.digest, manifest, archive })\n}\n\nasync function readArtifact(\n reference: AgentCandidateArtifactRef,\n artifacts: AgentCandidateArtifactPort,\n signal?: AbortSignal,\n): Promise<Buffer> {\n const chunks: Buffer[] = []\n for await (const chunk of verifiedArtifactChunks(reference, artifacts, signal)) {\n chunks.push(Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n\nasync function assertAbsentDestination(destination: string): Promise<void> {\n try {\n await lstat(destination)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n throw error\n }\n throw new Error('portable workspace destination already exists')\n}\n","/**\n * A content digest over a DIRECTORY TREE, and the per-file seed that fills one.\n *\n * The question this answers is \"is this workspace the same workspace\" — the question every launch\n * and every close of a branchable run has to answer, about a tree that a live process is still\n * writing to. That is a different question from the one\n * {@link scanMaterializedWorkspaceManifest} answers, and the difference decides the policies here:\n *\n * - A candidate manifest describes ONE EXACT regular-file workspace. It refuses a symbolic link\n * outright, because `AgentCandidateWorkspaceManifestMaterial` has no representation for one, and\n * it refuses an entry that disappears, because a signed manifest describes a settled tree.\n * - A tree descriptor describes what a RUN PRODUCED. A python venv writes\n * `bin/python -> /usr/bin/python3` as a matter of course, and a work directory can lose an entry\n * between two directory reads. Refusing on either aborts the close, and a run that never wrote\n * its digest can never be branched from.\n *\n * So the two policies are the caller's, one for links and one for vanishing entries, and both\n * default to `'refuse'` — the strict reading, correct for an INPUT seed, where a link that leaves\n * the tree means the seed describes bytes it does not contain. `'exclude'` is the reading a close\n * needs: the entry is never followed, it is recorded, and the exclusion itself is hashed, so two\n * trees that differ only in an excluded entry cannot share a digest.\n *\n * NOTHING is held in memory. A file reaches the tree digest as its own streamed sha-256 plus its\n * length, so the largest file in the tree does not decide whether the tree can be described:\n * `readFile` refuses anything above 2 GiB with `ERR_FS_FILE_TOO_LARGE`, and a single multi-gigabyte\n * artifact is exactly what a run leaves behind.\n *\n * @module\n * @experimental\n */\n\nimport { createHash } from 'node:crypto'\nimport { constants as fsConstants } from 'node:fs'\nimport { cp, lstat, open, readdir, readlink, realpath } from 'node:fs/promises'\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\n/**\n * `'tree-v1'` records a file's exact permission bits. `'portable-tree-v1'` records the two modes\n * Git stores — `755` when any execute bit is set, `644` otherwise, and `755` for a directory — so a\n * digest survives a checkout whose umask differs. Both stamp the algorithm into the digest, so one\n * tree cannot produce the same digest under both.\n */\nexport type WorkspaceTreeAlgorithm = 'tree-v1' | 'portable-tree-v1'\n\n/** What a walk does with an entry it refuses to describe: fail, or record and continue. */\nexport type WorkspaceTreeEntryPolicy = 'refuse' | 'exclude'\n\n/** Why one entry contributed its name instead of its content. */\nexport type WorkspaceTreeExclusionReason =\n | 'absolute-symlink'\n | 'symlink-escapes-tree'\n | 'symlink-resolves-outside-tree'\n | 'unresolved-symlink'\n | 'entry-disappeared'\n\n/** One entry the walk recorded but did not describe. Reported rather than dropped: a digest that\n * silently omitted an entry would be a different digest with no way to tell why. */\nexport interface WorkspaceTreeExclusion {\n /** Tree-relative path, `/`-separated. */\n readonly path: string\n readonly reason: WorkspaceTreeExclusionReason\n /** The link target exactly as it was written, for a symbolic-link exclusion. */\n readonly target?: string\n}\n\nexport interface WorkspaceTreeDescriptor {\n readonly algorithm: WorkspaceTreeAlgorithm\n readonly digest: Sha256Digest\n readonly files: number\n readonly directories: number\n /** Links kept INSIDE the tree. An excluded link is counted in `excluded`, never here. */\n readonly symlinks: number\n /** Total described regular-file bytes. */\n readonly bytes: number\n readonly excluded: ReadonlyArray<WorkspaceTreeExclusion>\n}\n\nexport interface DescribeWorkspaceTreeOptions {\n /** Default `'tree-v1'`. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n /**\n * A symbolic link that is absolute, leaves the tree lexically, resolves outside it, or does not\n * resolve at all. `'refuse'` (default) is correct for an input seed. `'exclude'` is correct for a\n * close-time walk over a tree a run wrote. The link is NEVER followed in either policy: an\n * escaping link must not contribute bytes from outside the tree to a content address.\n */\n readonly onEscapingLink?: WorkspaceTreeEntryPolicy\n /**\n * An entry that vanished between the directory read that named it and the walk that reached it.\n * `'refuse'` (default) is correct for a settled tree; `'exclude'` is correct for a workspace a\n * live process still writes to.\n */\n readonly onMissingEntry?: WorkspaceTreeEntryPolicy\n}\n\nexport interface SeedWorkspaceTreeInput {\n /** The tree to copy FROM. Described, then copied entry by entry. */\n readonly source: string\n /** The tree to copy INTO. Must exist, and must not lie inside `source`. */\n readonly destination: string\n /** Default `'tree-v1'`; decides only the digest this returns, never the bytes it writes. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n}\n\nconst TREE_ALGORITHMS: ReadonlySet<string> = new Set<WorkspaceTreeAlgorithm>([\n 'tree-v1',\n 'portable-tree-v1',\n])\n\nconst ENTRY_POLICIES: ReadonlySet<string> = new Set<WorkspaceTreeEntryPolicy>(['refuse', 'exclude'])\n\n/**\n * Describe one directory tree by content, streaming every file.\n *\n * The digest covers, for every entry in sorted order: its kind, its tree-relative path, its mode\n * under the selected algorithm, and then — for a file, its length and its own sha-256; for a kept\n * link, its target; for an excluded entry, the reason and the target. A file's content therefore\n * never enters the tree hash directly, which is what removes any in-memory size ceiling: the tree\n * hash consumes 32 bytes per file however large the file is.\n *\n * A hard-linked regular file is described like any other regular file. Its content is what the\n * digest is about, and a package manager that links a store into `node_modules` is ordinary\n * content, not a reason to refuse a workspace.\n */\nexport async function describeWorkspaceTree(\n directory: string,\n options: DescribeWorkspaceTreeOptions = {},\n): Promise<WorkspaceTreeDescriptor> {\n const algorithm = options.algorithm ?? 'tree-v1'\n const onEscapingLink = options.onEscapingLink ?? 'refuse'\n const onMissingEntry = options.onMissingEntry ?? 'refuse'\n if (!TREE_ALGORITHMS.has(algorithm)) {\n throw new Error(`unsupported workspace tree algorithm: ${algorithm}`)\n }\n for (const [name, policy] of [\n ['onEscapingLink', onEscapingLink],\n ['onMissingEntry', onMissingEntry],\n ] as const) {\n if (!ENTRY_POLICIES.has(policy)) {\n throw new Error(`unsupported workspace tree ${name} policy: ${policy}`)\n }\n }\n\n const root = resolve(directory)\n const rootStats = await lstatIfPresent(root)\n if (rootStats === null || !rootStats.isDirectory() || rootStats.isSymbolicLink()) {\n throw new Error(`workspace tree root must be a real directory: ${directory}`)\n }\n // Resolve the root once. Every physical containment test below compares against the RESOLVED\n // root, so a symlinked prefix — which is what macOS hands out for a temp directory — does not\n // make every entry look like it escapes.\n const physicalRoot = await realpath(root)\n\n const hash = createHash('sha256')\n // The algorithm is part of the digest. Without this, a tree whose modes already are 755/644\n // produces one digest under both algorithms, and two different questions share one answer.\n hash.update(`workspace-tree\\0${algorithm}\\0`)\n const counts = { files: 0, directories: 0, symlinks: 0, bytes: 0 }\n const excluded: WorkspaceTreeExclusion[] = []\n\n const exclude = (path: string, reason: WorkspaceTreeExclusionReason, target?: string): void => {\n const name = treePath(root, path)\n excluded.push(\n Object.freeze(target === undefined ? { path: name, reason } : { path: name, reason, target }),\n )\n // The reason is hashed with the entry. Two trees that differ only in WHY an entry was excluded\n // are different trees, and a refusal must not become a way to hide a difference.\n hash.update(`excluded\\0${name}\\0${reason}\\0${target ?? ''}\\0`)\n }\n\n /** True when the caller asked to continue past a vanished entry, and it was not the root. */\n const recordMissing = (path: string): boolean => {\n if (onMissingEntry === 'refuse' || path === root) return false\n exclude(path, 'entry-disappeared')\n return true\n }\n\n const visit = async (path: string): Promise<void> => {\n const info = await lstatIfPresent(path)\n if (info === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${treePath(root, path)}`)\n }\n const name = treePath(root, path)\n const mode = entryMode(info.mode, algorithm, info.isDirectory(), info.isSymbolicLink())\n\n if (info.isDirectory()) {\n let entries: string[]\n try {\n entries = await readdir(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n counts.directories += 1\n hash.update(`directory\\0${name}\\0${mode}\\0`)\n for (const entry of entries.sort()) await visit(join(path, entry))\n return\n }\n\n if (info.isSymbolicLink()) {\n await visitSymbolicLink(path, name, mode)\n return\n }\n\n if (!info.isFile()) {\n throw new Error(`workspace tree contains an unsupported entry: ${name}`)\n }\n const read = await digestFile(path)\n if (read === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${name}`)\n }\n counts.files += 1\n counts.bytes += read.byteLength\n hash.update(`file\\0${name}\\0${mode}\\0${read.byteLength}\\0${read.sha256}\\0`)\n }\n\n const visitSymbolicLink = async (path: string, name: string, mode: string): Promise<void> => {\n let target: string\n try {\n target = await readlink(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n const refuse = (reason: WorkspaceTreeExclusionReason): void => {\n if (onEscapingLink === 'refuse') {\n throw new Error(\n `workspace tree contains a link that ${reasonText(reason)}: ${name} -> ${target}`,\n )\n }\n exclude(path, reason, target)\n }\n if (isAbsolute(target)) return refuse('absolute-symlink')\n if (!isWithin(root, resolve(dirname(path), target))) return refuse('symlink-escapes-tree')\n let physicalTarget: string\n try {\n physicalTarget = await realpath(path)\n } catch {\n // A dangling link is a fact about the tree, not a reason to make the run unrecoverable.\n return refuse('unresolved-symlink')\n }\n if (!isWithin(physicalRoot, physicalTarget)) return refuse('symlink-resolves-outside-tree')\n counts.symlinks += 1\n hash.update(`symlink\\0${name}\\0${mode}\\0${target}\\0`)\n }\n\n await visit(root)\n return Object.freeze({\n algorithm,\n digest: `sha256:${hash.digest('hex')}` as Sha256Digest,\n files: counts.files,\n directories: counts.directories,\n symlinks: counts.symlinks,\n bytes: counts.bytes,\n excluded: Object.freeze(excluded),\n })\n}\n\n/**\n * Seed a workspace from a directory, one entry at a time, and return the digest of what was\n * seeded.\n *\n * Nothing is packed: `cp` walks and copies file by file, so a multi-gigabyte seed costs one file\n * handle rather than one archive in memory. Existing destination entries are never overwritten —\n * a seed that could replace a file the workspace already holds would make the resulting tree\n * depend on the order two seeds ran in.\n *\n * Links are copied verbatim, exactly as they were written. Following them would copy bytes from\n * outside the seed into the workspace, which is the same rule {@link describeWorkspaceTree}\n * applies to the digest.\n */\nexport async function seedWorkspaceTree(\n input: SeedWorkspaceTreeInput,\n): Promise<WorkspaceTreeDescriptor> {\n const source = resolve(input.source)\n const destination = resolve(input.destination)\n if (source === destination || isWithin(source, destination)) {\n throw new Error('workspace seed must not contain its destination')\n }\n const destinationStats = await lstatIfPresent(destination)\n if (destinationStats === null || !destinationStats.isDirectory()) {\n throw new Error(\n `workspace seed destination must be an existing directory: ${input.destination}`,\n )\n }\n // Described BEFORE anything is copied, so a seed this refuses leaves the destination untouched.\n const descriptor = await describeWorkspaceTree(source, {\n ...(input.algorithm === undefined ? {} : { algorithm: input.algorithm }),\n })\n for (const name of (await readdir(source)).sort()) {\n if ((await lstatIfPresent(join(destination, name))) !== null) {\n throw new Error(`workspace seed would overwrite an existing entry: ${name}`)\n }\n await cp(join(source, name), join(destination, name), {\n recursive: true,\n force: false,\n errorOnExist: true,\n verbatimSymlinks: true,\n })\n }\n return descriptor\n}\n\n/** Stream one regular file into its own digest, or `null` when it vanished mid-read. */\nasync function digestFile(\n path: string,\n): Promise<{ sha256: Sha256Digest; byteLength: number } | null> {\n let descriptor: Awaited<ReturnType<typeof open>>\n try {\n descriptor = await open(\n path,\n fsConstants.O_RDONLY |\n (typeof fsConstants.O_NOFOLLOW === 'number' ? fsConstants.O_NOFOLLOW : 0),\n )\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n try {\n const hash = createHash('sha256')\n const buffer = Buffer.allocUnsafe(1024 * 1024)\n let total = 0\n while (true) {\n const { bytesRead } = await descriptor.read(buffer, 0, buffer.byteLength, null)\n if (bytesRead === 0) break\n total += bytesRead\n hash.update(buffer.subarray(0, bytesRead))\n }\n // The length comes from the READ, never from `lstat`, so a file that grew between the two is\n // described by the bytes that reached the digest rather than refused for ordinary churn.\n return { sha256: `sha256:${hash.digest('hex')}` as Sha256Digest, byteLength: total }\n } finally {\n await descriptor.close()\n }\n}\n\n/** Git records exactly two file modes; a portable tree records the same two, plus 755 for a\n * directory and 777 for a link, which is what every filesystem reports for one. */\nfunction entryMode(\n mode: number | bigint,\n algorithm: WorkspaceTreeAlgorithm,\n isDirectory: boolean,\n isSymbolicLink: boolean,\n): string {\n const bits = Number(mode)\n if (algorithm !== 'portable-tree-v1') return String(bits & 0o777)\n if (isDirectory) return '755'\n if (isSymbolicLink) return '777'\n return (bits & 0o111) !== 0 ? '755' : '644'\n}\n\nfunction reasonText(reason: WorkspaceTreeExclusionReason): string {\n switch (reason) {\n case 'absolute-symlink':\n return 'is absolute'\n case 'symlink-escapes-tree':\n return 'escapes its tree'\n case 'symlink-resolves-outside-tree':\n return 'resolves outside its tree'\n default:\n return 'does not resolve'\n }\n}\n\nfunction treePath(root: string, path: string): string {\n return relative(root, path).split(sep).join('/') || '.'\n}\n\nfunction isWithin(root: string, path: string): boolean {\n return path === root || path.startsWith(`${root}${sep}`)\n}\n\nfunction isMissing(error: unknown): boolean {\n return (error as { code?: unknown } | null)?.code === 'ENOENT'\n}\n\nasync function lstatIfPresent(path: string): Promise<Awaited<ReturnType<typeof lstat>> | null> {\n try {\n return await lstat(path)\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["canonicalCandidateBytes","canonicalCandidateBytes","canonicalCandidateBytes","fsConstants"],"sources":["../../src/candidate-execution/builder.ts","../../src/candidate-execution/claim-file-store.ts","../../src/candidate-execution/dispose.ts","../../src/candidate-execution/protected-model-grant.ts","../../src/candidate-execution/recover.ts","../../src/candidate-execution/workspace-transfer.ts","../../src/candidate-execution/workspace-tree.ts"],"sourcesContent":["import type { CodeSurface } from '@tangle-network/agent-eval/campaign'\nimport { verifyCodeSurface } from '@tangle-network/agent-eval/campaign'\nimport type {\n AgentCandidateCodeDisabled,\n AgentCandidateCodeNoOp,\n AgentCandidateExecution,\n AgentCandidateGitHubRepository,\n AgentCandidateKnowledge,\n AgentCandidateMemoryPolicy,\n AgentCandidateProfile,\n AgentProfile,\n AgentProfileDiff,\n} from '@tangle-network/agent-interface'\nimport { type AgentCandidateBundleInput, sealAgentCandidateBundle } from './bundle'\nimport { embeddedCandidateArtifact } from './digest'\nimport {\n applyExactAgentProfileDiff,\n freezeGenericAgentCandidateProfile,\n parseExactAgentProfile,\n parseExactAgentProfileDiff,\n parseExactCandidateProfile,\n} from './profile'\n\n/** A complete profile that can be frozen without losing behavior. */\nexport type AgentCandidateProfileSource =\n | {\n kind: 'profile'\n profile: AgentProfile\n }\n | {\n kind: 'profile-diffs'\n base: AgentProfile\n /** Applied in order before the resulting profile is frozen into the bundle. */\n diffs: readonly AgentProfileDiff[]\n }\n | {\n kind: 'candidate-profile'\n /** Already converted to the closed, secret-free candidate profile contract. */\n profile: AgentCandidateProfile\n }\n\n/** The only accepted path from an agent-eval code candidate to executable bytes. */\nexport interface AgentCandidateCodeSurfaceSource {\n kind: 'code-surface'\n surface: CodeSurface\n repository: AgentCandidateGitHubRepository\n /** Optional parent directory used to resolve a relative `surface.worktreeRef`. */\n worktreeDir?: string\n}\n\n/** Explicit control/no-op code or one finalized CodeSurface whose bytes must still verify. */\nexport type AgentCandidateCodeSource =\n | AgentCandidateCodeDisabled\n | AgentCandidateCodeNoOp\n | AgentCandidateCodeSurfaceSource\n\n/** Complete measured surfaces and execution policy compiled into one candidate bundle. */\nexport interface BuildAgentCandidateBundleInput {\n profile: AgentCandidateProfileSource\n code: AgentCandidateCodeSource\n execution: AgentCandidateExecution\n knowledge?: AgentCandidateKnowledge\n memory: AgentCandidateMemoryPolicy\n}\n\n/**\n * Compile one measured profile/code candidate into the immutable execution\n * contract. Code bytes are re-read and verified by agent-eval before they are\n * embedded. The returned bundle is schema-validated, canonically digested, and\n * deeply immutable; call `verifyAgentCandidateBundle` at the execution boundary\n * to re-read external memory, repository, and workspace artifacts.\n */\nexport function buildAgentCandidateBundle(\n input: BuildAgentCandidateBundleInput,\n): ReturnType<typeof sealAgentCandidateBundle> {\n const bundle: AgentCandidateBundleInput = {\n kind: 'agent-candidate-bundle',\n digestAlgorithm: 'rfc8785-sha256',\n profile: compileCandidateProfile(input.profile),\n code: compileCandidateCode(input.code),\n execution: input.execution,\n ...(input.knowledge !== undefined ? { knowledge: input.knowledge } : {}),\n memory: input.memory,\n }\n return sealAgentCandidateBundle(bundle)\n}\n\nfunction compileCandidateProfile(source: AgentCandidateProfileSource): AgentCandidateProfile {\n if (source.kind === 'candidate-profile') {\n return parseExactCandidateProfile(source.profile)\n }\n\n if (source.kind === 'profile') {\n return freezeGenericAgentCandidateProfile(source.profile)\n }\n\n if (source.kind !== 'profile-diffs') {\n throw new Error(\n `unsupported candidate profile source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n if (source.diffs.length === 0) {\n throw new Error('profile-diffs source requires at least one AgentProfileDiff')\n }\n let profile = parseExactAgentProfile(source.base, 'base profile')\n for (const [index, inputDiff] of source.diffs.entries()) {\n const diff = parseExactAgentProfileDiff(inputDiff, `profile diff ${index}`)\n profile = applyExactAgentProfileDiff(profile, diff, `profile diff ${index}`)\n }\n return freezeGenericAgentCandidateProfile(profile)\n}\n\nfunction compileCandidateCode(source: AgentCandidateCodeSource): AgentCandidateBundleInput['code'] {\n if (source.kind === 'disabled' || source.kind === 'no-op') return source\n if (source.kind !== 'code-surface') {\n throw new Error(\n `unsupported candidate code source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n\n const verified = verifyCodeSurface(source.surface, source.worktreeDir)\n const patch = embeddedCandidateArtifact(verified.patchBytes)\n if (\n patch.sha256 !== source.surface.patch.sha256 ||\n patch.byteLength !== source.surface.patch.byteLength\n ) {\n throw new Error('verified CodeSurface patch bytes do not match its content identity')\n }\n return {\n kind: 'git-patch',\n repository: source.repository,\n baseCommit: source.surface.baseCommit,\n baseTree: source.surface.baseTree,\n candidateTree: source.surface.candidateTree,\n patch: { format: 'git-diff-binary', artifact: patch },\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { linkSync } from 'node:fs'\nimport { mkdir, open, unlink } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\nimport {\n type AgentCandidateExecutionAttemptRecord,\n type AgentCandidateExecutionAttemptRef,\n type AgentCandidateExecutionClaim,\n type AgentCandidateExecutionClaimResult,\n type AgentCandidateExecutionClaimStore,\n type AgentCandidateExecutionFinishResult,\n type AgentCandidateExecutionLease,\n type AgentCandidateExecutionPhase,\n type AgentCandidateExecutionPhaseResult,\n type AgentCandidateExecutionRecoveryEvidence,\n type AgentCandidateExecutionStageResult,\n type AgentCandidateExecutionTerminalRecord,\n type AgentCandidateExecutionTerminalResult,\n type AgentCandidateRetryRejection,\n candidateClaimFileInternals,\n} from './claim'\nimport {\n assertRecoveryMatchesStaged,\n assertTerminalAllowedInPhase,\n assertTerminalMatchesClaim,\n assertTerminalMatchesStaged,\n recoveredTerminalRecord,\n rejectedFinish,\n rejectedStage,\n requireStagedTerminal,\n sealTerminalDigest,\n terminalRecord,\n} from './claim-terminal'\nimport { canonicalCandidateBytes } from './digest'\n\nconst {\n assertExpiredLease,\n assertLease,\n assertSameSlot,\n assertUnexpiredLease,\n attemptRecord,\n claimSlot,\n leaseDigest,\n newLease,\n readClaim,\n readClaimIfPresent,\n readTerminal,\n readTerminalIfPresent,\n readTransitionIfPresent,\n rejectedExistingClaim,\n rejectedRetry,\n retryRejection,\n sealAttemptRef,\n sealClaim,\n sealLease,\n} = candidateClaimFileInternals\n\nexport interface FileAgentCandidateExecutionClaimStoreOptions {\n /** Evaluator-owned directory shared by every process allowed to execute candidates. */\n directory: string\n /** Testable evaluator clock; defaults to `Date.now`. */\n now?: () => number\n}\n\n/** Cross-process lifecycle implemented as fsynced, create-if-absent records. */\nexport class FileAgentCandidateExecutionClaimStore implements AgentCandidateExecutionClaimStore {\n private readonly directory: string\n private readonly now: () => number\n\n constructor(options: FileAgentCandidateExecutionClaimStoreOptions) {\n if (options.directory.length === 0) {\n throw new Error('candidate execution claim directory must not be empty')\n }\n this.directory = options.directory\n this.now = options.now ?? Date.now\n }\n\n async tryClaim(\n requested: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateExecutionClaimResult> {\n const claim = sealClaim(requested)\n await mkdir(this.directory, { recursive: true })\n const claimPath = this.claimPath(claim)\n const existing = await readClaimIfPresent(claimPath)\n if (existing) {\n assertSameSlot(existing.claim, claim, claimPath)\n return rejectedExistingClaim(existing.claim, claim)\n }\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n const retryFailure = await this.retryFailure(claim)\n if (retryFailure) return rejectedRetry(claim, retryFailure)\n\n const lease = newLease(claim)\n const acquired = await writeRecordIfAbsent(this.directory, claimPath, {\n ...claim,\n phase: 'claimed',\n leaseDigest: leaseDigest(lease),\n })\n if (acquired) return Object.freeze({ acquired: true, claim, lease })\n\n const winner = await readClaim(claimPath)\n assertSameSlot(winner.claim, claim, claimPath)\n return rejectedExistingClaim(winner.claim, claim)\n }\n\n async getAttempt(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n return await this.storedAttempt(sealAttemptRef(requestedAttempt))\n }\n\n async markCandidateMayRun(\n requestedLease: AgentCandidateExecutionLease,\n ): Promise<AgentCandidateExecutionPhaseResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n if (state.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n if (state.staged) {\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const marked = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, 1),\n {\n kind: 'candidate-execution-phase',\n executionId: stored.claim.executionId,\n attempt: stored.claim.attempt,\n executionPlanDigest: stored.claim.executionPlanDigest,\n phase: 'candidate-may-run',\n },\n this.ownerPublication(stored.claim),\n )\n if (marked) return Object.freeze({ marked: true, phase: 'candidate-may-run' })\n const winner = await this.transitionState(stored.claim)\n if (winner.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n\n async stageTerminal(\n requestedLease: AgentCandidateExecutionLease,\n result: AgentCandidateExecutionTerminalResult,\n ): Promise<AgentCandidateExecutionStageResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const terminal = terminalRecord(stored.claim, result)\n const state = await this.transitionState(stored.claim)\n if (state.staged) return rejectedStage(state.staged, terminal)\n assertTerminalAllowedInPhase(state.phase, terminal)\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const transition = state.phase === 'claimed' ? 1 : 2\n const staged = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal,\n },\n this.ownerPublication(stored.claim),\n )\n if (staged) return Object.freeze({ staged: true, terminal })\n const winner = await this.transitionState(stored.claim)\n if (!winner.staged) {\n throw new Error('candidate execution phase transition won while staging terminal')\n }\n return rejectedStage(winner.staged, terminal)\n }\n\n async finish(\n requestedLease: AgentCandidateExecutionLease,\n requestedTerminalDigest: Sha256Digest,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const lease = sealLease(requestedLease)\n const terminalDigest = sealTerminalDigest(requestedTerminalDigest)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n const staged = requireStagedTerminal(state.staged, terminalDigest)\n const terminalPath = this.terminalPath(lease)\n const existing = await readTerminalIfPresent(terminalPath)\n if (existing) {\n assertTerminalMatchesClaim(existing, stored.claim, terminalPath)\n assertTerminalMatchesStaged(existing, staged, terminalPath)\n return rejectedFinish(existing, terminalDigest)\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const finished = await writeRecordIfAbsent(\n this.directory,\n terminalPath,\n {\n terminal: staged,\n },\n this.ownerPublication(stored.claim),\n )\n if (finished) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, lease, terminalPath)\n assertTerminalMatchesClaim(winner, stored.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, terminalDigest)\n }\n\n async recoverExpired(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n evidence: AgentCandidateExecutionRecoveryEvidence,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const attempt = sealAttemptRef(requestedAttempt)\n const record = await this.storedAttempt(attempt)\n if (!record) throw new Error('candidate execution recovery does not name an acquired attempt')\n const recovered = recoveredTerminalRecord(record.claim, record.phase, evidence)\n if (record.staged) assertRecoveryMatchesStaged(record.staged, recovered)\n const requestedDigest = record.staged?.terminalDigest ?? recovered.terminalDigest\n if (record.terminal) return rejectedFinish(record.terminal, requestedDigest)\n assertExpiredLease(record.claim.leaseExpiresAtMs, this.now())\n\n let staged = record.staged\n if (!staged) {\n const transition = record.phase === 'claimed' ? 1 : 2\n const didStage = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(record.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal: recovered,\n },\n )\n if (didStage) {\n staged = recovered\n } else {\n const winner = await this.transitionState(record.claim)\n if (!winner.staged) {\n throw new Error(\n 'candidate execution recovery lost terminal staging to a phase transition',\n )\n }\n assertRecoveryMatchesStaged(winner.staged, recovered)\n staged = winner.staged\n }\n }\n\n const terminalPath = this.terminalPath(attempt)\n const didFinish = await writeRecordIfAbsent(this.directory, terminalPath, {\n terminal: staged,\n })\n if (didFinish) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, attempt, terminalPath)\n assertTerminalMatchesClaim(winner, record.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, staged.terminalDigest)\n }\n\n private async storedAttempt(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n const claimPath = this.claimPath(claim)\n const stored = await readClaimIfPresent(claimPath)\n if (!stored) return undefined\n assertSameSlot(stored.claim, claim, claimPath)\n const terminalPath = this.terminalPath(claim)\n const terminal = await readTerminalIfPresent(terminalPath)\n // Terminal publication follows its immutable staged outbox, so read that prerequisite later.\n const state = await this.transitionState(stored.claim)\n if (terminal) {\n assertTerminalMatchesClaim(terminal, stored.claim, terminalPath)\n if (!state.staged) {\n throw new Error(\n `candidate execution terminal record at ${terminalPath} has no staged outbox`,\n )\n }\n assertTerminalMatchesStaged(terminal, state.staged, terminalPath)\n }\n return attemptRecord(stored.claim, state.phase, state.staged, terminal)\n }\n\n private async transitionState(claim: AgentCandidateExecutionClaim): Promise<{\n phase: AgentCandidateExecutionPhase\n staged?: AgentCandidateExecutionTerminalRecord\n }> {\n const firstPath = this.transitionPath(claim, 1)\n const first = await readTransitionIfPresent(firstPath, claim)\n if (!first) return { phase: 'claimed' }\n if (first.kind === 'pending') return { phase: 'claimed', staged: first.terminal }\n const secondPath = this.transitionPath(claim, 2)\n const second = await readTransitionIfPresent(secondPath, claim)\n if (!second) return { phase: 'candidate-may-run' }\n if (second.kind !== 'pending') {\n throw new Error(`candidate execution transition at ${secondPath} repeats the phase marker`)\n }\n return { phase: 'candidate-may-run', staged: second.terminal }\n }\n\n private async retryFailure(\n claim: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateRetryRejection | undefined> {\n if (claim.attempt === 1) return undefined\n return retryRejection(\n claim,\n await this.storedAttempt({\n executionId: claim.executionId,\n attempt: claim.attempt - 1,\n }),\n )\n }\n\n private ownerPublication(claim: AgentCandidateExecutionClaim): {\n authorizePublish: () => true\n } {\n return {\n authorizePublish: () => {\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n return true\n },\n }\n }\n\n private claimPath(claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>): string {\n return join(this.directory, `${claimSlot(claim)}.claim.json`)\n }\n\n private terminalPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.terminal.json`)\n }\n\n private transitionPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ordinal: 1 | 2,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.transition-${ordinal}.json`)\n }\n}\n\n/**\n * Candidate records keep this async writer because lease authorization must run after the\n * asynchronous temp-file fsync and immediately before synchronous link publication. The\n * supervisor durability helper is synchronous and has no lease hook, so combining them would\n * either move authorization earlier or add an async race to the claim boundary.\n */\nasync function writeRecordIfAbsent(\n directory: string,\n destination: string,\n record: object,\n options: {\n /** Synchronous authorization checked after temp fsync, immediately before atomic publication. */\n authorizePublish?: () => true\n } = {},\n): Promise<boolean> {\n const temporaryPath = join(directory, `.candidate-execution-${process.pid}-${randomUUID()}.tmp`)\n const handle = await open(temporaryPath, 'wx', 0o600)\n try {\n await handle.writeFile(\n Buffer.concat([Buffer.from(canonicalCandidateBytes(record)), Buffer.from('\\n')]),\n )\n await handle.sync()\n } finally {\n await handle.close()\n }\n\n let written = false\n try {\n if (options.authorizePublish && options.authorizePublish() !== true) {\n throw new Error('candidate execution record publication was not authorized')\n }\n // Authorization and the atomic filesystem call are one synchronous critical\n // section so the event loop cannot advance an injected lease clock between them.\n linkSync(temporaryPath, destination)\n written = true\n await syncDirectory(directory)\n } catch (error) {\n if (!isNodeError(error, 'EEXIST')) throw error\n } finally {\n await unlink(temporaryPath).catch((error: unknown) => {\n if (!isNodeError(error, 'ENOENT')) throw error\n })\n }\n return written\n}\n\nasync function syncDirectory(directory: string): Promise<void> {\n const handle = await open(directory, 'r')\n try {\n await handle.sync()\n } finally {\n await handle.close()\n }\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n (error as { code?: unknown }).code === code\n )\n}\n","import { candidateCleanupDeadline, withinCandidateCleanupDeadline } from './cleanup'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport {\n assertPreparedCandidateIntegrity,\n beginPreparedCandidateDisposal,\n consumePreparedCandidateExecution,\n} from './prepared-state'\nimport type { PreparedAgentCandidateExecution } from './types'\n\nexport interface DisposePreparedAgentCandidateOptions {\n cleanupTimeoutMs?: number\n}\n\n/** Revoke reservations held by a prepared candidate that will not be executed. */\nexport async function disposePreparedAgentCandidateExecution(\n prepared: PreparedAgentCandidateExecution,\n options: DisposePreparedAgentCandidateOptions = {},\n): Promise<{ disposed: true }> {\n const initialState = assertPreparedCandidateIntegrity(prepared)\n const cleanupTimeoutMs = options.cleanupTimeoutMs ?? initialState.cleanupTimeoutMs\n if (cleanupTimeoutMs > initialState.cleanupTimeoutMs) {\n throw new Error('disposal cleanup timeout exceeds the frozen preparation bound')\n }\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const state = beginPreparedCandidateDisposal(prepared)\n const cleanup: Array<Promise<unknown>> = []\n\n if (state.memory.mode === 'isolated') {\n const reservation = state.memoryReservation\n if (!reservation) throw new Error('isolated memory reservation is missing')\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const closed = await state.ports.memory.close({\n executionId: state.executionId,\n preparationId: reservation.preparationId,\n accessDigest: reservation.accessDigest,\n effectiveNamespace: reservation.effectiveNamespace,\n reason: 'abandoned',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('abandoned isolated memory access did not acknowledge closure')\n }\n },\n cleanupDeadlineAtMs,\n 'isolated memory disposal',\n ),\n )\n }\n\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const settlement = sealAgentCandidateModelSettlement(\n await state.ports.models.settleGrant({\n executionId: state.executionId,\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n resolved: state.resolvedModel,\n reason: 'abandoned',\n }),\n {\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n model: state.resolvedModel.model,\n },\n )\n if (settlement.usage.modelCalls !== 0) {\n throw new Error('unexecuted model reservation unexpectedly contains calls')\n }\n },\n cleanupDeadlineAtMs,\n 'model reservation disposal',\n ),\n )\n\n const results = await Promise.allSettled(cleanup)\n const failures = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason)\n if (failures.length > 0) {\n consumePreparedCandidateExecution(prepared, 'disposal-failed')\n throw new AggregateError(failures, 'candidate preparation disposal failed')\n }\n\n consumePreparedCandidateExecution(prepared, 'disposed')\n return Object.freeze({ disposed: true as const })\n}\n","import type { AgentCandidateResolvedModel } from '@tangle-network/agent-interface'\n\nimport type {\n AgentCandidateModelGrantActivateInput,\n AgentCandidateModelGrantReserveInput,\n AgentCandidateModelGrantSettleInput,\n} from './protected-model-port'\nimport type {\n AgentCandidateModelPort,\n AgentCandidateProtectedModelActivation,\n AgentCandidateProtectedModelReservation,\n AgentCandidateProtectedModelSettlement,\n} from './types'\n\n/** Reservation fields supplied by a caller before Runtime resolves the model. */\nexport type AgentCandidateModelGrantRunReservationInput = Omit<\n AgentCandidateModelGrantReserveInput,\n 'resolved'\n>\n\n/** Values available only while one protected model grant is active. */\nexport interface ProtectedAgentCandidateModelGrantContext {\n readonly activation: AgentCandidateProtectedModelActivation\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly resolved: AgentCandidateResolvedModel\n}\n\n/** Inputs for one protected grant scoped to one bounded caller unit. */\nexport interface RunProtectedAgentCandidateModelGrantOptions<TResult> {\n /** Runtime port that validates and settles the evaluator-owned grant. */\n readonly port: AgentCandidateModelPort\n /** Provider-neutral model request resolved before any grant is reserved. */\n readonly resolve: Parameters<AgentCandidateModelPort['resolve']>[0]\n /** One bounded unit's immutable identity, attempt, expiry, and limits. */\n readonly reserve: AgentCandidateModelGrantRunReservationInput\n /** Must be no later than the reservation expiry. */\n readonly deadlineAtMs: AgentCandidateModelGrantActivateInput['deadlineAtMs']\n /** Execute exactly one bounded unit while the activated environment is valid. */\n readonly execute: (context: ProtectedAgentCandidateModelGrantContext) => Promise<TResult>\n}\n\n/** Result and sealed settlement returned after one protected grant closes. */\nexport interface RunProtectedAgentCandidateModelGrantResult<TResult> {\n readonly value: TResult\n readonly resolved: AgentCandidateResolvedModel\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly settlement: AgentCandidateProtectedModelSettlement\n}\n\nconst SETTLEMENT_RETRY_INITIAL_DELAY_MS = 25\nconst SETTLEMENT_RETRY_MAX_DELAY_MS = 1_000\n\n/**\n * Run one bounded unit under a protected model grant.\n *\n * Runtime owns the grant lifecycle; callers own the unit boundary and any\n * durable scheduling or accounting around it. A reserved grant is settled\n * after activation failure or callback failure, and the callback error is\n * preserved when settlement also fails.\n */\nexport async function runProtectedAgentCandidateModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n): Promise<RunProtectedAgentCandidateModelGrantResult<TResult>> {\n if (typeof options.execute !== 'function') {\n throw new TypeError('protected model grant execute callback is required')\n }\n\n const resolved = await options.port.resolve(options.resolve)\n const reservation = await options.port.reserveGrant({\n ...options.reserve,\n resolved,\n })\n\n let value!: TResult\n let executionError: unknown\n let executionFailed = false\n let activated = false\n let reason: AgentCandidateModelGrantSettleInput['reason'] = 'preparation-failed'\n\n try {\n const activation = await options.port.activateGrant({\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n deadlineAtMs: options.deadlineAtMs,\n })\n activated = true\n value = await options.execute({ activation, reservation, resolved })\n reason = 'completed'\n } catch (error) {\n executionError = error\n executionFailed = true\n if (activated) reason = 'failed'\n }\n\n let settlement: AgentCandidateProtectedModelSettlement\n try {\n settlement = await settleProtectedModelGrant(options, {\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n reason,\n })\n } catch (settlementError) {\n if (executionFailed) {\n throw new AggregateError(\n [executionError, settlementError],\n 'protected model execution failed and its grant did not settle',\n )\n }\n throw settlementError\n }\n\n if (executionFailed) throw executionError\n return { value, resolved, reservation, settlement }\n}\n\nasync function settleProtectedModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n input: AgentCandidateModelGrantSettleInput,\n): Promise<AgentCandidateProtectedModelSettlement> {\n let delayMs = SETTLEMENT_RETRY_INITIAL_DELAY_MS\n for (;;) {\n try {\n return await options.port.settleGrant(input)\n } catch (error) {\n if (!isCandidateGrantDrainingError(error)) throw error\n const remainingMs = options.deadlineAtMs - Date.now()\n if (remainingMs <= 0) throw error\n await waitForSettlementRetry(Math.min(delayMs, remainingMs))\n if (Date.now() >= options.deadlineAtMs) throw error\n delayMs = Math.min(delayMs * 2, SETTLEMENT_RETRY_MAX_DELAY_MS)\n }\n }\n}\n\nfunction waitForSettlementRetry(delayMs: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, delayMs))\n}\n\n/** Only the gateway's explicit draining state is retryable; auth and ledger errors fail closed. */\nfunction isCandidateGrantDrainingError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false\n const candidate = error as { code?: unknown; message?: unknown }\n if (candidate.code === 'candidate_grant_draining') return true\n return (\n typeof candidate.message === 'string' && /\\bcandidate_grant_draining\\b/u.test(candidate.message)\n )\n}\n","import type { TraceStore } from '@tangle-network/agent-eval'\nimport type {\n AgentCandidateExecutionPlanMaterial,\n AgentCandidateMaterializationReceipt,\n} from '@tangle-network/agent-interface'\nimport {\n agentCandidateExecutionPlanMaterialSchema,\n agentCandidateMaterializationReceiptSchema,\n} from '@tangle-network/agent-interface'\n\nimport { readVerifiedArtifact } from './artifacts'\nimport type {\n AgentCandidateExecutionAttemptRef,\n AgentCandidateExecutionClaim,\n AgentCandidateExecutionClaimStore,\n AgentCandidateExecutionFinishResult,\n} from './claim'\nimport {\n candidateCleanupDeadline,\n candidateCleanupTimeout,\n withinCandidateCleanupDeadline,\n} from './cleanup'\nimport { canonicalCandidateBytes } from './digest'\nimport { sealAgentCandidateExecutorStopAcknowledgement } from './executor-capture'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport { persistCandidateModelSettlementEvidence } from './outcome-evidence'\nimport { persistCandidateOutputArtifact } from './output-artifacts'\nimport { RecoveryAgentCandidateTraceStore } from './protected-trace-store'\nimport type {\n AgentCandidateExecutionPorts,\n AgentCandidateExecutorPort,\n AgentCandidateOutputArtifactPort,\n} from './types'\n\nexport interface RecoverExpiredAgentCandidateOptions {\n attempt: AgentCandidateExecutionAttemptRef\n claimStore: AgentCandidateExecutionClaimStore\n executor: AgentCandidateExecutorPort\n traceStore: TraceStore\n ports: Pick<AgentCandidateExecutionPorts, 'models' | 'memory'>\n outputArtifacts: AgentCandidateOutputArtifactPort\n cleanupTimeoutMs?: number\n /** Evaluator clock; must be the same clock used by the claim store. */\n now?: () => number\n}\n\n/** Close an expired crashed attempt from persisted non-secret handles, then record failure. */\nexport async function recoverExpiredAgentCandidateExecution(\n options: RecoverExpiredAgentCandidateOptions,\n): Promise<AgentCandidateExecutionFinishResult> {\n const record = await options.claimStore.getAttempt(options.attempt)\n if (!record) throw new Error('candidate execution recovery attempt is missing')\n if (record.terminal) {\n return Object.freeze({ finished: false, terminal: record.terminal, exactReplay: true })\n }\n const cleanupTimeoutMs = candidateCleanupTimeout(\n options.cleanupTimeoutMs ?? record.claim.cleanup.cleanupTimeoutMs,\n )\n if (cleanupTimeoutMs > record.claim.cleanup.cleanupTimeoutMs) {\n throw new Error('recovery cleanup timeout exceeds the frozen preparation bound')\n }\n\n const now = options.now ?? Date.now\n if (now() < record.claim.leaseExpiresAtMs) {\n throw new Error('candidate execution lease has not expired')\n }\n\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const recoveryTraceStore = new RecoveryAgentCandidateTraceStore(options.traceStore)\n const preparation = withinCandidateCleanupDeadline(\n () => readRecoveryPreparation(record.claim, options.outputArtifacts),\n cleanupDeadlineAtMs,\n 'expired candidate preparation evidence read',\n )\n const processClosure = withinCandidateCleanupDeadline(\n async (cleanupSignal) => {\n const stopped = await options.executor.stop(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n {\n traceStore: recoveryTraceStore,\n reason: 'failed',\n signal: cleanupSignal,\n deadlineAtMs: cleanupDeadlineAtMs,\n },\n )\n sealAgentCandidateExecutorStopAcknowledgement(stopped)\n if (options.executor.dispose) {\n const disposed = await options.executor.dispose(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n { signal: cleanupSignal },\n )\n if (disposed.disposed !== true || Object.keys(disposed).some((key) => key !== 'disposed')) {\n throw new Error('expired candidate executor did not acknowledge resource disposal')\n }\n }\n return { stopped: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate process termination',\n )\n\n const modelClosure = withinCandidateCleanupDeadline(\n async () =>\n sealAgentCandidateModelSettlement(\n await options.ports.models.settleGrant({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n resolved: record.claim.cleanup.resolvedModel,\n reason: 'failed',\n }),\n {\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n model: record.claim.cleanup.resolvedModel.model,\n },\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model settlement',\n )\n\n const memoryClosure = record.claim.cleanup.memory\n ? withinCandidateCleanupDeadline(\n async () => {\n const memory = record.claim.cleanup.memory\n if (!memory) throw new Error('expired candidate memory handle is missing')\n const closed = await options.ports.memory.close({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n reason: 'failed',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('expired candidate memory did not acknowledge closure')\n }\n return { closed: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate memory closure',\n )\n : undefined\n\n const closureOutcomes = Promise.allSettled([\n modelClosure,\n memoryClosure ?? Promise.resolve(undefined),\n ] as const)\n const [preparationOutcome, processOutcome] = await Promise.allSettled([\n preparation,\n processClosure,\n ] as const)\n const failures: unknown[] = [preparationOutcome, processOutcome]\n .filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected')\n .map((outcome) => outcome.reason)\n const [modelOutcome, memoryOutcome] = await closureOutcomes\n for (const outcome of [modelOutcome, memoryOutcome]) {\n if (outcome.status === 'rejected') failures.push(outcome.reason)\n }\n if (failures.length > 0) {\n throw new AggregateError(failures, 'expired candidate cleanup could not be proven')\n }\n\n if (modelOutcome.status !== 'fulfilled') {\n throw new Error('expired candidate model settlement was not recovered')\n }\n const model = modelOutcome.value\n const modelSettlement = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateModelSettlementEvidence(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n resolvedModel: record.claim.cleanup.resolvedModel,\n },\n model,\n options.outputArtifacts,\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model-settlement persistence',\n )\n const failureClass =\n record.phase === 'claimed' && model.usage.modelCalls === 0\n ? 'pre-model-infrastructure'\n : 'unknown'\n const failureEvidence = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateOutputArtifact(options.outputArtifacts, {\n executionId: record.claim.executionId,\n purpose: 'failure-evidence',\n bytes: canonicalCandidateBytes({\n kind: 'agent-candidate-recovery-failure',\n executionId: record.claim.executionId,\n attempt: record.claim.attempt,\n bundleDigest: record.claim.bundleDigest,\n executionPlanDigest: record.claim.executionPlanDigest,\n materializationReceiptDigest:\n record.claim.preparationEvidence.materializationReceipt.sha256,\n failureClass,\n processStopped: true,\n modelSettlementDigest: modelSettlement.digest,\n memoryClosed: record.claim.cleanup.memory !== undefined,\n }),\n }),\n cleanupDeadlineAtMs,\n 'expired candidate failure-evidence persistence',\n )\n const memory = record.claim.cleanup.memory\n return await options.claimStore.recoverExpired(options.attempt, {\n failureClass,\n usage: model.usage,\n modelSettlement: modelSettlement.artifact,\n failureEvidence,\n process: {\n stopped: true,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n model: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n },\n ...(memory\n ? {\n memory: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n },\n }\n : {}),\n })\n}\n\nasync function readRecoveryPreparation(\n claim: AgentCandidateExecutionClaim,\n artifacts: AgentCandidateOutputArtifactPort,\n): Promise<{\n plan: AgentCandidateExecutionPlanMaterial\n receipt: AgentCandidateMaterializationReceipt\n}> {\n const [planBytes, receiptBytes] = await Promise.all([\n readVerifiedArtifact(claim.preparationEvidence.executionPlan, artifacts),\n readVerifiedArtifact(claim.preparationEvidence.materializationReceipt, artifacts),\n ])\n const plan = agentCandidateExecutionPlanMaterialSchema.parse(\n parseCanonicalBytes(planBytes, 'plan'),\n )\n if (claim.preparationEvidence.executionPlan.sha256 !== claim.executionPlanDigest) {\n throw new Error('recovery execution plan artifact does not match the claimed digest')\n }\n const receiptMaterial = parseCanonicalBytes(receiptBytes, 'materialization receipt')\n const receipt = agentCandidateMaterializationReceiptSchema.parse({\n ...receiptMaterial,\n digest: claim.preparationEvidence.materializationReceipt.sha256,\n })\n if (\n receipt.bundleDigest !== claim.bundleDigest ||\n receipt.executionPlan.digest !== claim.executionPlanDigest ||\n plan.runCell.bundleDigest !== claim.bundleDigest ||\n plan.executionId !== claim.executionId\n ) {\n throw new Error('recovery preparation evidence does not match the durable claim')\n }\n return { plan, receipt }\n}\n\nfunction parseCanonicalBytes(bytes: Uint8Array, label: string): Record<string, unknown> {\n let parsed: unknown\n try {\n parsed = JSON.parse(Buffer.from(bytes).toString('utf8'))\n } catch (error) {\n throw new Error(`candidate recovery ${label} is not JSON`, { cause: error })\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`candidate recovery ${label} must be an object`)\n }\n if (!Buffer.from(canonicalCandidateBytes(parsed)).equals(Buffer.from(bytes))) {\n throw new Error(`candidate recovery ${label} bytes are not canonical`)\n }\n return parsed as Record<string, unknown>\n}\n","import { lstat } from 'node:fs/promises'\nimport { isAbsolute, resolve } from 'node:path'\nimport {\n type AgentCandidateArtifactRef,\n type AgentCandidateWorkspaceSnapshotEvidence,\n agentCandidateArtifactRefSchema,\n agentCandidateWorkspaceManifestMaterialSchema,\n agentCandidateWorkspaceSnapshotEvidenceSchema,\n} from '@tangle-network/agent-interface'\nimport { verifiedArtifactChunks } from './artifact-streams'\nimport { canonicalCandidateBytes, deepFreezeCandidate } from './digest'\nimport type { AgentCandidateArtifactPort } from './types'\nimport { type AgentCandidateWorkspaceArchiveLimits, workspaceLimits } from './workspace-archive'\nimport {\n type CaptureAgentCandidateWorkspaceOptions,\n captureAgentCandidateWorkspace,\n createAgentCandidateWorkspacePort,\n} from './workspace-archive-local'\n\n/** The canonical workspace evidence without manifest material or embedded file bytes. */\nexport type AgentCandidateWorkspaceSnapshotReferences = Pick<\n AgentCandidateWorkspaceSnapshotEvidence,\n 'kind' | 'digest'\n> & {\n readonly manifest: AgentCandidateArtifactRef\n readonly archive: AgentCandidateArtifactRef\n}\n\nexport type CaptureAgentWorkspaceSnapshotOptions = Omit<\n CaptureAgentCandidateWorkspaceOptions,\n 'artifactPersistence'\n> & {\n artifactPersistence: NonNullable<CaptureAgentCandidateWorkspaceOptions['artifactPersistence']>\n}\n\n/**\n * Capture through the canonical archive owner and return references only.\n * The caller holds its existing private source workspace lease throughout capture, and binds\n * its public source provenance at the SDK boundary. Choose includeRepository and working-tree\n * explicitly when staged, dirty, deleted and unignored untracked Git files must travel.\n */\nexport async function captureAgentWorkspaceSnapshot(\n root: string,\n options: CaptureAgentWorkspaceSnapshotOptions,\n): Promise<AgentCandidateWorkspaceSnapshotReferences> {\n if (!options?.artifactPersistence) {\n throw new Error('portable workspace capture requires artifactPersistence')\n }\n const captured = await captureAgentCandidateWorkspace(root, {\n ...options,\n ...(options.limits ? { limits: { ...options.limits } } : {}),\n artifactPersistence: { ...options.artifactPersistence },\n })\n return workspaceReferences(captured.snapshot)\n}\n\nexport interface MaterializeAgentWorkspaceSnapshotOptions {\n snapshot: AgentCandidateWorkspaceSnapshotReferences\n /** Authorizes each immutable reference for the accepted transfer owner; must stream reads. */\n artifacts: AgentCandidateArtifactPort\n /** Absent destination inside a caller-owned private allocation scope. */\n destination: string\n limits?: Partial<AgentCandidateWorkspaceArchiveLimits>\n signal?: AbortSignal\n}\n\n/**\n * Restore canonical workspace references before an agent starts.\n * The SDK boundary validates source provenance and the accepted snapshot digest before this\n * byte-level composition runs. Artifact references identify content; the injected port owns\n * authorization. The archive owner verifies all files and Git state before publishing fresh\n * staging. Destinations present before or during artifact reads are refused. The caller owns\n * the allocation scope against other writers; Node directory rename is not atomic no-replace.\n */\nexport async function materializeAgentWorkspaceSnapshot(\n input: MaterializeAgentWorkspaceSnapshotOptions,\n): Promise<void> {\n input.signal?.throwIfAborted()\n const snapshot = workspaceReferences(input.snapshot)\n const limits = workspaceLimits(input.limits)\n if (!input.artifacts.readStream) {\n throw new Error('portable workspace restore requires an authorized readStream')\n }\n if (!isAbsolute(input.destination)) {\n throw new Error('portable workspace destination must be absolute')\n }\n const destination = resolve(input.destination)\n await assertAbsentDestination(destination)\n for (const artifact of [snapshot.manifest, snapshot.archive]) {\n if (artifact.byteLength > limits.maxArchiveBytes) {\n throw new Error('portable workspace artifact exceeds maxArchiveBytes')\n }\n }\n const manifest = await readArtifact(snapshot.manifest, input.artifacts, input.signal)\n const material = agentCandidateWorkspaceManifestMaterialSchema.parse(\n JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(manifest)),\n )\n if (!Buffer.from(canonicalCandidateBytes(material)).equals(manifest)) {\n throw new Error('workspace manifest artifact is not the exact canonical manifest material')\n }\n const evidence = agentCandidateWorkspaceSnapshotEvidenceSchema.parse({ ...snapshot, material })\n const archive = await readArtifact(snapshot.archive, input.artifacts, input.signal)\n input.signal?.throwIfAborted()\n // The artifact resolver may await remote storage. A destination that appeared while waiting\n // belongs to its creator, even when it is empty.\n await assertAbsentDestination(destination)\n input.signal?.throwIfAborted()\n await createAgentCandidateWorkspacePort({ limits }).materialize({\n role: 'task',\n snapshot: evidence,\n archive,\n destination,\n ...(input.signal ? { signal: input.signal } : {}),\n })\n}\n\nfunction workspaceReferences(\n snapshot: Pick<\n AgentCandidateWorkspaceSnapshotEvidence,\n 'kind' | 'digest' | 'manifest' | 'archive'\n >,\n): AgentCandidateWorkspaceSnapshotReferences {\n if (snapshot.kind !== 'agent-candidate-workspace-snapshot') {\n throw new Error('portable workspace snapshot kind is invalid')\n }\n const manifest = agentCandidateArtifactRefSchema.parse(snapshot.manifest)\n const archive = agentCandidateArtifactRefSchema.parse(snapshot.archive)\n for (const artifact of [manifest, archive]) {\n if (!Number.isSafeInteger(artifact.byteLength) || artifact.byteLength < 1) {\n throw new Error('portable workspace artifacts require positive safe byte lengths')\n }\n }\n if (snapshot.digest !== manifest.sha256) {\n throw new Error('workspace digest must equal the canonical manifest hash')\n }\n return deepFreezeCandidate({ kind: snapshot.kind, digest: snapshot.digest, manifest, archive })\n}\n\nasync function readArtifact(\n reference: AgentCandidateArtifactRef,\n artifacts: AgentCandidateArtifactPort,\n signal?: AbortSignal,\n): Promise<Buffer> {\n const chunks: Buffer[] = []\n for await (const chunk of verifiedArtifactChunks(reference, artifacts, signal)) {\n chunks.push(Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n\nasync function assertAbsentDestination(destination: string): Promise<void> {\n try {\n await lstat(destination)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n throw error\n }\n throw new Error('portable workspace destination already exists')\n}\n","/**\n * A content digest over a DIRECTORY TREE, and the per-file seed that fills one.\n *\n * The question this answers is \"is this workspace the same workspace\" — the question every launch\n * and every close of a branchable run has to answer, about a tree that a live process is still\n * writing to. That is a different question from the one\n * {@link scanMaterializedWorkspaceManifest} answers, and the difference decides the policies here:\n *\n * - A candidate manifest describes ONE EXACT regular-file workspace. It refuses a symbolic link\n * outright, because `AgentCandidateWorkspaceManifestMaterial` has no representation for one, and\n * it refuses an entry that disappears, because a signed manifest describes a settled tree.\n * - A tree descriptor describes what a RUN PRODUCED. A python venv writes\n * `bin/python -> /usr/bin/python3` as a matter of course, and a work directory can lose an entry\n * between two directory reads. Refusing on either aborts the close, and a run that never wrote\n * its digest can never be branched from.\n *\n * So the two policies are the caller's, one for links and one for vanishing entries, and both\n * default to `'refuse'` — the strict reading, correct for an INPUT seed, where a link that leaves\n * the tree means the seed describes bytes it does not contain. `'exclude'` is the reading a close\n * needs: the entry is never followed, it is recorded, and the exclusion itself is hashed, so two\n * trees that differ only in an excluded entry cannot share a digest.\n *\n * NOTHING is held in memory. A file reaches the tree digest as its own streamed sha-256 plus its\n * length, so the largest file in the tree does not decide whether the tree can be described:\n * `readFile` refuses anything above 2 GiB with `ERR_FS_FILE_TOO_LARGE`, and a single multi-gigabyte\n * artifact is exactly what a run leaves behind.\n *\n * @module\n * @experimental\n */\n\nimport { createHash } from 'node:crypto'\nimport { constants as fsConstants } from 'node:fs'\nimport { cp, lstat, open, readdir, readlink, realpath } from 'node:fs/promises'\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\n/**\n * `'tree-v1'` records a file's exact permission bits. `'portable-tree-v1'` records the two modes\n * Git stores — `755` when any execute bit is set, `644` otherwise, and `755` for a directory — so a\n * digest survives a checkout whose umask differs. Both stamp the algorithm into the digest, so one\n * tree cannot produce the same digest under both.\n */\nexport type WorkspaceTreeAlgorithm = 'tree-v1' | 'portable-tree-v1'\n\n/** What a walk does with an entry it refuses to describe: fail, or record and continue. */\nexport type WorkspaceTreeEntryPolicy = 'refuse' | 'exclude'\n\n/** Why one entry contributed its name instead of its content. */\nexport type WorkspaceTreeExclusionReason =\n | 'absolute-symlink'\n | 'symlink-escapes-tree'\n | 'symlink-resolves-outside-tree'\n | 'unresolved-symlink'\n | 'entry-disappeared'\n\n/** One entry the walk recorded but did not describe. Reported rather than dropped: a digest that\n * silently omitted an entry would be a different digest with no way to tell why. */\nexport interface WorkspaceTreeExclusion {\n /** Tree-relative path, `/`-separated. */\n readonly path: string\n readonly reason: WorkspaceTreeExclusionReason\n /** The link target exactly as it was written, for a symbolic-link exclusion. */\n readonly target?: string\n}\n\nexport interface WorkspaceTreeDescriptor {\n readonly algorithm: WorkspaceTreeAlgorithm\n readonly digest: Sha256Digest\n readonly files: number\n readonly directories: number\n /** Links kept INSIDE the tree. An excluded link is counted in `excluded`, never here. */\n readonly symlinks: number\n /** Total described regular-file bytes. */\n readonly bytes: number\n readonly excluded: ReadonlyArray<WorkspaceTreeExclusion>\n}\n\nexport interface DescribeWorkspaceTreeOptions {\n /** Default `'tree-v1'`. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n /**\n * A symbolic link that is absolute, leaves the tree lexically, resolves outside it, or does not\n * resolve at all. `'refuse'` (default) is correct for an input seed. `'exclude'` is correct for a\n * close-time walk over a tree a run wrote. The link is NEVER followed in either policy: an\n * escaping link must not contribute bytes from outside the tree to a content address.\n */\n readonly onEscapingLink?: WorkspaceTreeEntryPolicy\n /**\n * An entry that vanished between the directory read that named it and the walk that reached it.\n * `'refuse'` (default) is correct for a settled tree; `'exclude'` is correct for a workspace a\n * live process still writes to.\n */\n readonly onMissingEntry?: WorkspaceTreeEntryPolicy\n}\n\nexport interface SeedWorkspaceTreeInput {\n /** The tree to copy FROM. Described, then copied entry by entry. */\n readonly source: string\n /** The tree to copy INTO. Must exist, and must not lie inside `source`. */\n readonly destination: string\n /** Default `'tree-v1'`; decides only the digest this returns, never the bytes it writes. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n}\n\nconst TREE_ALGORITHMS: ReadonlySet<string> = new Set<WorkspaceTreeAlgorithm>([\n 'tree-v1',\n 'portable-tree-v1',\n])\n\nconst ENTRY_POLICIES: ReadonlySet<string> = new Set<WorkspaceTreeEntryPolicy>(['refuse', 'exclude'])\n\n/**\n * Describe one directory tree by content, streaming every file.\n *\n * The digest covers, for every entry in sorted order: its kind, its tree-relative path, its mode\n * under the selected algorithm, and then — for a file, its length and its own sha-256; for a kept\n * link, its target; for an excluded entry, the reason and the target. A file's content therefore\n * never enters the tree hash directly, which is what removes any in-memory size ceiling: the tree\n * hash consumes 32 bytes per file however large the file is.\n *\n * A hard-linked regular file is described like any other regular file. Its content is what the\n * digest is about, and a package manager that links a store into `node_modules` is ordinary\n * content, not a reason to refuse a workspace.\n */\nexport async function describeWorkspaceTree(\n directory: string,\n options: DescribeWorkspaceTreeOptions = {},\n): Promise<WorkspaceTreeDescriptor> {\n const algorithm = options.algorithm ?? 'tree-v1'\n const onEscapingLink = options.onEscapingLink ?? 'refuse'\n const onMissingEntry = options.onMissingEntry ?? 'refuse'\n if (!TREE_ALGORITHMS.has(algorithm)) {\n throw new Error(`unsupported workspace tree algorithm: ${algorithm}`)\n }\n for (const [name, policy] of [\n ['onEscapingLink', onEscapingLink],\n ['onMissingEntry', onMissingEntry],\n ] as const) {\n if (!ENTRY_POLICIES.has(policy)) {\n throw new Error(`unsupported workspace tree ${name} policy: ${policy}`)\n }\n }\n\n const root = resolve(directory)\n const rootStats = await lstatIfPresent(root)\n if (rootStats === null || !rootStats.isDirectory() || rootStats.isSymbolicLink()) {\n throw new Error(`workspace tree root must be a real directory: ${directory}`)\n }\n // Resolve the root once. Every physical containment test below compares against the RESOLVED\n // root, so a symlinked prefix — which is what macOS hands out for a temp directory — does not\n // make every entry look like it escapes.\n const physicalRoot = await realpath(root)\n\n const hash = createHash('sha256')\n // The algorithm is part of the digest. Without this, a tree whose modes already are 755/644\n // produces one digest under both algorithms, and two different questions share one answer.\n hash.update(`workspace-tree\\0${algorithm}\\0`)\n const counts = { files: 0, directories: 0, symlinks: 0, bytes: 0 }\n const excluded: WorkspaceTreeExclusion[] = []\n\n const exclude = (path: string, reason: WorkspaceTreeExclusionReason, target?: string): void => {\n const name = treePath(root, path)\n excluded.push(\n Object.freeze(target === undefined ? { path: name, reason } : { path: name, reason, target }),\n )\n // The reason is hashed with the entry. Two trees that differ only in WHY an entry was excluded\n // are different trees, and a refusal must not become a way to hide a difference.\n hash.update(`excluded\\0${name}\\0${reason}\\0${target ?? ''}\\0`)\n }\n\n /** True when the caller asked to continue past a vanished entry, and it was not the root. */\n const recordMissing = (path: string): boolean => {\n if (onMissingEntry === 'refuse' || path === root) return false\n exclude(path, 'entry-disappeared')\n return true\n }\n\n const visit = async (path: string): Promise<void> => {\n const info = await lstatIfPresent(path)\n if (info === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${treePath(root, path)}`)\n }\n const name = treePath(root, path)\n const mode = entryMode(info.mode, algorithm, info.isDirectory(), info.isSymbolicLink())\n\n if (info.isDirectory()) {\n let entries: string[]\n try {\n entries = await readdir(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n counts.directories += 1\n hash.update(`directory\\0${name}\\0${mode}\\0`)\n for (const entry of entries.sort()) await visit(join(path, entry))\n return\n }\n\n if (info.isSymbolicLink()) {\n await visitSymbolicLink(path, name, mode)\n return\n }\n\n if (!info.isFile()) {\n throw new Error(`workspace tree contains an unsupported entry: ${name}`)\n }\n const read = await digestFile(path)\n if (read === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${name}`)\n }\n counts.files += 1\n counts.bytes += read.byteLength\n hash.update(`file\\0${name}\\0${mode}\\0${read.byteLength}\\0${read.sha256}\\0`)\n }\n\n const visitSymbolicLink = async (path: string, name: string, mode: string): Promise<void> => {\n let target: string\n try {\n target = await readlink(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n const refuse = (reason: WorkspaceTreeExclusionReason): void => {\n if (onEscapingLink === 'refuse') {\n throw new Error(\n `workspace tree contains a link that ${reasonText(reason)}: ${name} -> ${target}`,\n )\n }\n exclude(path, reason, target)\n }\n if (isAbsolute(target)) return refuse('absolute-symlink')\n if (!isWithin(root, resolve(dirname(path), target))) return refuse('symlink-escapes-tree')\n let physicalTarget: string\n try {\n physicalTarget = await realpath(path)\n } catch {\n // A dangling link is a fact about the tree, not a reason to make the run unrecoverable.\n return refuse('unresolved-symlink')\n }\n if (!isWithin(physicalRoot, physicalTarget)) return refuse('symlink-resolves-outside-tree')\n counts.symlinks += 1\n hash.update(`symlink\\0${name}\\0${mode}\\0${target}\\0`)\n }\n\n await visit(root)\n return Object.freeze({\n algorithm,\n digest: `sha256:${hash.digest('hex')}` as Sha256Digest,\n files: counts.files,\n directories: counts.directories,\n symlinks: counts.symlinks,\n bytes: counts.bytes,\n excluded: Object.freeze(excluded),\n })\n}\n\n/**\n * Seed a workspace from a directory, one entry at a time, and return the digest of what was\n * seeded.\n *\n * Nothing is packed: `cp` walks and copies file by file, so a multi-gigabyte seed costs one file\n * handle rather than one archive in memory. Existing destination entries are never overwritten —\n * a seed that could replace a file the workspace already holds would make the resulting tree\n * depend on the order two seeds ran in.\n *\n * Links are copied verbatim, exactly as they were written. Following them would copy bytes from\n * outside the seed into the workspace, which is the same rule {@link describeWorkspaceTree}\n * applies to the digest.\n */\nexport async function seedWorkspaceTree(\n input: SeedWorkspaceTreeInput,\n): Promise<WorkspaceTreeDescriptor> {\n const source = resolve(input.source)\n const destination = resolve(input.destination)\n if (source === destination || isWithin(source, destination)) {\n throw new Error('workspace seed must not contain its destination')\n }\n const destinationStats = await lstatIfPresent(destination)\n if (destinationStats === null || !destinationStats.isDirectory()) {\n throw new Error(\n `workspace seed destination must be an existing directory: ${input.destination}`,\n )\n }\n // Described BEFORE anything is copied, so a seed this refuses leaves the destination untouched.\n const descriptor = await describeWorkspaceTree(source, {\n ...(input.algorithm === undefined ? {} : { algorithm: input.algorithm }),\n })\n for (const name of (await readdir(source)).sort()) {\n if ((await lstatIfPresent(join(destination, name))) !== null) {\n throw new Error(`workspace seed would overwrite an existing entry: ${name}`)\n }\n await cp(join(source, name), join(destination, name), {\n recursive: true,\n force: false,\n errorOnExist: true,\n verbatimSymlinks: true,\n })\n }\n return descriptor\n}\n\n/** Stream one regular file into its own digest, or `null` when it vanished mid-read. */\nasync function digestFile(\n path: string,\n): Promise<{ sha256: Sha256Digest; byteLength: number } | null> {\n let descriptor: Awaited<ReturnType<typeof open>>\n try {\n descriptor = await open(\n path,\n fsConstants.O_RDONLY |\n (typeof fsConstants.O_NOFOLLOW === 'number' ? fsConstants.O_NOFOLLOW : 0),\n )\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n try {\n const hash = createHash('sha256')\n const buffer = Buffer.allocUnsafe(1024 * 1024)\n let total = 0\n while (true) {\n const { bytesRead } = await descriptor.read(buffer, 0, buffer.byteLength, null)\n if (bytesRead === 0) break\n total += bytesRead\n hash.update(buffer.subarray(0, bytesRead))\n }\n // The length comes from the READ, never from `lstat`, so a file that grew between the two is\n // described by the bytes that reached the digest rather than refused for ordinary churn.\n return { sha256: `sha256:${hash.digest('hex')}` as Sha256Digest, byteLength: total }\n } finally {\n await descriptor.close()\n }\n}\n\n/** Git records exactly two file modes; a portable tree records the same two, plus 755 for a\n * directory and 777 for a link, which is what every filesystem reports for one. */\nfunction entryMode(\n mode: number | bigint,\n algorithm: WorkspaceTreeAlgorithm,\n isDirectory: boolean,\n isSymbolicLink: boolean,\n): string {\n const bits = Number(mode)\n if (algorithm !== 'portable-tree-v1') return String(bits & 0o777)\n if (isDirectory) return '755'\n if (isSymbolicLink) return '777'\n return (bits & 0o111) !== 0 ? '755' : '644'\n}\n\nfunction reasonText(reason: WorkspaceTreeExclusionReason): string {\n switch (reason) {\n case 'absolute-symlink':\n return 'is absolute'\n case 'symlink-escapes-tree':\n return 'escapes its tree'\n case 'symlink-resolves-outside-tree':\n return 'resolves outside its tree'\n default:\n return 'does not resolve'\n }\n}\n\nfunction treePath(root: string, path: string): string {\n return relative(root, path).split(sep).join('/') || '.'\n}\n\nfunction isWithin(root: string, path: string): boolean {\n return path === root || path.startsWith(`${root}${sep}`)\n}\n\nfunction isMissing(error: unknown): boolean {\n return (error as { code?: unknown } | null)?.code === 'ENOENT'\n}\n\nasync function lstatIfPresent(path: string): Promise<Awaited<ReturnType<typeof lstat>> | null> {\n try {\n return await lstat(path)\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-digest-sBTLujlK.js","names":[],"sources":["../src/content-digest.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\n\nexport function sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex')\n}\n"],"mappings":";;AAEA,SAAgB,OAAO,OAAuB;CAC5C,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;AACxD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as ConfigError } from "./errors-DodWX-cb.js";
|
|
2
|
-
import {
|
|
2
|
+
import { t as supervise } from "./supervise-WuPAwfPh.js";
|
|
3
3
|
import { agentProfileSchema } from "@tangle-network/agent-interface";
|
|
4
4
|
import { computeFindingId, makeFinding } from "@tangle-network/agent-eval";
|
|
5
5
|
//#region src/runtime/supervise/authoring.ts
|
|
@@ -207,4 +207,4 @@ async function delegate(intent, opts) {
|
|
|
207
207
|
//#endregion
|
|
208
208
|
export { defaultProfileRichnessThresholds as a, assessAuthoredProfile as i, delegate as n, profileRichnessFinding as o, asAuthoredProfile as r, supervisorInstructions as s, defaultDelegateBudget as t };
|
|
209
209
|
|
|
210
|
-
//# sourceMappingURL=delegate-
|
|
210
|
+
//# sourceMappingURL=delegate-Se1YZKMb.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegate-B-T_ZB50.js","names":[],"sources":["../src/runtime/supervise/authoring.ts","../src/runtime/supervise/delegate.ts"],"sourcesContent":["/**\n *\n * The supervisor's intelligence is AUTHORING the agents it spawns — not pressing buttons.\n *\n * Every agent here is three things: instructions (system prompt), tools, and a model — its\n * `AgentProfile`. The supervisor's job is to WRITE those profiles: read the task, decompose it,\n * and for each sub-task author a tailored worker recipe. `supervisorInstructions` is the how-to the\n * supervisor reads; canonical Runtime executors materialize the resulting profile.\n *\n * The skill is the single OPTIMIZABLE surface: edit it → the supervisor designs better agents.\n * That is the self-improvement lever (the prompt/skill lever), not the execution plumbing.\n *\n * @experimental\n */\n\nimport { type AnalystFinding, computeFindingId, makeFinding } from '@tangle-network/agent-eval'\nimport {\n type AgentProfile,\n type AgentProfilePrompt,\n agentProfileSchema,\n} from '@tangle-network/agent-interface'\n\n/** What the supervisor AUTHORS per sub-task: one complete canonical profile whose name and\n * task-specific system prompt are present. Every other `AgentProfile` axis is preserved exactly. */\nexport type AuthoredProfile = AgentProfile & {\n readonly name: string\n readonly prompt: AgentProfilePrompt & { readonly systemPrompt: string }\n}\n\n/** Narrow an untyped `spawn_worker` profile argument to an `AuthoredProfile`, or null if the\n * supervisor failed to author one (empty/placeholder profile — a skill violation worth catching). */\nexport function asAuthoredProfile(raw: unknown): AuthoredProfile | null {\n const parsed = agentProfileSchema.safeParse(raw)\n if (!parsed.success) return null\n const systemPrompt = parsed.data.prompt?.systemPrompt\n if (typeof systemPrompt !== 'string' || systemPrompt.trim().length === 0) return null\n return {\n ...parsed.data,\n name:\n typeof parsed.data.name === 'string' && parsed.data.name.length > 0\n ? parsed.data.name\n : 'worker',\n prompt: { ...parsed.data.prompt, systemPrompt },\n }\n}\n\n/** The supervisor skill: an explicit profile-authoring instruction, never an implicit Runtime\n * policy. Editing this text changes how a profile designs the descendants it spawns. */\nexport function supervisorInstructions(opts?: { goal?: string }): string {\n return [\n 'Your delegation craft is AUTHORING: a spawned worker is exactly as good as the profile you write.',\n '',\n 'For the task you are given:',\n '1. DECOMPOSE it into the smallest set of sub-tasks a single focused worker can each deliver.',\n '2. For EACH sub-task, AUTHOR a worker by calling spawn_worker with a COMPLETE `profile`:',\n ' • name and description: who this specialist is and why it exists.',\n ' • prompt.systemPrompt: rich instructions for THIS sub-task — exact output, process, evidence, and what \"done\" means.',\n ' • model.default, model.reasoningEffort, and harness: choose the execution system deliberately when the task benefits from it.',\n ' • tools, mcp, resources.skills/files/instructions, hooks, subagents, permissions, and modes: grant or attach every capability the worker needs; omit an axis only when it is intentionally unnecessary.',\n ' • tools.agent_runtime_coordination_spawn_worker: true ONLY when this child should author and drive descendants. Add only the other agent_runtime_coordination_<verb> tools it will call, such as observe_agent or steer_agent.',\n ' • A child with spawn_worker MUST carry this complete profile-authoring instruction as an immutable resources.skills entry with resources.failOnError: true, so it can author its own descendants from the same contract.',\n ' • metadata may describe the work, but it never grants recursion or selects a Runtime execution path.',\n ' NEVER spawn a worker with an empty profile. The quality of the worker IS the quality of the profile you write.',\n '3. End your turn while your workers run: Runtime wakes you with each settled worker. A settlement says valid:true only if the deployable check passed.',\n '4. If a worker did NOT deliver, AUTHOR A NEW profile whose prompt.systemPrompt names the SPECIFIC failure and how to fix it — never just retry the same profile.',\n \"5. read_journal to re-read YOUR OWN record before you decide the next move: every spawn you made, every settle, every question and answer, every steer, every analyst finding — oldest first, this node only, including what you did before a restart. Use it to see what you already tried instead of trying it again. It is paged: pass the returned nextRow as the next call's sinceRow, narrow with kinds, and raise limit/maxBytes only as far as you will actually read. A truncated:true page means a bound cut it short — keep paging before you conclude you have read everything.\",\n '6. AUTHOR YOUR OWN LENS when the questions you can already ask of a settled trace do not cover the failure you are chasing: define_analyst takes an id, a description, an area, the question in your own words, the instructions for answering it with trace evidence, and the smallest toolGroup that can answer it (model is the seat it runs on; omit it for the run default). It is DATA, never code. Then run_analyst it on any settled worker like a lens the run shipped with, and read the finding. list_analysts shows what you have. Define a lens when you need a different question asked — not a second copy of a question already on the menu.',\n '7. EVERY refusal you get back carries a `reason` naming the exact unmet condition. Read it and change that condition — a spawn refused for budget-exhausted needs a smaller budget or the refund of a settled worker, an invalid-profile needs the named field fixed, a submit_result refused because the check THREW is a broken check to report, not a result to resubmit. Never repeat a call that was refused without changing what it was refused for.',\n '8. ask_parent ONLY when you genuinely cannot decide, and then READ ITS OUTCOME. \"queued-for-parent\" means an inbox above you now holds the question. \"no-parent\" means no inbox above you is configured to receive it: the question is still on the run record for anyone watching, but nothing will route an answer back to you, so do not block. Decide it with answer_question, or answer_question with deferReason to record that it stays open, and carry on — a blocking question left undecided also refuses your stop.',\n '9. Once the work is delivered, end your turn with nothing left running.',\n ...(opts?.goal ? ['', `The goal: ${opts.goal}`] : []),\n ].join('\\n')\n}\n\n// ── Profile-richness gate ────────────────────────────────────────────────────\n//\n// The supervisor's product is the worker PROFILE it authors. The failure mode the existing\n// gates miss: `asAuthoredProfile` / `local-harness` only reject a FULLY EMPTY system prompt —\n// a two-sentence stub passes. `assessAuthoredProfile` OBSERVES the authored artifact (it reads\n// no judge verdict, so it steers cleanly past `assertTraceDerivedFindings`) and flags THIN:\n// a short/few-line system prompt, OR no tools, OR no skills, OR no MCP when the task needs one.\n// It emits a real `AnalystFinding` so it rides the SAME coordination bus the driver pulls via\n// receives in its next wake — the supervisor can self-correct and re-author richer.\n\n/** Thresholds below which a system prompt is treated as a thin stub. Tunable per call. */\nexport interface ProfileRichnessThresholds {\n /** A prompt shorter than this many characters is thin (default 600). */\n readonly minSystemPromptChars: number\n /** A prompt with fewer than this many non-blank lines is thin (default 6). */\n readonly minSystemPromptLines: number\n}\n\n/** Default thresholds for `ProfileRichnessThresholds` — 600 chars / 6 lines minimum system prompt. */\nexport const defaultProfileRichnessThresholds: ProfileRichnessThresholds = {\n minSystemPromptChars: 600,\n minSystemPromptLines: 6,\n}\n\n/** Per-field verdict on one authored profile — the raw material the bench renders + scores. */\nexport interface ProfileRichness {\n readonly name: string\n /** The resolved system prompt (canonical `prompt.systemPrompt`, the sandbox `prompt.system`\n * convention, or a bare-string prompt — whichever the author used). */\n readonly systemPrompt: string\n readonly systemPromptChars: number\n readonly systemPromptLines: number\n readonly sentenceCount: number\n readonly hasDescription: boolean\n readonly hasTools: boolean\n readonly hasSkills: boolean\n readonly hasMcp: boolean\n readonly hasSubagents: boolean\n /** 0..1 — fraction of richness signals present (prompt-depth + the four levers). */\n readonly richness: number\n /** True when the supervisor authored a stub instead of a real profile. */\n readonly thin: boolean\n /** The specific reasons it is thin (empty when rich) — used in the finding's action. */\n readonly reasons: string[]\n}\n\n/** Read the system prompt from any authored shape: canonical `prompt.systemPrompt`, the sandbox\n * `prompt.system` convention, or a bare-string `prompt`. */\nfunction resolveSystemPrompt(profile: AgentProfile): string {\n const pr = (profile as { prompt?: unknown }).prompt\n if (typeof pr === 'string') return pr\n if (pr && typeof pr === 'object') {\n const o = pr as { systemPrompt?: unknown; system?: unknown }\n if (typeof o.systemPrompt === 'string') return o.systemPrompt\n if (typeof o.system === 'string') return o.system\n }\n return ''\n}\n\n/** OBSERVE one authored `AgentProfile` and score its richness (no judge verdict is read). The task\n * context (`needsMcp`) lets a domain say \"this work needs a data/tool MCP\" so a missing MCP counts. */\nexport function assessAuthoredProfile(\n profile: AgentProfile,\n opts?: { needsMcp?: boolean; thresholds?: Partial<ProfileRichnessThresholds> },\n): ProfileRichness {\n const th = { ...defaultProfileRichnessThresholds, ...(opts?.thresholds ?? {}) }\n const systemPrompt = resolveSystemPrompt(profile)\n const trimmed = systemPrompt.trim()\n const systemPromptChars = trimmed.length\n const systemPromptLines = trimmed\n ? trimmed.split('\\n').filter((l) => l.trim().length > 0).length\n : 0\n const sentenceCount = trimmed\n ? (trimmed.match(/[.!?](\\s|$)/g) ?? []).length || (trimmed ? 1 : 0)\n : 0\n const hasDescription =\n typeof profile.description === 'string' && profile.description.trim().length > 0\n const tools = (profile as { tools?: Record<string, unknown> }).tools\n const hasTools = !!tools && Object.keys(tools).length > 0\n const skills = (profile.resources as { skills?: unknown[] } | undefined)?.skills\n const hasSkills = Array.isArray(skills) && skills.length > 0\n const mcp = (profile as { mcp?: Record<string, unknown> }).mcp\n const hasMcp = !!mcp && Object.keys(mcp).length > 0\n const subagents = (profile as { subagents?: Record<string, unknown> }).subagents\n const hasSubagents = !!subagents && Object.keys(subagents).length > 0\n\n const reasons: string[] = []\n const promptThin =\n systemPromptChars < th.minSystemPromptChars || systemPromptLines < th.minSystemPromptLines\n if (promptThin)\n reasons.push(\n `system prompt is thin (${systemPromptChars} chars, ${systemPromptLines} lines; need ≥${th.minSystemPromptChars} chars and ≥${th.minSystemPromptLines} lines)`,\n )\n if (!hasTools)\n reasons.push('no tools granted (a worker can only act through the tools you grant it)')\n if (!hasSkills) reasons.push('no skills attached (no reusable how-to notes injected)')\n if (opts?.needsMcp && !hasMcp) reasons.push('no MCP server, but the task needs data/tool access')\n\n // Richness = fraction of signals present. Prompt-depth is one signal; the four levers are the rest.\n const signals = [!promptThin, hasTools, hasSkills, hasDescription, opts?.needsMcp ? hasMcp : true]\n const richness = signals.filter(Boolean).length / signals.length\n // THIN ⟺ the prompt is a stub OR the worker has no levers at all (no tools AND no skills AND no mcp).\n const thin = promptThin || (!hasTools && !hasSkills && !hasMcp)\n\n return {\n name: profile.name ?? 'worker',\n systemPrompt,\n systemPromptChars,\n systemPromptLines,\n sentenceCount,\n hasDescription,\n hasTools,\n hasSkills,\n hasMcp,\n hasSubagents,\n richness,\n thin,\n reasons,\n }\n}\n\n/** Turn a {@link ProfileRichness} verdict into a bus-routable `AnalystFinding` (area `profile-quality`).\n * Severity scales with thinness; the recommended action names the MISSING lever so the supervisor can\n * re-author. `subject` = the worker name so per-worker findings diff cleanly across re-authors. */\nexport function profileRichnessFinding(\n richness: ProfileRichness,\n opts?: { analystId?: string; runId?: string },\n): AnalystFinding {\n const analyst_id = opts?.analystId ?? 'profile-richness'\n const subject = richness.name\n const claim = richness.thin\n ? `Worker \"${richness.name}\" was authored as a THIN profile: ${richness.reasons.join('; ')}.`\n : `Worker \"${richness.name}\" was authored as a rich profile (richness ${(richness.richness * 100).toFixed(0)}%).`\n const severity: AnalystFinding['severity'] = richness.thin\n ? richness.richness < 0.25\n ? 'high'\n : 'medium'\n : 'info'\n return makeFinding({\n analyst_id,\n severity,\n area: 'profile-quality',\n claim,\n subject,\n confidence: 0.9,\n evidence_refs: [\n {\n kind: 'metric',\n uri: `profile:${subject}`,\n excerpt: `chars=${richness.systemPromptChars} lines=${richness.systemPromptLines} tools=${richness.hasTools} skills=${richness.hasSkills} mcp=${richness.hasMcp} richness=${richness.richness.toFixed(2)}`,\n },\n ],\n ...(richness.thin\n ? { recommended_action: `Re-author \"${richness.name}\" with: ${richness.reasons.join('; ')}.` }\n : {}),\n id_basis: computeFindingId({\n analyst_id,\n area: 'profile-quality',\n subject,\n claim: `richness:${richness.thin ? 'thin' : 'rich'}`,\n }),\n })\n}\n","/**\n *\n * `delegate` — the one generic delegation verb. You hand it an INTENT (what you want done) and it\n * hands that intent to a default AUTHORING supervisor: a router-brained supervisor whose standing\n * instruction is `supervisorInstructions()` (the authoring-agent-profiles skill). The supervisor\n * DECOMPOSES the intent and AUTHORS the worker profile it needs per sub-task — there is NO hardcoded\n * coder/researcher profile here. That is the whole point: `delegate('fix the failing test', …)` and\n * `delegate('research X and cite sources', …)` route through the SAME front door; the supervisor\n * writes a code-shaped or research-shaped worker on its own.\n *\n * It is a thin wrapper over `supervise()` — the one front door — so the conserved-budget pool, the\n * completion oracle (`deliverable`), the coordination toolbox, and equal-compute accounting all come\n * for free; nothing is hand-rolled. The result is `supervise()`'s `SupervisedResult` returned\n * UNCHANGED, so its `spentTotal` (`{ iterations, tokens, usd, ms }`) rides straight back to the\n * caller on BOTH paths — a `winner` carries the delivered worker's spend, a `no-winner` carries the\n * spend incurred before it failed. That cost channel means a `delegate()` caller always learns what\n * the delegation actually spent.\n *\n * @experimental\n */\n\nimport { ConfigError } from '../../errors'\nimport type { RouterTransportConfig } from '../router-client'\nimport type { DeliverableSpec } from './completion-gate'\nimport type { ExecutorConfig } from './runtime'\nimport { supervise } from './supervise'\nimport type { SupervisorProfile } from './supervisor-agent'\nimport type { Budget, SupervisedResult } from './types'\n\n/** The conserved pool a `delegate()` call applies when the caller does not pass its own `budget`.\n * A modest token ceiling + a small iteration ceiling — generous enough for a few-worker decompose,\n * bounded enough that an unsupervised intent cannot run away. Callers override via `opts.budget`. */\nexport const defaultDelegateBudget: Budget = { maxIterations: 50, maxTokens: 200_000 }\n\n/** Inputs to {@link delegate}. The intent is the first positional arg; everything here is optional\n * with explicit execution identity, so the common call names one exact supervisor profile. */\nexport interface DelegateOptions<Out = unknown> {\n /** The completion oracle (settled ⟺ delivered) the authored workers settle against. Strongly\n * recommended — without it the supervisor trusts a worker's self-report. For a code intent,\n * `patchDelivered()` is the canonical example; for a free-form answer, a content check. */\n readonly deliverable?: DeliverableSpec<Out>\n /** WHERE the authored workers run — the worker-execution backend (`router-tools` / `sandbox` /\n * `cli-worktree` / …). The supervisor authors the worker PROFILE; this is the substrate it runs\n * on. Provide this OR `makeWorkerAgent`-style wiring through `supervise()` is unavailable. */\n readonly backend?: ExecutorConfig\n /** The conserved compute pool for the whole delegation. Defaults to {@link defaultDelegateBudget}. */\n readonly budget?: Budget\n /** Exact executable authoring supervisor. Model, prompt, harness, and provider live here. */\n readonly supervisorProfile: SupervisorProfile\n /** Router endpoint/auth for a `cli-base` supervisor; contains no behavioral settings. */\n readonly router: RouterTransportConfig\n /** Restrict the run to this subset of models (forwarded to `supervise()`). */\n readonly allowedModels?: readonly string[]\n readonly runId?: string\n}\n\n/**\n * Delegate an INTENT to a default authoring supervisor and return its `SupervisedResult` unchanged.\n *\n * The supervisor authors + spawns whatever worker the intent needs over the conserved-budget pool;\n * `result.spentTotal` reports what the whole delegation actually cost. A `winner` result carries the\n * authored worker's delivered output; a `no-winner` result names why (never a fabricated success).\n */\nexport async function delegate<Out = unknown>(\n intent: string,\n opts: DelegateOptions<Out>,\n): Promise<SupervisedResult<Out>> {\n if (typeof intent !== 'string' || intent.trim().length === 0) {\n throw new ConfigError('delegate: `intent` must be a non-empty string')\n }\n return supervise(opts.supervisorProfile, intent, {\n budget: opts.budget ?? defaultDelegateBudget,\n ...(opts.backend ? { backend: opts.backend } : {}),\n ...(opts.deliverable ? { deliverable: opts.deliverable as DeliverableSpec<unknown> } : {}),\n router: opts.router,\n ...(opts.allowedModels ? { allowedModels: opts.allowedModels } : {}),\n ...(opts.runId ? { runId: opts.runId } : {}),\n }) as Promise<SupervisedResult<Out>>\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"delegate-Se1YZKMb.js","names":[],"sources":["../src/runtime/supervise/authoring.ts","../src/runtime/supervise/delegate.ts"],"sourcesContent":["/**\n *\n * The supervisor's intelligence is AUTHORING the agents it spawns — not pressing buttons.\n *\n * Every agent here is three things: instructions (system prompt), tools, and a model — its\n * `AgentProfile`. The supervisor's job is to WRITE those profiles: read the task, decompose it,\n * and for each sub-task author a tailored worker recipe. `supervisorInstructions` is the how-to the\n * supervisor reads; canonical Runtime executors materialize the resulting profile.\n *\n * The skill is the single OPTIMIZABLE surface: edit it → the supervisor designs better agents.\n * That is the self-improvement lever (the prompt/skill lever), not the execution plumbing.\n *\n * @experimental\n */\n\nimport { type AnalystFinding, computeFindingId, makeFinding } from '@tangle-network/agent-eval'\nimport {\n type AgentProfile,\n type AgentProfilePrompt,\n agentProfileSchema,\n} from '@tangle-network/agent-interface'\n\n/** What the supervisor AUTHORS per sub-task: one complete canonical profile whose name and\n * task-specific system prompt are present. Every other `AgentProfile` axis is preserved exactly. */\nexport type AuthoredProfile = AgentProfile & {\n readonly name: string\n readonly prompt: AgentProfilePrompt & { readonly systemPrompt: string }\n}\n\n/** Narrow an untyped `spawn_worker` profile argument to an `AuthoredProfile`, or null if the\n * supervisor failed to author one (empty/placeholder profile — a skill violation worth catching). */\nexport function asAuthoredProfile(raw: unknown): AuthoredProfile | null {\n const parsed = agentProfileSchema.safeParse(raw)\n if (!parsed.success) return null\n const systemPrompt = parsed.data.prompt?.systemPrompt\n if (typeof systemPrompt !== 'string' || systemPrompt.trim().length === 0) return null\n return {\n ...parsed.data,\n name:\n typeof parsed.data.name === 'string' && parsed.data.name.length > 0\n ? parsed.data.name\n : 'worker',\n prompt: { ...parsed.data.prompt, systemPrompt },\n }\n}\n\n/** The supervisor skill: an explicit profile-authoring instruction, never an implicit Runtime\n * policy. Editing this text changes how a profile designs the descendants it spawns. */\nexport function supervisorInstructions(opts?: { goal?: string }): string {\n return [\n 'Your delegation craft is AUTHORING: a spawned worker is exactly as good as the profile you write.',\n '',\n 'For the task you are given:',\n '1. DECOMPOSE it into the smallest set of sub-tasks a single focused worker can each deliver.',\n '2. For EACH sub-task, AUTHOR a worker by calling spawn_worker with a COMPLETE `profile`:',\n ' • name and description: who this specialist is and why it exists.',\n ' • prompt.systemPrompt: rich instructions for THIS sub-task — exact output, process, evidence, and what \"done\" means.',\n ' • model.default, model.reasoningEffort, and harness: choose the execution system deliberately when the task benefits from it.',\n ' • tools, mcp, resources.skills/files/instructions, hooks, subagents, permissions, and modes: grant or attach every capability the worker needs; omit an axis only when it is intentionally unnecessary.',\n ' • tools.agent_runtime_coordination_spawn_worker: true ONLY when this child should author and drive descendants. Add only the other agent_runtime_coordination_<verb> tools it will call, such as observe_agent or steer_agent.',\n ' • A child with spawn_worker MUST carry this complete profile-authoring instruction as an immutable resources.skills entry with resources.failOnError: true, so it can author its own descendants from the same contract.',\n ' • metadata may describe the work, but it never grants recursion or selects a Runtime execution path.',\n ' NEVER spawn a worker with an empty profile. The quality of the worker IS the quality of the profile you write.',\n '3. End your turn while your workers run: Runtime wakes you with each settled worker. A settlement says valid:true only if the deployable check passed.',\n '4. If a worker did NOT deliver, AUTHOR A NEW profile whose prompt.systemPrompt names the SPECIFIC failure and how to fix it — never just retry the same profile.',\n \"5. read_journal to re-read YOUR OWN record before you decide the next move: every spawn you made, every settle, every question and answer, every steer, every analyst finding — oldest first, this node only, including what you did before a restart. Use it to see what you already tried instead of trying it again. It is paged: pass the returned nextRow as the next call's sinceRow, narrow with kinds, and raise limit/maxBytes only as far as you will actually read. A truncated:true page means a bound cut it short — keep paging before you conclude you have read everything.\",\n '6. AUTHOR YOUR OWN LENS when the questions you can already ask of a settled trace do not cover the failure you are chasing: define_analyst takes an id, a description, an area, the question in your own words, the instructions for answering it with trace evidence, and the smallest toolGroup that can answer it (model is the seat it runs on; omit it for the run default). It is DATA, never code. Then run_analyst it on any settled worker like a lens the run shipped with, and read the finding. list_analysts shows what you have. Define a lens when you need a different question asked — not a second copy of a question already on the menu.',\n '7. EVERY refusal you get back carries a `reason` naming the exact unmet condition. Read it and change that condition — a spawn refused for budget-exhausted needs a smaller budget or the refund of a settled worker, an invalid-profile needs the named field fixed, a submit_result refused because the check THREW is a broken check to report, not a result to resubmit. Never repeat a call that was refused without changing what it was refused for.',\n '8. ask_parent ONLY when you genuinely cannot decide, and then READ ITS OUTCOME. \"queued-for-parent\" means an inbox above you now holds the question. \"no-parent\" means no inbox above you is configured to receive it: the question is still on the run record for anyone watching, but nothing will route an answer back to you, so do not block. Decide it with answer_question, or answer_question with deferReason to record that it stays open, and carry on — a blocking question left undecided also refuses your stop.',\n '9. Once the work is delivered, end your turn with nothing left running.',\n ...(opts?.goal ? ['', `The goal: ${opts.goal}`] : []),\n ].join('\\n')\n}\n\n// ── Profile-richness gate ────────────────────────────────────────────────────\n//\n// The supervisor's product is the worker PROFILE it authors. The failure mode the existing\n// gates miss: `asAuthoredProfile` / `local-harness` only reject a FULLY EMPTY system prompt —\n// a two-sentence stub passes. `assessAuthoredProfile` OBSERVES the authored artifact (it reads\n// no judge verdict, so it steers cleanly past `assertTraceDerivedFindings`) and flags THIN:\n// a short/few-line system prompt, OR no tools, OR no skills, OR no MCP when the task needs one.\n// It emits a real `AnalystFinding` so it rides the SAME coordination bus the driver pulls via\n// receives in its next wake — the supervisor can self-correct and re-author richer.\n\n/** Thresholds below which a system prompt is treated as a thin stub. Tunable per call. */\nexport interface ProfileRichnessThresholds {\n /** A prompt shorter than this many characters is thin (default 600). */\n readonly minSystemPromptChars: number\n /** A prompt with fewer than this many non-blank lines is thin (default 6). */\n readonly minSystemPromptLines: number\n}\n\n/** Default thresholds for `ProfileRichnessThresholds` — 600 chars / 6 lines minimum system prompt. */\nexport const defaultProfileRichnessThresholds: ProfileRichnessThresholds = {\n minSystemPromptChars: 600,\n minSystemPromptLines: 6,\n}\n\n/** Per-field verdict on one authored profile — the raw material the bench renders + scores. */\nexport interface ProfileRichness {\n readonly name: string\n /** The resolved system prompt (canonical `prompt.systemPrompt`, the sandbox `prompt.system`\n * convention, or a bare-string prompt — whichever the author used). */\n readonly systemPrompt: string\n readonly systemPromptChars: number\n readonly systemPromptLines: number\n readonly sentenceCount: number\n readonly hasDescription: boolean\n readonly hasTools: boolean\n readonly hasSkills: boolean\n readonly hasMcp: boolean\n readonly hasSubagents: boolean\n /** 0..1 — fraction of richness signals present (prompt-depth + the four levers). */\n readonly richness: number\n /** True when the supervisor authored a stub instead of a real profile. */\n readonly thin: boolean\n /** The specific reasons it is thin (empty when rich) — used in the finding's action. */\n readonly reasons: string[]\n}\n\n/** Read the system prompt from any authored shape: canonical `prompt.systemPrompt`, the sandbox\n * `prompt.system` convention, or a bare-string `prompt`. */\nfunction resolveSystemPrompt(profile: AgentProfile): string {\n const pr = (profile as { prompt?: unknown }).prompt\n if (typeof pr === 'string') return pr\n if (pr && typeof pr === 'object') {\n const o = pr as { systemPrompt?: unknown; system?: unknown }\n if (typeof o.systemPrompt === 'string') return o.systemPrompt\n if (typeof o.system === 'string') return o.system\n }\n return ''\n}\n\n/** OBSERVE one authored `AgentProfile` and score its richness (no judge verdict is read). The task\n * context (`needsMcp`) lets a domain say \"this work needs a data/tool MCP\" so a missing MCP counts. */\nexport function assessAuthoredProfile(\n profile: AgentProfile,\n opts?: { needsMcp?: boolean; thresholds?: Partial<ProfileRichnessThresholds> },\n): ProfileRichness {\n const th = { ...defaultProfileRichnessThresholds, ...(opts?.thresholds ?? {}) }\n const systemPrompt = resolveSystemPrompt(profile)\n const trimmed = systemPrompt.trim()\n const systemPromptChars = trimmed.length\n const systemPromptLines = trimmed\n ? trimmed.split('\\n').filter((l) => l.trim().length > 0).length\n : 0\n const sentenceCount = trimmed\n ? (trimmed.match(/[.!?](\\s|$)/g) ?? []).length || (trimmed ? 1 : 0)\n : 0\n const hasDescription =\n typeof profile.description === 'string' && profile.description.trim().length > 0\n const tools = (profile as { tools?: Record<string, unknown> }).tools\n const hasTools = !!tools && Object.keys(tools).length > 0\n const skills = (profile.resources as { skills?: unknown[] } | undefined)?.skills\n const hasSkills = Array.isArray(skills) && skills.length > 0\n const mcp = (profile as { mcp?: Record<string, unknown> }).mcp\n const hasMcp = !!mcp && Object.keys(mcp).length > 0\n const subagents = (profile as { subagents?: Record<string, unknown> }).subagents\n const hasSubagents = !!subagents && Object.keys(subagents).length > 0\n\n const reasons: string[] = []\n const promptThin =\n systemPromptChars < th.minSystemPromptChars || systemPromptLines < th.minSystemPromptLines\n if (promptThin)\n reasons.push(\n `system prompt is thin (${systemPromptChars} chars, ${systemPromptLines} lines; need ≥${th.minSystemPromptChars} chars and ≥${th.minSystemPromptLines} lines)`,\n )\n if (!hasTools)\n reasons.push('no tools granted (a worker can only act through the tools you grant it)')\n if (!hasSkills) reasons.push('no skills attached (no reusable how-to notes injected)')\n if (opts?.needsMcp && !hasMcp) reasons.push('no MCP server, but the task needs data/tool access')\n\n // Richness = fraction of signals present. Prompt-depth is one signal; the four levers are the rest.\n const signals = [!promptThin, hasTools, hasSkills, hasDescription, opts?.needsMcp ? hasMcp : true]\n const richness = signals.filter(Boolean).length / signals.length\n // THIN ⟺ the prompt is a stub OR the worker has no levers at all (no tools AND no skills AND no mcp).\n const thin = promptThin || (!hasTools && !hasSkills && !hasMcp)\n\n return {\n name: profile.name ?? 'worker',\n systemPrompt,\n systemPromptChars,\n systemPromptLines,\n sentenceCount,\n hasDescription,\n hasTools,\n hasSkills,\n hasMcp,\n hasSubagents,\n richness,\n thin,\n reasons,\n }\n}\n\n/** Turn a {@link ProfileRichness} verdict into a bus-routable `AnalystFinding` (area `profile-quality`).\n * Severity scales with thinness; the recommended action names the MISSING lever so the supervisor can\n * re-author. `subject` = the worker name so per-worker findings diff cleanly across re-authors. */\nexport function profileRichnessFinding(\n richness: ProfileRichness,\n opts?: { analystId?: string; runId?: string },\n): AnalystFinding {\n const analyst_id = opts?.analystId ?? 'profile-richness'\n const subject = richness.name\n const claim = richness.thin\n ? `Worker \"${richness.name}\" was authored as a THIN profile: ${richness.reasons.join('; ')}.`\n : `Worker \"${richness.name}\" was authored as a rich profile (richness ${(richness.richness * 100).toFixed(0)}%).`\n const severity: AnalystFinding['severity'] = richness.thin\n ? richness.richness < 0.25\n ? 'high'\n : 'medium'\n : 'info'\n return makeFinding({\n analyst_id,\n severity,\n area: 'profile-quality',\n claim,\n subject,\n confidence: 0.9,\n evidence_refs: [\n {\n kind: 'metric',\n uri: `profile:${subject}`,\n excerpt: `chars=${richness.systemPromptChars} lines=${richness.systemPromptLines} tools=${richness.hasTools} skills=${richness.hasSkills} mcp=${richness.hasMcp} richness=${richness.richness.toFixed(2)}`,\n },\n ],\n ...(richness.thin\n ? { recommended_action: `Re-author \"${richness.name}\" with: ${richness.reasons.join('; ')}.` }\n : {}),\n id_basis: computeFindingId({\n analyst_id,\n area: 'profile-quality',\n subject,\n claim: `richness:${richness.thin ? 'thin' : 'rich'}`,\n }),\n })\n}\n","/**\n *\n * `delegate` — the one generic delegation verb. You hand it an INTENT (what you want done) and it\n * hands that intent to a default AUTHORING supervisor: a router-brained supervisor whose standing\n * instruction is `supervisorInstructions()` (the authoring-agent-profiles skill). The supervisor\n * DECOMPOSES the intent and AUTHORS the worker profile it needs per sub-task — there is NO hardcoded\n * coder/researcher profile here. That is the whole point: `delegate('fix the failing test', …)` and\n * `delegate('research X and cite sources', …)` route through the SAME front door; the supervisor\n * writes a code-shaped or research-shaped worker on its own.\n *\n * It is a thin wrapper over `supervise()` — the one front door — so the conserved-budget pool, the\n * completion oracle (`deliverable`), the coordination toolbox, and equal-compute accounting all come\n * for free; nothing is hand-rolled. The result is `supervise()`'s `SupervisedResult` returned\n * UNCHANGED, so its `spentTotal` (`{ iterations, tokens, usd, ms }`) rides straight back to the\n * caller on BOTH paths — a `winner` carries the delivered worker's spend, a `no-winner` carries the\n * spend incurred before it failed. That cost channel means a `delegate()` caller always learns what\n * the delegation actually spent.\n *\n * @experimental\n */\n\nimport { ConfigError } from '../../errors'\nimport type { RouterTransportConfig } from '../router-http-transport'\nimport type { DeliverableSpec } from './completion-gate'\nimport type { ExecutorConfig } from './runtime'\nimport { supervise } from './supervise'\nimport type { SupervisorProfile } from './supervisor-agent'\nimport type { Budget, SupervisedResult } from './types'\n\n/** The conserved pool a `delegate()` call applies when the caller does not pass its own `budget`.\n * A modest token ceiling + a small iteration ceiling — generous enough for a few-worker decompose,\n * bounded enough that an unsupervised intent cannot run away. Callers override via `opts.budget`. */\nexport const defaultDelegateBudget: Budget = { maxIterations: 50, maxTokens: 200_000 }\n\n/** Inputs to {@link delegate}. The intent is the first positional arg; everything here is optional\n * with explicit execution identity, so the common call names one exact supervisor profile. */\nexport interface DelegateOptions<Out = unknown> {\n /** The completion oracle (settled ⟺ delivered) the authored workers settle against. Strongly\n * recommended — without it the supervisor trusts a worker's self-report. For a code intent,\n * `patchDelivered()` is the canonical example; for a free-form answer, a content check. */\n readonly deliverable?: DeliverableSpec<Out>\n /** WHERE the authored workers run — the worker-execution backend (`router-tools` / `sandbox` /\n * `cli-worktree` / …). The supervisor authors the worker PROFILE; this is the substrate it runs\n * on. Provide this OR `makeWorkerAgent`-style wiring through `supervise()` is unavailable. */\n readonly backend?: ExecutorConfig\n /** The conserved compute pool for the whole delegation. Defaults to {@link defaultDelegateBudget}. */\n readonly budget?: Budget\n /** Exact executable authoring supervisor. Model, prompt, harness, and provider live here. */\n readonly supervisorProfile: SupervisorProfile\n /** Router endpoint/auth for a `cli-base` supervisor; contains no behavioral settings. */\n readonly router: RouterTransportConfig\n /** Restrict the run to this subset of models (forwarded to `supervise()`). */\n readonly allowedModels?: readonly string[]\n readonly runId?: string\n}\n\n/**\n * Delegate an INTENT to a default authoring supervisor and return its `SupervisedResult` unchanged.\n *\n * The supervisor authors + spawns whatever worker the intent needs over the conserved-budget pool;\n * `result.spentTotal` reports what the whole delegation actually cost. A `winner` result carries the\n * authored worker's delivered output; a `no-winner` result names why (never a fabricated success).\n */\nexport async function delegate<Out = unknown>(\n intent: string,\n opts: DelegateOptions<Out>,\n): Promise<SupervisedResult<Out>> {\n if (typeof intent !== 'string' || intent.trim().length === 0) {\n throw new ConfigError('delegate: `intent` must be a non-empty string')\n }\n return supervise(opts.supervisorProfile, intent, {\n budget: opts.budget ?? defaultDelegateBudget,\n ...(opts.backend ? { backend: opts.backend } : {}),\n ...(opts.deliverable ? { deliverable: opts.deliverable as DeliverableSpec<unknown> } : {}),\n router: opts.router,\n ...(opts.allowedModels ? { allowedModels: opts.allowedModels } : {}),\n ...(opts.runId ? { runId: opts.runId } : {}),\n }) as Promise<SupervisedResult<Out>>\n}\n"],"mappings":"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"}
|