@inflexa-ai/harness 0.46.0 → 0.47.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.
Files changed (280) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/conversation-agent.d.ts +3 -8
  3. package/dist/agents/conversation-agent.js +24 -4
  4. package/dist/agents/report-session-agent.d.ts +11 -14
  5. package/dist/agents/report-session-agent.js +30 -17
  6. package/dist/agents/sandbox/shared.d.ts +18 -13
  7. package/dist/agents/sandbox/shared.js +42 -27
  8. package/dist/agents/sandbox/types.d.ts +1 -1
  9. package/dist/agents/sandbox-catalog.d.ts +2 -0
  10. package/dist/agents/sandbox-catalog.js +30 -1
  11. package/dist/app/chat-turn-workflow.js +5 -6
  12. package/dist/app/synthesize-run.d.ts +10 -6
  13. package/dist/app/synthesize-run.js +4 -2
  14. package/dist/contracts/analogy-report.d.ts +46 -2
  15. package/dist/contracts/analogy-report.js +31 -25
  16. package/dist/contracts/chat-parts.d.ts +3 -14
  17. package/dist/contracts/report-reference.d.ts +2 -1
  18. package/dist/contracts/report-reference.js +2 -1
  19. package/dist/contracts/schemas/chat-parts.d.ts +0 -27
  20. package/dist/contracts/schemas/chat-parts.js +1 -3
  21. package/dist/execution/run-canceler.d.ts +2 -0
  22. package/dist/execution/run-canceler.js +9 -0
  23. package/dist/execution/run-synthesis.d.ts +36 -8
  24. package/dist/execution/run-synthesis.js +114 -32
  25. package/dist/index.d.ts +2 -5
  26. package/dist/index.js +3 -6
  27. package/dist/input-scan/enrich.d.ts +5 -10
  28. package/dist/input-scan/enrich.js +12 -8
  29. package/dist/lib/hooks.d.ts +9 -0
  30. package/dist/lib/hooks.js +6 -1
  31. package/dist/lib/markdown-pdf.d.ts +27 -0
  32. package/dist/lib/markdown-pdf.js +236 -0
  33. package/dist/lib/metrics.d.ts +31 -0
  34. package/dist/lib/metrics.js +64 -0
  35. package/dist/lib/pdf-text.d.ts +23 -0
  36. package/dist/lib/pdf-text.js +34 -0
  37. package/dist/lib/regulatory-corpus/fetch-fda-guidance.js +3 -5
  38. package/dist/lib/regulatory-corpus/fetch-ich.js +3 -5
  39. package/dist/loop/run-loop.d.ts +5 -0
  40. package/dist/loop/run-loop.js +30 -2
  41. package/dist/loop/sub-agent.js +5 -6
  42. package/dist/loop/tool-name-repair.d.ts +11 -0
  43. package/dist/loop/tool-name-repair.js +23 -0
  44. package/dist/loop/turn-credentials.d.ts +5 -0
  45. package/dist/loop/turn-credentials.js +17 -0
  46. package/dist/loop/types.d.ts +14 -0
  47. package/dist/memory/card-builders.d.ts +1 -1
  48. package/dist/prompts/SOUL.d.ts +6 -6
  49. package/dist/prompts/SOUL.js +22 -121
  50. package/dist/prompts/analogical-reasoner.d.ts +1 -1
  51. package/dist/prompts/analogical-reasoner.js +35 -101
  52. package/dist/prompts/briefing.d.ts +20 -11
  53. package/dist/prompts/briefing.js +36 -19
  54. package/dist/prompts/conversation.d.ts +1 -1
  55. package/dist/prompts/conversation.js +103 -383
  56. package/dist/prompts/planner.d.ts +1 -5
  57. package/dist/prompts/planner.js +45 -128
  58. package/dist/prompts/report-session.d.ts +1 -1
  59. package/dist/prompts/report-session.js +26 -57
  60. package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
  61. package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +3 -3
  62. package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
  63. package/dist/prompts/sandbox/cheminformatics-agent.js +12 -47
  64. package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
  65. package/dist/prompts/sandbox/chromatin-agent.js +4 -5
  66. package/dist/prompts/sandbox/data-profiler.js +11 -34
  67. package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
  68. package/dist/prompts/sandbox/dna-methylation-agent.js +3 -1
  69. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
  70. package/dist/prompts/sandbox/drug-repurposing-agent.js +23 -73
  71. package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
  72. package/dist/prompts/sandbox/enrichment-agent.js +3 -1
  73. package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
  74. package/dist/prompts/sandbox/genomic-variant-agent.js +3 -4
  75. package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
  76. package/dist/prompts/sandbox/immune-profiling-agent.js +5 -4
  77. package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
  78. package/dist/prompts/sandbox/metabolomics-agent.js +3 -1
  79. package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
  80. package/dist/prompts/sandbox/microbiome-agent.js +3 -1
  81. package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
  82. package/dist/prompts/sandbox/multi-omics-integration-agent.js +3 -1
  83. package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
  84. package/dist/prompts/sandbox/multimodal-sc-agent.js +3 -1
  85. package/dist/prompts/sandbox/network-agent.d.ts +1 -1
  86. package/dist/prompts/sandbox/network-agent.js +3 -1
  87. package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
  88. package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +4 -7
  89. package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
  90. package/dist/prompts/sandbox/proteomics-agent.js +3 -1
  91. package/dist/prompts/sandbox/scientific-executor.d.ts +1 -1
  92. package/dist/prompts/sandbox/scientific-executor.js +0 -12
  93. package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
  94. package/dist/prompts/sandbox/single-cell-agent.js +3 -1
  95. package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
  96. package/dist/prompts/sandbox/spatial-omics-agent.js +3 -1
  97. package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
  98. package/dist/prompts/sandbox/statistical-modeling-agent.js +4 -4
  99. package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
  100. package/dist/prompts/sandbox/translational-safety-agent.js +10 -29
  101. package/dist/prompts/sandbox-standards.d.ts +15 -18
  102. package/dist/prompts/sandbox-standards.js +96 -305
  103. package/dist/prompts/synthesis-agent.d.ts +1 -1
  104. package/dist/prompts/synthesis-agent.js +24 -90
  105. package/dist/provenance/collector.d.ts +2 -5
  106. package/dist/provenance/collector.js +2 -5
  107. package/dist/provenance/seam.d.ts +36 -1
  108. package/dist/provenance/workspace-reads.d.ts +36 -0
  109. package/dist/provenance/workspace-reads.js +33 -0
  110. package/dist/providers/request-headers.js +12 -3
  111. package/dist/report-model/production-resolver.d.ts +22 -52
  112. package/dist/report-model/production-resolver.js +43 -112
  113. package/dist/report-render/chart-export.d.ts +9 -0
  114. package/dist/report-render/chart-export.js +1 -1
  115. package/dist/report-render/views/chart-view.d.ts +1 -0
  116. package/dist/report-render/views/chart-view.js +1 -0
  117. package/dist/report-render/views/lineage.d.ts +1 -0
  118. package/dist/report-render/views/page-view.d.ts +1 -0
  119. package/dist/report-render/views/page-view.js +1 -0
  120. package/dist/report-render/views/prose.d.ts +1 -0
  121. package/dist/report-render/views/prose.js +1 -0
  122. package/dist/report-render/views/references-view.d.ts +1 -0
  123. package/dist/report-render/views/values.d.ts +1 -0
  124. package/dist/report-render/views/values.js +1 -0
  125. package/dist/runtime/assemble.d.ts +20 -9
  126. package/dist/runtime/assemble.js +47 -38
  127. package/dist/sandbox/client.d.ts +5 -3
  128. package/dist/sandbox/create-sandbox.d.ts +7 -12
  129. package/dist/sandbox/create-sandbox.js +15 -37
  130. package/dist/sandbox/docker-client.d.ts +1 -3
  131. package/dist/sandbox/docker-client.js +3 -5
  132. package/dist/sandbox/exec-outcome.d.ts +11 -11
  133. package/dist/sandbox/exec-outcome.js +22 -22
  134. package/dist/sandbox/exec.d.ts +5 -0
  135. package/dist/sandbox/exec.js +9 -1
  136. package/dist/sandbox/identity.d.ts +4 -16
  137. package/dist/sandbox/identity.js +5 -21
  138. package/dist/sandbox/k8s-client.d.ts +0 -1
  139. package/dist/sandbox/k8s-client.js +8 -13
  140. package/dist/sandbox/lease-names.d.ts +6 -0
  141. package/dist/sandbox/lease-names.js +12 -0
  142. package/dist/sandbox/leases.d.ts +105 -0
  143. package/dist/sandbox/leases.js +519 -0
  144. package/dist/sandbox/liveness.d.ts +5 -2
  145. package/dist/sandbox/mount-plan.d.ts +10 -1
  146. package/dist/sandbox/mount-plan.js +7 -1
  147. package/dist/sandbox/reconciler.d.ts +58 -0
  148. package/dist/sandbox/reconciler.js +153 -0
  149. package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
  150. package/dist/sandbox/types.d.ts +25 -18
  151. package/dist/sandbox/types.js +10 -4
  152. package/dist/schemas/plan-schemas.d.ts +0 -21
  153. package/dist/schemas/plan-schemas.js +2 -3
  154. package/dist/schemas/run-synthesis.d.ts +2 -2
  155. package/dist/schemas/run-synthesis.js +3 -3
  156. package/dist/schemas/validate-plan.d.ts +1 -14
  157. package/dist/schemas/validate-plan.js +5 -24
  158. package/dist/schemas/workflow-state.d.ts +3 -32
  159. package/dist/schemas/workflow-state.js +4 -13
  160. package/dist/state/index.d.ts +0 -1
  161. package/dist/state/index.js +0 -1
  162. package/dist/state/migrations/20261030120000_lease_the_sandboxes.d.ts +7 -0
  163. package/dist/state/migrations/20261030120000_lease_the_sandboxes.js +34 -0
  164. package/dist/state/migrations/20261030120100_drop_the_report_derivations.d.ts +5 -0
  165. package/dist/state/migrations/20261030120100_drop_the_report_derivations.js +9 -0
  166. package/dist/state/migrations/20261030120200_keep_the_report_derivations.d.ts +6 -0
  167. package/dist/state/migrations/20261030120200_keep_the_report_derivations.js +10 -0
  168. package/dist/state/migrations/index.js +6 -0
  169. package/dist/state/purge-analysis.d.ts +4 -2
  170. package/dist/state/purge-analysis.js +22 -11
  171. package/dist/state/sandbox-leases.d.ts +81 -0
  172. package/dist/state/sandbox-leases.js +247 -0
  173. package/dist/state/schema.d.ts +1 -13
  174. package/dist/state/schema.js +1 -6
  175. package/dist/state/step-executions.d.ts +0 -2
  176. package/dist/state/step-executions.js +1 -4
  177. package/dist/tasks/data-profile.d.ts +40 -2
  178. package/dist/tasks/data-profile.js +89 -87
  179. package/dist/testing.d.ts +2 -0
  180. package/dist/testing.js +6 -1
  181. package/dist/tools/ad-hoc-router.d.ts +1 -6
  182. package/dist/tools/ad-hoc-router.js +5 -48
  183. package/dist/tools/bio/comptox.js +1 -1
  184. package/dist/tools/bio/drug-gene-interactions.js +1 -1
  185. package/dist/tools/bio/gene-disease-evidence.js +1 -1
  186. package/dist/tools/bio/keys.d.ts +1 -1
  187. package/dist/tools/bio/pubmed.js +31 -0
  188. package/dist/tools/bio/search-gene.js +17 -0
  189. package/dist/tools/bio/search-geo-datasets.js +13 -0
  190. package/dist/tools/bio/search-regulatory-approvals.js +1 -1
  191. package/dist/tools/define-tool.d.ts +25 -2
  192. package/dist/tools/define-tool.js +11 -1
  193. package/dist/tools/display/show-user.js +1 -1
  194. package/dist/tools/execute-analysis.d.ts +1 -3
  195. package/dist/tools/execute-analysis.js +5 -33
  196. package/dist/tools/report-session/index.d.ts +0 -1
  197. package/dist/tools/report-session/index.js +0 -1
  198. package/dist/tools/report-session/script-tools.d.ts +30 -0
  199. package/dist/tools/report-session/script-tools.js +177 -0
  200. package/dist/tools/research/generate-analogy-report.d.ts +16 -9
  201. package/dist/tools/research/generate-analogy-report.js +111 -49
  202. package/dist/tools/research/generate-plan.d.ts +102 -7
  203. package/dist/tools/research/generate-plan.js +74 -43
  204. package/dist/tools/research/index.d.ts +4 -3
  205. package/dist/tools/research/index.js +4 -3
  206. package/dist/tools/research/inspect-run.d.ts +0 -1
  207. package/dist/tools/research/inspect-run.js +5 -10
  208. package/dist/tools/research/search-arxiv.js +15 -0
  209. package/dist/tools/research/search-github-repos.js +13 -0
  210. package/dist/tools/research/search-semantic-scholar.js +16 -0
  211. package/dist/tools/research/synthesis-lookups.d.ts +21 -0
  212. package/dist/tools/research/synthesis-lookups.js +29 -0
  213. package/dist/tools/research/web-fetch.d.ts +1 -1
  214. package/dist/tools/research/web-fetch.js +14 -12
  215. package/dist/tools/sandbox/lease-tools.d.ts +32 -0
  216. package/dist/tools/sandbox/lease-tools.js +60 -0
  217. package/dist/tools/script/codemode-worker.d.ts +5 -0
  218. package/dist/tools/script/codemode-worker.js +5 -0
  219. package/dist/tools/script/file-tools.d.ts +100 -0
  220. package/dist/tools/script/file-tools.js +377 -0
  221. package/dist/tools/script/metrics.d.ts +21 -0
  222. package/dist/tools/script/metrics.js +38 -0
  223. package/dist/tools/script/quickjs.wasm +0 -0
  224. package/dist/tools/script/run-script.d.ts +76 -0
  225. package/dist/tools/script/run-script.js +326 -0
  226. package/dist/tools/script/scratch.d.ts +81 -0
  227. package/dist/tools/script/scratch.js +142 -0
  228. package/dist/tools/start-report-session.js +1 -1
  229. package/dist/tools/workspace/edit-file.js +2 -1
  230. package/dist/tools/workspace/execute-command.d.ts +9 -13
  231. package/dist/tools/workspace/execute-command.js +23 -19
  232. package/dist/tools/workspace/file-stat.js +1 -1
  233. package/dist/tools/workspace/grep.d.ts +5 -2
  234. package/dist/tools/workspace/grep.js +19 -10
  235. package/dist/tools/workspace/mutator.d.ts +48 -4
  236. package/dist/tools/workspace/mutator.js +43 -12
  237. package/dist/tools/workspace/read-file.d.ts +5 -2
  238. package/dist/tools/workspace/read-file.js +15 -11
  239. package/dist/tools/workspace/read-surface.d.ts +17 -0
  240. package/dist/tools/workspace/read-surface.js +17 -0
  241. package/dist/tools/workspace/result-bounds.d.ts +1 -0
  242. package/dist/tools/workspace/run-exec.d.ts +12 -13
  243. package/dist/tools/workspace/run-exec.js +13 -13
  244. package/dist/tools/workspace/scan-inputs.d.ts +2 -5
  245. package/dist/tools/workspace/scan-inputs.js +2 -3
  246. package/dist/tools/workspace/show-file.js +1 -1
  247. package/dist/tools/workspace/show-plan.js +4 -3
  248. package/dist/tools/workspace/write-file.js +2 -1
  249. package/dist/workflows/execute-analysis-scheduler.d.ts +0 -26
  250. package/dist/workflows/execute-analysis-scheduler.js +12 -32
  251. package/dist/workflows/execute-analysis.d.ts +17 -35
  252. package/dist/workflows/execute-analysis.js +13 -107
  253. package/dist/workflows/pause.js +29 -22
  254. package/dist/workflows/sandbox-step.d.ts +16 -31
  255. package/dist/workflows/sandbox-step.js +36 -71
  256. package/dist/workflows/test/sql-writes.d.ts +0 -1
  257. package/dist/workflows/test/sql-writes.js +0 -2
  258. package/dist/workspace/filesystem.d.ts +2 -2
  259. package/dist/workspace/filesystem.js +10 -5
  260. package/dist/workspace/paths.d.ts +19 -1
  261. package/dist/workspace/paths.js +22 -1
  262. package/package.json +6 -3
  263. package/dist/prompts/literature-reviewer.d.ts +0 -1
  264. package/dist/prompts/literature-reviewer.js +0 -114
  265. package/dist/sandbox/reaper.d.ts +0 -81
  266. package/dist/sandbox/reaper.js +0 -161
  267. package/dist/sandbox/step-sandbox.d.ts +0 -47
  268. package/dist/sandbox/step-sandbox.js +0 -53
  269. package/dist/state/active-sandboxes.d.ts +0 -33
  270. package/dist/state/active-sandboxes.js +0 -65
  271. package/dist/tasks/extract-values-script.d.ts +0 -64
  272. package/dist/tasks/extract-values-script.js +0 -180
  273. package/dist/tasks/extract-values.d.ts +0 -77
  274. package/dist/tasks/extract-values.js +0 -146
  275. package/dist/tools/report-session/derive-table.d.ts +0 -164
  276. package/dist/tools/report-session/derive-table.js +0 -419
  277. package/dist/tools/research/literature-reviewer.d.ts +0 -42
  278. package/dist/tools/research/literature-reviewer.js +0 -107
  279. package/dist/workflows/metrics.d.ts +0 -23
  280. package/dist/workflows/metrics.js +0 -38
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The sandbox reconciler (sandbox-leases spec): the backstop of the lease workflows.
3
+ *
4
+ * A lease workflow removes its own machine at each normal end. The reconciler covers the ends that a lease workflow
5
+ * cannot see: an operator cancel of the lease workflow, a purge, and a consumer that ends while its lease workflow
6
+ * waits in a pause. Each 5 minutes it does three passes in one DBOS step:
7
+ *
8
+ * 1. Each managed machine whose lease workflow is terminal goes away. A machine whose owner does not resolve goes
9
+ * away only when a liveness probe finds it dead.
10
+ * 2. Each lease row whose lease workflow is terminal or absent becomes `released`, thus its capacity frees.
11
+ * 3. Each lease workflow whose owner is terminal gets a cancel, and the next sweep removes its machine.
12
+ *
13
+ * The pure decision (`classifyManaged`) and the sweep (`reconcileOnce`) take their effects as parameters, thus a
14
+ * test drives them without a DBOS runtime.
15
+ */
16
+ import type { Logger } from "../lib/logger.js";
17
+ import type { Querier } from "../state/db.js";
18
+ import { type ResolveWorkspaceRoot } from "../workspace/paths.js";
19
+ import type { SandboxClient } from "./client.js";
20
+ import type { ManagedSandbox } from "./types.js";
21
+ export type ReconcileDecision = "leave" | "remove" | "remove-if-dead";
22
+ /**
23
+ * Decide the fate of a managed machine. A resolved owner status is authoritative in both directions: DBOS records
24
+ * the status of a lease workflow at its enqueue, before its machine exists. A missing status is authoritative for
25
+ * neither, thus past the grace the decision defers to a liveness probe.
26
+ */
27
+ export declare function classifyManaged(sb: ManagedSandbox, status: {
28
+ status: string;
29
+ } | null, nowMs: number, graceMs: number): ReconcileDecision;
30
+ export type ReconcilerDeps = {
31
+ readonly pool: Querier;
32
+ readonly sandboxClient: Pick<SandboxClient, "listManagedSandboxes" | "teardownById" | "isAliveById" | "teardown">;
33
+ readonly resolveWorkspaceRoot: ResolveWorkspaceRoot;
34
+ readonly getStatus: (workflowId: string) => Promise<{
35
+ status: string;
36
+ } | null>;
37
+ /** Cancel a lease workflow whose owner ended. */
38
+ readonly cancel: (workflowId: string) => Promise<void>;
39
+ /** Creation-time grace before an unattributable machine is even probed. */
40
+ readonly graceMs?: number;
41
+ /** Wall-clock ms; injected for tests. */
42
+ readonly nowMs?: () => number;
43
+ readonly logger?: Logger;
44
+ };
45
+ export type ReconcileSummary = {
46
+ readonly managedCount: number;
47
+ readonly removedCount: number;
48
+ readonly leftCount: number;
49
+ /** Machines past the grace whose owner did not resolve, but which are alive. A non-zero value is a reported leak. */
50
+ readonly liveUnattributed: number;
51
+ readonly leasesReleased: number;
52
+ readonly leasesCanceled: number;
53
+ };
54
+ /** One sweep. A failure on one machine or one lease is logged and skipped, and the next sweep tries again. */
55
+ export declare function reconcileOnce(deps: ReconcilerDeps): Promise<ReconcileSummary>;
56
+ export type RegisterReconcilerDeps = Omit<ReconcilerDeps, "getStatus" | "nowMs">;
57
+ /** Register the scheduled reconciler: one unsharded workflow, whose whole sweep is one step. */
58
+ export declare function registerSandboxReconciler(deps: RegisterReconcilerDeps): void;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * The sandbox reconciler (sandbox-leases spec): the backstop of the lease workflows.
3
+ *
4
+ * A lease workflow removes its own machine at each normal end. The reconciler covers the ends that a lease workflow
5
+ * cannot see: an operator cancel of the lease workflow, a purge, and a consumer that ends while its lease workflow
6
+ * waits in a pause. Each 5 minutes it does three passes in one DBOS step:
7
+ *
8
+ * 1. Each managed machine whose lease workflow is terminal goes away. A machine whose owner does not resolve goes
9
+ * away only when a liveness probe finds it dead.
10
+ * 2. Each lease row whose lease workflow is terminal or absent becomes `released`, thus its capacity frees.
11
+ * 3. Each lease workflow whose owner is terminal gets a cancel, and the next sweep removes its machine.
12
+ *
13
+ * The pure decision (`classifyManaged`) and the sweep (`reconcileOnce`) take their effects as parameters, thus a
14
+ * test drives them without a DBOS runtime.
15
+ */
16
+ import { rm } from "node:fs/promises";
17
+ import { DBOS } from "@dbos-inc/dbos-sdk";
18
+ import { createNoopLogger } from "../lib/console-logger.js";
19
+ import { recordMachineReplaced } from "../lib/metrics.js";
20
+ import { untracedWorkflow } from "../lib/otel-spans.js";
21
+ import { unwrapOrThrow } from "../lib/result.js";
22
+ import { scheduleWorkflow } from "../runtime/dbos.js";
23
+ import { openLeases, releaseLease } from "../state/sandbox-leases.js";
24
+ import { tailWritePrefix } from "../workspace/paths.js";
25
+ import { leaseRecordTail } from "./lease-names.js";
26
+ const RECONCILER_CRON = "0 */5 * * * *";
27
+ const RECONCILER_WORKFLOW = "sandbox-reconciler";
28
+ const DEFAULT_GRACE_MS = 10 * 60_000;
29
+ /** The statuses of a workflow that still runs. A machine or a lease of such a workflow stays. */
30
+ const ACTIVE_WORKFLOW_STATUSES = new Set(["PENDING", "ENQUEUED", "RUNNING"]);
31
+ /**
32
+ * Decide the fate of a managed machine. A resolved owner status is authoritative in both directions: DBOS records
33
+ * the status of a lease workflow at its enqueue, before its machine exists. A missing status is authoritative for
34
+ * neither, thus past the grace the decision defers to a liveness probe.
35
+ */
36
+ export function classifyManaged(sb, status, nowMs, graceMs) {
37
+ if (status)
38
+ return ACTIVE_WORKFLOW_STATUSES.has(status.status) ? "leave" : "remove";
39
+ const ageMs = sb.createdAtMs == null ? Number.POSITIVE_INFINITY : nowMs - sb.createdAtMs;
40
+ return ageMs >= graceMs ? "remove-if-dead" : "leave";
41
+ }
42
+ async function sweepMachines(deps, logger, nowMs, graceMs) {
43
+ const managed = await deps.sandboxClient.listManagedSandboxes();
44
+ let removedCount = 0;
45
+ let leftCount = 0;
46
+ let liveUnattributed = 0;
47
+ for (const sb of managed) {
48
+ const status = sb.ownerWorkflowId ? await deps.getStatus(sb.ownerWorkflowId) : null;
49
+ const decision = classifyManaged(sb, status, nowMs, graceMs);
50
+ if (decision === "leave") {
51
+ leftCount++;
52
+ continue;
53
+ }
54
+ if (decision === "remove-if-dead") {
55
+ if (sb.ownerWorkflowId)
56
+ logger.warn("owner workflow id resolved to no workflow", { sandboxId: sb.sandboxId, ownerWorkflowId: sb.ownerWorkflowId });
57
+ let liveness;
58
+ try {
59
+ liveness = await deps.sandboxClient.isAliveById(sb.sandboxId);
60
+ }
61
+ catch (failure) {
62
+ // A probe that cannot answer is not a dead machine. The next sweep probes again.
63
+ logger.warn("liveness probe threw — leaving this machine", { sandboxId: sb.sandboxId, ...logger.errorFields(failure) });
64
+ leftCount++;
65
+ continue;
66
+ }
67
+ if (liveness.alive) {
68
+ logger.warn("machine has no resolvable owner but is still alive — left standing", {
69
+ sandboxId: sb.sandboxId,
70
+ ownerWorkflowId: sb.ownerWorkflowId,
71
+ });
72
+ leftCount++;
73
+ liveUnattributed++;
74
+ continue;
75
+ }
76
+ }
77
+ try {
78
+ await deps.sandboxClient.teardownById(sb.sandboxId);
79
+ recordMachineReplaced({ cause: "release" });
80
+ removedCount++;
81
+ }
82
+ catch (failure) {
83
+ logger.warn("removal failed — skipping this round", { sandboxId: sb.sandboxId, ...logger.errorFields(failure) });
84
+ }
85
+ }
86
+ return { managedCount: managed.length, removedCount, leftCount, liveUnattributed };
87
+ }
88
+ async function sweepLeases(deps, logger) {
89
+ let leasesReleased = 0;
90
+ let leasesCanceled = 0;
91
+ for (const lease of unwrapOrThrow(await openLeases(deps.pool))) {
92
+ const status = await deps.getStatus(lease.leaseWorkflowId);
93
+ const leaseActive = status !== null && ACTIVE_WORKFLOW_STATUSES.has(status.status);
94
+ if (!leaseActive) {
95
+ // A lease row with no workflow: its acquire stopped before the enqueue. The owner reruns its acquire when it
96
+ // still runs, thus the row stays until the owner ends.
97
+ if (status === null) {
98
+ const owner = await deps.getStatus(lease.ownerWorkflowId);
99
+ if (owner !== null && ACTIVE_WORKFLOW_STATUSES.has(owner.status))
100
+ continue;
101
+ }
102
+ try {
103
+ const released = unwrapOrThrow(await releaseLease(deps.pool, lease.leaseWorkflowId, "lease-workflow-ended"));
104
+ if (released?.machine !== undefined)
105
+ await deps.sandboxClient.teardown(released.machine);
106
+ const dir = tailWritePrefix({ workspaceRoot: await deps.resolveWorkspaceRoot(lease.analysisId), tail: leaseRecordTail(lease.leaseKey) });
107
+ await rm(dir, { recursive: true, force: true });
108
+ leasesReleased++;
109
+ }
110
+ catch (failure) {
111
+ logger.warn("the release of an ended lease failed — skipping this round", {
112
+ leaseWorkflowId: lease.leaseWorkflowId,
113
+ ...logger.errorFields(failure),
114
+ });
115
+ }
116
+ continue;
117
+ }
118
+ const owner = await deps.getStatus(lease.ownerWorkflowId);
119
+ if (owner !== null && ACTIVE_WORKFLOW_STATUSES.has(owner.status))
120
+ continue;
121
+ try {
122
+ await deps.cancel(lease.leaseWorkflowId);
123
+ leasesCanceled++;
124
+ }
125
+ catch (failure) {
126
+ logger.warn("the cancel of a lease whose owner ended failed", { leaseWorkflowId: lease.leaseWorkflowId, ...logger.errorFields(failure) });
127
+ }
128
+ }
129
+ return { leasesReleased, leasesCanceled };
130
+ }
131
+ /** One sweep. A failure on one machine or one lease is logged and skipped, and the next sweep tries again. */
132
+ export async function reconcileOnce(deps) {
133
+ const logger = (deps.logger ?? createNoopLogger()).named("sandbox-reconciler");
134
+ const nowMs = (deps.nowMs ?? (() => Date.now()))();
135
+ const graceMs = deps.graceMs ?? DEFAULT_GRACE_MS;
136
+ const machines = await sweepMachines(deps, logger, nowMs, graceMs);
137
+ const leases = await sweepLeases(deps, logger);
138
+ const summary = { ...machines, ...leases };
139
+ logger.info("sweep completed", { ...summary });
140
+ return summary;
141
+ }
142
+ /** Register the scheduled reconciler: one unsharded workflow, whose whole sweep is one step. */
143
+ export function registerSandboxReconciler(deps) {
144
+ const reconciler = DBOS.registerWorkflow(async () => {
145
+ // One step for the whole sweep: the machine list is live cluster state, and it sets how many status reads
146
+ // run. In the body each status read takes a function id, thus a different list on a replay would diverge.
147
+ await DBOS.runStep(() => reconcileOnce({ ...deps, getStatus: async (workflowId) => await DBOS.getWorkflowStatus(workflowId) }), {
148
+ name: "sandbox-reconciler-sweep",
149
+ });
150
+ }, { name: RECONCILER_WORKFLOW });
151
+ untracedWorkflow(RECONCILER_WORKFLOW);
152
+ scheduleWorkflow({ scheduleName: RECONCILER_WORKFLOW, workflowFn: reconciler, schedule: RECONCILER_CRON });
153
+ }
@@ -41,7 +41,7 @@ export declare function toolActivityKey(toolUseId: string): string;
41
41
  * phase, and the `data-activity-entry` that keeps the report in the run stream under the synthesis step. `seq` is the
42
42
  * position of the report in the synthesis, so each entry has its own id. The `extra` fields stay on the progress part.
43
43
  */
44
- export declare function synthesisEmission(runId: string, stepId: string, seq: number, phase: SynthesisPhase, activity: string, at: string, extra: Pick<SynthesisProgressPart, "delegationCount" | "reason" | "error">): {
44
+ export declare function synthesisEmission(runId: string, stepId: string, seq: number, phase: SynthesisPhase, activity: string, at: string, extra: Pick<SynthesisProgressPart, "reason" | "error">): {
45
45
  readonly progress: SynthesisProgressPart;
46
46
  readonly entry: ActivityEntryPart;
47
47
  };
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Sandbox-client types — the wire/persistence shapes that cross the
3
- * submit/poll protocol (see the harness-sandbox-exec spec) and the active-sandbox registry.
3
+ * submit/poll protocol (see the harness-sandbox-exec spec) and the lease table.
4
4
  *
5
- * `SandboxRef` is the handle the harness uses to talk to a live sandbox. The
6
- * active-sandbox registry persists the same shape (`PersistedSandboxRef`, from
5
+ * `SandboxRef` is the handle the harness uses to talk to a live sandbox. A lease
6
+ * row persists the same shape (`PersistedSandboxRef`, from
7
7
  * `harness/state/schema.ts`).
8
8
  */
9
9
  import type { ResultAsync } from "neverthrow";
@@ -212,6 +212,10 @@ export declare const ExecResultSchema: z.ZodObject<{
212
212
  stderrTotalBytes: z.ZodOptional<z.ZodNumber>;
213
213
  syntheticFailure: z.ZodOptional<z.ZodObject<{
214
214
  reason: z.ZodString;
215
+ memoryLimitGb: z.ZodOptional<z.ZodNumber>;
216
+ }, z.core.$strip>>;
217
+ lost: z.ZodOptional<z.ZodObject<{
218
+ reason: z.ZodString;
215
219
  }, z.core.$strip>>;
216
220
  provenance: z.ZodOptional<z.ZodObject<{
217
221
  disabled: z.ZodDefault<z.ZodBoolean>;
@@ -276,6 +280,10 @@ export declare const PollResponseSchema: z.ZodObject<{
276
280
  stderrTotalBytes: z.ZodOptional<z.ZodNumber>;
277
281
  syntheticFailure: z.ZodOptional<z.ZodObject<{
278
282
  reason: z.ZodString;
283
+ memoryLimitGb: z.ZodOptional<z.ZodNumber>;
284
+ }, z.core.$strip>>;
285
+ lost: z.ZodOptional<z.ZodObject<{
286
+ reason: z.ZodString;
279
287
  }, z.core.$strip>>;
280
288
  provenance: z.ZodOptional<z.ZodObject<{
281
289
  disabled: z.ZodDefault<z.ZodBoolean>;
@@ -327,10 +335,12 @@ export type SubmitExecBody = {
327
335
  };
328
336
  /** What a spawn needs beside its session. */
329
337
  export type SandboxSpec = {
330
- /** Owning DBOS child workflow id (`"${parentRunId}-${N}"`). Recorded verbatim
331
- * on the sandbox machine under `cortex/owner-workflow-id` so the reaper can
332
- * map a cluster-side machine back to its workflow and check liveness. */
333
- childWorkflowId: string;
338
+ /** The id of the lease workflow that owns the machine. Recorded verbatim on the
339
+ * machine under `cortex/owner-workflow-id`, thus the reconciler maps a machine
340
+ * back to its lease workflow. */
341
+ ownerWorkflowId: string;
342
+ /** The workspace-relative directory of the exec records of the lease. */
343
+ recordTail: string;
334
344
  /** Backend-specific extras carried through to the per-backend impl. */
335
345
  image?: string;
336
346
  extraEnv?: Record<string, string>;
@@ -356,23 +366,20 @@ export type SandboxLabels = Readonly<Record<string, string>>;
356
366
  */
357
367
  export type ResolveSandboxLabels = (session: RunSession) => ResultAsync<SandboxLabels, GateFailure>;
358
368
  /**
359
- * The identity minted for a sandbox machine *before* it is spawned — the
360
- * durable half of the two-step create (see the harness-sandbox-exec spec). Step 1 checkpoints this so a
361
- * recovery re-run of the spawn step adopts the already-created machine under
362
- * the same name instead of leaking a second one.
369
+ * The name of a sandbox machine. It comes from the lease workflow and the machine
370
+ * generation, thus a rerun of the spawn step adopts the machine of the earlier
371
+ * attempt instead of a second one.
363
372
  */
364
373
  export type SandboxIdentity = {
365
- /** `sbx-{run8}-{uuid4}` — informative for `kubectl`, not load-bearing; the
366
- * checkpoint, not the name, is what makes create idempotent. */
374
+ /** `sbx-{run8}-{hash12}`. */
367
375
  sandboxId: string;
368
376
  };
369
377
  /**
370
378
  * A sandbox machine the backend is running that Cortex *manages*
371
- * (`app.kubernetes.io/managed-by=cortex`), enumerated by the reaper for the
372
- * cluster→registry sweep (see the harness-sandbox-exec spec). `ownerWorkflowId`
373
- * is the id as minted, so it is usable as a DBOS lookup key; null means the
374
- * machine records no owner, and such a machine is reaped only past a
375
- * creation-time grace and only when observably dead.
379
+ * (`app.kubernetes.io/managed-by=cortex`), enumerated by the reconciler.
380
+ * `ownerWorkflowId` is the id of the lease workflow as given, so it is usable as
381
+ * a DBOS lookup key; null means the machine records no owner, and such a machine
382
+ * is removed only past a creation-time grace and only when observably dead.
376
383
  */
377
384
  export type ManagedSandbox = {
378
385
  sandboxId: string;
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Sandbox-client types — the wire/persistence shapes that cross the
3
- * submit/poll protocol (see the harness-sandbox-exec spec) and the active-sandbox registry.
3
+ * submit/poll protocol (see the harness-sandbox-exec spec) and the lease table.
4
4
  *
5
- * `SandboxRef` is the handle the harness uses to talk to a live sandbox. The
6
- * active-sandbox registry persists the same shape (`PersistedSandboxRef`, from
5
+ * `SandboxRef` is the handle the harness uses to talk to a live sandbox. A lease
6
+ * row persists the same shape (`PersistedSandboxRef`, from
7
7
  * `harness/state/schema.ts`).
8
8
  */
9
9
  import { z } from "zod";
@@ -78,12 +78,18 @@ export const ExecResultSchema = z.object({
78
78
  stderrTruncated: z.boolean().optional(),
79
79
  stdoutTotalBytes: z.number().int().nonnegative().optional(),
80
80
  stderrTotalBytes: z.number().int().nonnegative().optional(),
81
- /** Set when the liveness probe found the machine dead under the exec. */
81
+ /**
82
+ * Set when the machine died under the exec, or when a new machine of the lease found the exec lost. The sandbox
83
+ * module adds the memory limit of the grant, thus the agent can tell its own memory use from an outside cause.
84
+ */
82
85
  syntheticFailure: z
83
86
  .object({
84
87
  reason: z.string(),
88
+ memoryLimitGb: z.number().optional(),
85
89
  })
86
90
  .optional(),
91
+ /** Set by sandbox-server on the record of an exec that a restart of the machine cut. */
92
+ lost: z.object({ reason: z.string() }).optional(),
87
93
  /** Runtime file-I/O frame from sandbox-server. Absent from a synthetic failure. */
88
94
  provenance: ProvenanceFrameSchema.optional(),
89
95
  /**
@@ -18,13 +18,6 @@ export declare const PlanStepSchema: z.ZodObject<{
18
18
  caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
19
19
  packages: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
20
20
  depends_on: z.ZodArray<z.ZodString>;
21
- resources: z.ZodNonOptional<z.ZodOptional<z.ZodObject<{
22
- cpu: z.ZodNumber;
23
- memoryGb: z.ZodNumber;
24
- gpu: z.ZodOptional<z.ZodObject<{
25
- count: z.ZodNumber;
26
- }, z.core.$strip>>;
27
- }, z.core.$strip>>>;
28
21
  grounding: z.ZodOptional<z.ZodObject<{
29
22
  status: z.ZodEnum<{
30
23
  flagged: "flagged";
@@ -69,13 +62,6 @@ export declare const PlannerPlanSchema: z.ZodObject<{
69
62
  caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
70
63
  packages: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
71
64
  depends_on: z.ZodArray<z.ZodString>;
72
- resources: z.ZodNonOptional<z.ZodOptional<z.ZodObject<{
73
- cpu: z.ZodNumber;
74
- memoryGb: z.ZodNumber;
75
- gpu: z.ZodOptional<z.ZodObject<{
76
- count: z.ZodNumber;
77
- }, z.core.$strip>>;
78
- }, z.core.$strip>>>;
79
65
  grounding: z.ZodOptional<z.ZodObject<{
80
66
  status: z.ZodEnum<{
81
67
  flagged: "flagged";
@@ -129,13 +115,6 @@ export declare const PlanningAgentOutputSchema: z.ZodObject<{
129
115
  caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
130
116
  packages: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
131
117
  depends_on: z.ZodArray<z.ZodString>;
132
- resources: z.ZodNonOptional<z.ZodOptional<z.ZodObject<{
133
- cpu: z.ZodNumber;
134
- memoryGb: z.ZodNumber;
135
- gpu: z.ZodOptional<z.ZodObject<{
136
- count: z.ZodNumber;
137
- }, z.core.$strip>>;
138
- }, z.core.$strip>>>;
139
118
  grounding: z.ZodOptional<z.ZodObject<{
140
119
  status: z.ZodEnum<{
141
120
  flagged: "flagged";
@@ -11,19 +11,18 @@ import { DEFAULT_SANDBOX_MAX_STEPS } from "../config/resource-limits.js";
11
11
  * and the hardcoded sandbox turn budget. */
12
12
  export const PlanStepSchema = AnalysisStepSchema.omit({
13
13
  status: true,
14
- timeout: true,
15
14
  summary: true,
16
15
  artifactIds: true,
17
16
  error: true,
18
17
  maxSteps: true,
19
18
  })
20
- .required({ agent: true, resources: true, packages: true, capability: true })
19
+ .required({ agent: true, packages: true, capability: true })
21
20
  .extend({
22
21
  agent: z.enum(plannableAgentIds).describe("Sandbox agent ID, routed by the step's primary data object. Must be one of the available agents."),
23
22
  });
24
23
  /** Plan schema for planner output — uses PlanStepSchema for steps and requires
25
24
  * a concise title (optional on the persistence schema for historical plans). */
26
- export const PlannerPlanSchema = AnalysisPlanSchema.extend({
25
+ export const PlannerPlanSchema = AnalysisPlanSchema.omit({ request: true }).extend({
27
26
  title: z
28
27
  .string()
29
28
  .min(1)
@@ -2,8 +2,8 @@
2
2
  * Run synthesis schema — cross-step findings grounded in literature.
3
3
  *
4
4
  * Produced by the synthesis step after all sandbox steps complete.
5
- * Combines computational findings from step summaries with literature
6
- * evidence from the literature-reviewer agent.
5
+ * Combines computational findings from step summaries with the literature
6
+ * evidence of the lookups of the synthesizer.
7
7
  *
8
8
  * This schema is the synthesizer's output contract: it is emitted as the
9
9
  * `submit_synthesis` tool's arg schema, so every field's meaning must live in
@@ -2,8 +2,8 @@
2
2
  * Run synthesis schema — cross-step findings grounded in literature.
3
3
  *
4
4
  * Produced by the synthesis step after all sandbox steps complete.
5
- * Combines computational findings from step summaries with literature
6
- * evidence from the literature-reviewer agent.
5
+ * Combines computational findings from step summaries with the literature
6
+ * evidence of the lookups of the synthesizer.
7
7
  *
8
8
  * This schema is the synthesizer's output contract: it is emitted as the
9
9
  * `submit_synthesis` tool's arg schema, so every field's meaning must live in
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import { z } from "zod";
13
13
  export const LiteratureReferenceSchema = z.object({
14
- pmid: z.string().describe("Numeric PubMed ID. Must come from a literature_reviewer response — never invented."),
14
+ pmid: z.string().describe("Numeric PubMed ID, from a lookup result of this run."),
15
15
  citation: z.string().describe('Short citation for the paper, e.g. "Smith 2020".'),
16
16
  relevance: z.string().describe("Why this paper matters to the finding — what it establishes, challenges, or contextualizes."),
17
17
  concordance: z
@@ -9,25 +9,12 @@
9
9
  * 1. Topological sort succeeds (no cycles, no missing deps)
10
10
  * 2. Output prefix uniqueness
11
11
  * 3. All agent assignments exist in the agent catalog
12
- * 4. All steps have resources defined
13
12
  */
14
- import type { ResourceLimits } from "../config/resource-limits.js";
15
13
  import type { AnalysisPlan } from "./workflow-state.js";
16
14
  export type ValidationResult = {
17
15
  valid: boolean;
18
16
  errors: string[];
19
17
  };
20
- export type ValidatePlanOptions = {
21
- /**
22
- * Host per-step resource ceilings. When present, a step whose declared
23
- * `resources` exceed them is an error — the planner gets actionable
24
- * feedback at plan time instead of a silent clamp at sandbox creation.
25
- * The plan-generation path passes this; `execute_analysis` plan mode deliberately does
26
- * not, so stored plans that predate the policy keep running (the
27
- * sandbox-creation clamp remains their backstop).
28
- */
29
- readonly perStepCeiling?: ResourceLimits;
30
- };
31
18
  /** Derive a filesystem-safe output prefix from a step ID. */
32
19
  export declare function deriveOutputPrefix(stepId: string): string;
33
20
  /**
@@ -36,4 +23,4 @@ export declare function deriveOutputPrefix(stepId: string): string;
36
23
  * Returns `valid: true` if the plan passes all checks, or `valid: false`
37
24
  * with a list of human-readable error strings.
38
25
  */
39
- export declare function validatePlan(plan: AnalysisPlan, options?: ValidatePlanOptions): ValidationResult;
26
+ export declare function validatePlan(plan: AnalysisPlan): ValidationResult;
@@ -9,7 +9,6 @@
9
9
  * 1. Topological sort succeeds (no cycles, no missing deps)
10
10
  * 2. Output prefix uniqueness
11
11
  * 3. All agent assignments exist in the agent catalog
12
- * 4. All steps have resources defined
13
12
  */
14
13
  import { errorMessageOf } from "../lib/thrown.js";
15
14
  import { textOf } from "../lib/unknown-text.js";
@@ -75,7 +74,7 @@ export function deriveOutputPrefix(stepId) {
75
74
  * Returns `valid: true` if the plan passes all checks, or `valid: false`
76
75
  * with a list of human-readable error strings.
77
76
  */
78
- export function validatePlan(plan, options) {
77
+ export function validatePlan(plan) {
79
78
  const errors = [];
80
79
  if (plan.steps.length === 0) {
81
80
  return { valid: true, errors: [] };
@@ -120,25 +119,7 @@ export function validatePlan(plan, options) {
120
119
  errors.push(`Step "${step.id}" assigns unknown agent "${step.agent}" — not found in agent catalog`);
121
120
  }
122
121
  }
123
- // 4. Resources validation
124
- const ceiling = options?.perStepCeiling;
125
- for (const step of plan.steps) {
126
- if (!step.resources) {
127
- errors.push(`Step "${step.id}" has no resources defined — cpu and memoryGb are required`);
128
- continue;
129
- }
130
- if (!ceiling)
131
- continue;
132
- if (step.resources.cpu > ceiling.maxCpu) {
133
- errors.push(`Step "${step.id}" requests cpu: ${step.resources.cpu} but this host allows at most ` +
134
- `${ceiling.maxCpu} per step — reduce cpu or restructure the step`);
135
- }
136
- if (step.resources.memoryGb > ceiling.maxMemoryGb) {
137
- errors.push(`Step "${step.id}" requests memoryGb: ${step.resources.memoryGb} but this host allows at most ` +
138
- `${ceiling.maxMemoryGb} per step — reduce memoryGb or restructure the step`);
139
- }
140
- }
141
- // 5. Reserved step-id names (collide with artifact subdirectories or the
122
+ // 4. Reserved step-id names (collide with artifact subdirectories or the
142
123
  // run-phase synthesis ledger row)
143
124
  for (const step of plan.steps) {
144
125
  if (RESERVED_STEP_IDS.has(step.id.toLowerCase())) {
@@ -147,7 +128,7 @@ export function validatePlan(plan, options) {
147
128
  `step-directory convention; "${SYNTHESIS_STEP_ID}" is the run-level synthesis phase)`);
148
129
  }
149
130
  }
150
- // 6. Each package entry is a query of the one grammar. The validation IS
131
+ // 5. Each package entry is a query of the one grammar. The validation IS
151
132
  // the parse, thus no second reader of the grammar can disagree with the
152
133
  // link pass. An absent array passes, because stored plans from before
153
134
  // the field carry none.
@@ -158,7 +139,7 @@ export function validatePlan(plan, options) {
158
139
  errors.push(describeParseError(step.id, entry, parsed.error));
159
140
  }
160
141
  }
161
- // 7. Step-id path safety. The id becomes the `runs/{runId}/{stepId}` directory
142
+ // 6. Step-id path safety. The id becomes the `runs/{runId}/{stepId}` directory
162
143
  // segment and a `/{analysisId}/…` container mount path; an unsafe segment
163
144
  // (a slash, or `.`/`..`) could traverse or widen the mount. The sandbox
164
145
  // mount boundary also rejects these (assertSafeId), but catching it here
@@ -170,7 +151,7 @@ export function validatePlan(plan, options) {
170
151
  `and cannot be '.' or '..' (the id becomes a workspace directory and container mount segment)`);
171
152
  }
172
153
  }
173
- // 8. Step-id label safety. The id also becomes the value of the sandbox
154
+ // 7. Step-id label safety. The id also becomes the value of the sandbox
174
155
  // label `cortex/step-id`, and the harness stamps a label value with no
175
156
  // change (sandbox-labels spec). A safe id can be too long for a label
176
157
  // value, or it can start or end with a separator. Refused here, the
@@ -71,13 +71,6 @@ export declare const AnalysisStepSchema: z.ZodObject<{
71
71
  running: "running";
72
72
  skipped: "skipped";
73
73
  }>>;
74
- resources: z.ZodOptional<z.ZodObject<{
75
- cpu: z.ZodNumber;
76
- memoryGb: z.ZodNumber;
77
- gpu: z.ZodOptional<z.ZodObject<{
78
- count: z.ZodNumber;
79
- }, z.core.$strip>>;
80
- }, z.core.$strip>>;
81
74
  grounding: z.ZodOptional<z.ZodObject<{
82
75
  status: z.ZodEnum<{
83
76
  flagged: "flagged";
@@ -97,7 +90,6 @@ export declare const AnalysisStepSchema: z.ZodObject<{
97
90
  }, z.core.$strip>>;
98
91
  agent: z.ZodOptional<z.ZodString>;
99
92
  capability: z.ZodOptional<z.ZodString>;
100
- timeout: z.ZodOptional<z.ZodNumber>;
101
93
  maxSteps: z.ZodNumber;
102
94
  description: z.ZodOptional<z.ZodString>;
103
95
  summary: z.ZodOptional<z.ZodString>;
@@ -126,13 +118,6 @@ export declare const AnalysisPlanSchema: z.ZodObject<{
126
118
  running: "running";
127
119
  skipped: "skipped";
128
120
  }>>;
129
- resources: z.ZodOptional<z.ZodObject<{
130
- cpu: z.ZodNumber;
131
- memoryGb: z.ZodNumber;
132
- gpu: z.ZodOptional<z.ZodObject<{
133
- count: z.ZodNumber;
134
- }, z.core.$strip>>;
135
- }, z.core.$strip>>;
136
121
  grounding: z.ZodOptional<z.ZodObject<{
137
122
  status: z.ZodEnum<{
138
123
  flagged: "flagged";
@@ -152,7 +137,6 @@ export declare const AnalysisPlanSchema: z.ZodObject<{
152
137
  }, z.core.$strip>>;
153
138
  agent: z.ZodOptional<z.ZodString>;
154
139
  capability: z.ZodOptional<z.ZodString>;
155
- timeout: z.ZodOptional<z.ZodNumber>;
156
140
  maxSteps: z.ZodNumber;
157
141
  description: z.ZodOptional<z.ZodString>;
158
142
  summary: z.ZodOptional<z.ZodString>;
@@ -162,6 +146,7 @@ export declare const AnalysisPlanSchema: z.ZodObject<{
162
146
  created_at: z.ZodString;
163
147
  omicsType: z.ZodOptional<z.ZodString>;
164
148
  omicsSubtype: z.ZodOptional<z.ZodString>;
149
+ request: z.ZodOptional<z.ZodString>;
165
150
  }, z.core.$strip>;
166
151
  /**
167
152
  * Declarative suspension format — tells the frontend what to render
@@ -216,13 +201,6 @@ export declare const ContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
216
201
  running: "running";
217
202
  skipped: "skipped";
218
203
  }>>;
219
- resources: z.ZodOptional<z.ZodObject<{
220
- cpu: z.ZodNumber;
221
- memoryGb: z.ZodNumber;
222
- gpu: z.ZodOptional<z.ZodObject<{
223
- count: z.ZodNumber;
224
- }, z.core.$strip>>;
225
- }, z.core.$strip>>;
226
204
  grounding: z.ZodOptional<z.ZodObject<{
227
205
  status: z.ZodEnum<{
228
206
  flagged: "flagged";
@@ -242,7 +220,6 @@ export declare const ContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
242
220
  }, z.core.$strip>>;
243
221
  agent: z.ZodOptional<z.ZodString>;
244
222
  capability: z.ZodOptional<z.ZodString>;
245
- timeout: z.ZodOptional<z.ZodNumber>;
246
223
  maxSteps: z.ZodNumber;
247
224
  description: z.ZodOptional<z.ZodString>;
248
225
  summary: z.ZodOptional<z.ZodString>;
@@ -252,6 +229,7 @@ export declare const ContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
252
229
  created_at: z.ZodString;
253
230
  omicsType: z.ZodOptional<z.ZodString>;
254
231
  omicsSubtype: z.ZodOptional<z.ZodString>;
232
+ request: z.ZodOptional<z.ZodString>;
255
233
  }, z.core.$strip>;
256
234
  }, z.core.$strip>, z.ZodObject<{
257
235
  type: z.ZodLiteral<"json">;
@@ -354,13 +332,6 @@ export declare const SuspensionPayloadSchema: z.ZodObject<{
354
332
  running: "running";
355
333
  skipped: "skipped";
356
334
  }>>;
357
- resources: z.ZodOptional<z.ZodObject<{
358
- cpu: z.ZodNumber;
359
- memoryGb: z.ZodNumber;
360
- gpu: z.ZodOptional<z.ZodObject<{
361
- count: z.ZodNumber;
362
- }, z.core.$strip>>;
363
- }, z.core.$strip>>;
364
335
  grounding: z.ZodOptional<z.ZodObject<{
365
336
  status: z.ZodEnum<{
366
337
  flagged: "flagged";
@@ -380,7 +351,6 @@ export declare const SuspensionPayloadSchema: z.ZodObject<{
380
351
  }, z.core.$strip>>;
381
352
  agent: z.ZodOptional<z.ZodString>;
382
353
  capability: z.ZodOptional<z.ZodString>;
383
- timeout: z.ZodOptional<z.ZodNumber>;
384
354
  maxSteps: z.ZodNumber;
385
355
  description: z.ZodOptional<z.ZodString>;
386
356
  summary: z.ZodOptional<z.ZodString>;
@@ -390,6 +360,7 @@ export declare const SuspensionPayloadSchema: z.ZodObject<{
390
360
  created_at: z.ZodString;
391
361
  omicsType: z.ZodOptional<z.ZodString>;
392
362
  omicsSubtype: z.ZodOptional<z.ZodString>;
363
+ request: z.ZodOptional<z.ZodString>;
393
364
  }, z.core.$strip>;
394
365
  }, z.core.$strip>, z.ZodObject<{
395
366
  type: z.ZodLiteral<"json">;