@citeark/agent 0.3.20

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 (347) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +128 -0
  3. package/data/dataset-source-registry.v1.json +300 -0
  4. package/dist/arkgraph/boot.js +6 -0
  5. package/dist/arkgraph/index.html +1 -0
  6. package/dist/arkgraph/viewer.css +1 -0
  7. package/dist/arkgraph/viewer.en.css +1 -0
  8. package/dist/arkgraph/viewer.en.js +49 -0
  9. package/dist/arkgraph/viewer.en.js.LEGAL.txt +56 -0
  10. package/dist/arkgraph/viewer.js +49 -0
  11. package/dist/arkgraph/viewer.js.LEGAL.txt +56 -0
  12. package/docker/claude-code/Dockerfile +97 -0
  13. package/docker/claude-code/codex-pro-relay.mjs +466 -0
  14. package/docker/claude-code/runtime-contract-check.mjs +79 -0
  15. package/docs/arkgraph-reading.md +79 -0
  16. package/docs/configuration.md +100 -0
  17. package/docs/integration.md +92 -0
  18. package/docs/maturity-plan.md +27 -0
  19. package/docs/npm-release.md +44 -0
  20. package/docs/paper-reading.md +40 -0
  21. package/docs/research-plan-granularity.md +27 -0
  22. package/docs/terminal.md +49 -0
  23. package/examples/toy-evaluation/compile-task.json +27 -0
  24. package/examples/toy-evaluation/paper.md +5 -0
  25. package/examples/toy-evaluation/repository/README.md +9 -0
  26. package/examples/toy-evaluation/repository/checkpoint.json +4 -0
  27. package/examples/toy-evaluation/repository/evaluate.py +17 -0
  28. package/examples/toy-evaluation/task.json +81 -0
  29. package/package.json +59 -0
  30. package/prompts/compile-research.md +58 -0
  31. package/prompts/execute-contract.md +72 -0
  32. package/prompts/execute-workspace-simple.md +51 -0
  33. package/prompts/execute-workspace.md +34 -0
  34. package/prompts/prepare-reproduction.md +82 -0
  35. package/prompts/repair-research.md +45 -0
  36. package/protocol/CAP.md +129 -0
  37. package/protocol/LICENSE +12 -0
  38. package/protocol/MAPPINGS.md +72 -0
  39. package/protocol/README.md +38 -0
  40. package/protocol/conformance-v2.0-alpha.1.json +36 -0
  41. package/protocol/examples/arkgraph/checkpoint-evaluation.json +309 -0
  42. package/protocol/examples/arkgraph/fixtures.mjs +49 -0
  43. package/protocol/examples/arkgraph/paper-free.json +291 -0
  44. package/protocol/examples/arkgraph/partial-failure.json +344 -0
  45. package/protocol/examples/arkgraph/training-evaluation.json +443 -0
  46. package/protocol/profiles/agent-trace.md +16 -0
  47. package/protocol/profiles/computational-run.md +16 -0
  48. package/protocol/profiles/core.md +15 -0
  49. package/protocol/profiles/public-bundle.md +18 -0
  50. package/protocol/profiles/reproduction.md +29 -0
  51. package/protocol/profiles/research-compilation.md +44 -0
  52. package/protocol/profiles/research-plan.md +39 -0
  53. package/protocol/profiles/restricted-evidence.md +15 -0
  54. package/runtime/bootstrap-autodl-runtime.sh +314 -0
  55. package/runtime/create-runtime-venv.sh +41 -0
  56. package/runtime/install-local-cpu-runtime.sh +23 -0
  57. package/runtime/install-scientific-runtime.sh +153 -0
  58. package/runtime/mineru/parse.py +62 -0
  59. package/runtime/mineru/requirements.txt +4 -0
  60. package/runtime/requirements-baseline.txt +38 -0
  61. package/schemas/cap/v2/activity.schema.json +47 -0
  62. package/schemas/cap/v2/agent.schema.json +32 -0
  63. package/schemas/cap/v2/assertion.schema.json +110 -0
  64. package/schemas/cap/v2/descriptor.schema.json +243 -0
  65. package/schemas/cap/v2/entity.schema.json +64 -0
  66. package/schemas/cap/v2/manifest.schema.json +67 -0
  67. package/schemas/cap/v2/relation.schema.json +82 -0
  68. package/schemas/compute-catalog.schema.json +63 -0
  69. package/schemas/compute-decision.schema.json +27 -0
  70. package/schemas/execution-contract.schema.json +1024 -0
  71. package/schemas/research-card.schema.json +30 -0
  72. package/schemas/research-inventory-draft.schema.json +366 -0
  73. package/schemas/research.schema.json +1044 -0
  74. package/schemas/result.schema.json +173 -0
  75. package/schemas/verification-policy.schema.json +47 -0
  76. package/schemas/verified-conclusion.schema.json +58 -0
  77. package/schemas/workspace-summary.schema.json +24 -0
  78. package/scripts/build-arkgraph-view.mjs +12 -0
  79. package/scripts/check-execution-feasibility.mjs +24 -0
  80. package/scripts/check-syntax.mjs +15 -0
  81. package/scripts/deterministic-asset-preparation.py +438 -0
  82. package/scripts/package-cap.mjs +23 -0
  83. package/scripts/package-local-agent.mjs +23 -0
  84. package/scripts/preview-arkgraph.mjs +25 -0
  85. package/scripts/replay-research-compiler-candidate.mjs +134 -0
  86. package/scripts/review-compiler-sources.mjs +44 -0
  87. package/scripts/run-asset-preparation.sh +17 -0
  88. package/scripts/run-research-plan.mjs +98 -0
  89. package/scripts/validate-asset-preparation.py +290 -0
  90. package/scripts/verify-local-runtime.mjs +57 -0
  91. package/scripts/verify-npm-package.mjs +57 -0
  92. package/src/adapters/paper2agent.mjs +107 -0
  93. package/src/assets/cache.mjs +159 -0
  94. package/src/assets/compute.mjs +98 -0
  95. package/src/assets/executor.mjs +145 -0
  96. package/src/assets/lifecycle.mjs +213 -0
  97. package/src/assets/manifest.mjs +242 -0
  98. package/src/assets/opportunistic-preparation.mjs +81 -0
  99. package/src/assets/plan.mjs +411 -0
  100. package/src/assets/prompts.mjs +29 -0
  101. package/src/assets/public-asset-probe.mjs +525 -0
  102. package/src/assets/qualification.mjs +119 -0
  103. package/src/assets/readiness.mjs +130 -0
  104. package/src/assets/reproduction-admission.mjs +355 -0
  105. package/src/assets/requirements.mjs +152 -0
  106. package/src/assets/source-grounding.mjs +341 -0
  107. package/src/assets/source-policy.mjs +118 -0
  108. package/src/autodl/client.mjs +260 -0
  109. package/src/autodl/ssh.mjs +380 -0
  110. package/src/autodl/tools.mjs +129 -0
  111. package/src/cap/redaction.mjs +38 -0
  112. package/src/cap/v2/archive.mjs +152 -0
  113. package/src/cap/v2/attestation.mjs +204 -0
  114. package/src/cap/v2/canonical-json.mjs +114 -0
  115. package/src/cap/v2/compilation-artifact.mjs +240 -0
  116. package/src/cap/v2/core.mjs +282 -0
  117. package/src/cap/v2/measurement-assessment-records.mjs +23 -0
  118. package/src/cap/v2/pipeline-artifact.mjs +922 -0
  119. package/src/cap/v2/read.mjs +41 -0
  120. package/src/cap/v2/reassessment-artifact.mjs +383 -0
  121. package/src/cap/v2/research-artifact.mjs +231 -0
  122. package/src/cap/v2/research-map-records.mjs +46 -0
  123. package/src/cap/v2/research-object-records.mjs +163 -0
  124. package/src/cap/v2/research-records.mjs +187 -0
  125. package/src/cap/v2/verify.mjs +642 -0
  126. package/src/cli.mjs +1146 -0
  127. package/src/compute/autodl-pro-compiler.mjs +347 -0
  128. package/src/compute/autodl-pro-executor.mjs +459 -0
  129. package/src/compute/autodl-pro-job.mjs +843 -0
  130. package/src/compute/autodl-pro-network.mjs +295 -0
  131. package/src/compute/autodl-pro-remote.mjs +810 -0
  132. package/src/compute/autodl-pro-staging.mjs +117 -0
  133. package/src/compute/campaign.mjs +110 -0
  134. package/src/compute/catalog.mjs +123 -0
  135. package/src/compute/checkpoint-protocol.mjs +154 -0
  136. package/src/compute/codex-account-lock.mjs +111 -0
  137. package/src/compute/codex-account-session.mjs +107 -0
  138. package/src/compute/compiler-profile.mjs +38 -0
  139. package/src/compute/compiler-router.mjs +23 -0
  140. package/src/compute/coordinator-recovery.mjs +210 -0
  141. package/src/compute/executor-router.mjs +29 -0
  142. package/src/compute/gcp-batch-compiler.mjs +685 -0
  143. package/src/compute/gcp-batch-executor.mjs +1215 -0
  144. package/src/compute/gcp-batch-failure.mjs +92 -0
  145. package/src/compute/gcp-batch-job.mjs +527 -0
  146. package/src/compute/gcp-batch-lifecycle.mjs +81 -0
  147. package/src/compute/gcp-checkpoint-worker.mjs +1633 -0
  148. package/src/compute/local-codex-compiler.mjs +52 -0
  149. package/src/compute/measurement-hardware.mjs +128 -0
  150. package/src/compute/remote-attempt.mjs +226 -0
  151. package/src/compute/requirements.mjs +124 -0
  152. package/src/compute/research-phases.mjs +48 -0
  153. package/src/compute/scheduler.mjs +452 -0
  154. package/src/compute/shared-workloads.mjs +26 -0
  155. package/src/compute/stage-archive.mjs +79 -0
  156. package/src/contracts/campaign-contract.mjs +52 -0
  157. package/src/contracts/execution-contract.mjs +819 -0
  158. package/src/contracts/execution-mode.mjs +19 -0
  159. package/src/contracts/execution-timeouts.mjs +45 -0
  160. package/src/contracts/execution-workload.mjs +68 -0
  161. package/src/contracts/preflight-schema.mjs +25 -0
  162. package/src/contracts/public-contract.mjs +63 -0
  163. package/src/contracts/subject-tags.mjs +31 -0
  164. package/src/dashboard/data.mjs +898 -0
  165. package/src/dashboard/server.mjs +79 -0
  166. package/src/dashboard/static/dashboard.css +366 -0
  167. package/src/dashboard/static/dashboard.js +560 -0
  168. package/src/dashboard/static/index.html +85 -0
  169. package/src/deployment/community-policy.mjs +9 -0
  170. package/src/deployment/environment.mjs +112 -0
  171. package/src/deployment/guided.mjs +98 -0
  172. package/src/deployment/handoff.mjs +102 -0
  173. package/src/deployment/local-contract.mjs +31 -0
  174. package/src/deployment/local.mjs +100 -0
  175. package/src/deployment/prepare.mjs +46 -0
  176. package/src/deployment/recipe.mjs +108 -0
  177. package/src/deployment/supplement.mjs +51 -0
  178. package/src/deployment/terminal.mjs +43 -0
  179. package/src/diagnosis/renderer.mjs +75 -0
  180. package/src/diagnosis/target-failure.mjs +46 -0
  181. package/src/evidence/parser-registry.mjs +54 -0
  182. package/src/evidence/parsers/fasttext-classification.mjs +82 -0
  183. package/src/evidence/parsers/json-scalar.mjs +96 -0
  184. package/src/evidence/parsers/simcse-senteval.mjs +104 -0
  185. package/src/evidence/parsers/starspace-classification.mjs +78 -0
  186. package/src/evidence/registry.mjs +147 -0
  187. package/src/execution/runner-audit.mjs +473 -0
  188. package/src/gcp/auth.mjs +106 -0
  189. package/src/gcp/batch-client.mjs +120 -0
  190. package/src/gcp/resource-discovery.mjs +177 -0
  191. package/src/gcp/rest.mjs +82 -0
  192. package/src/gcp/secret-manager.mjs +34 -0
  193. package/src/gcp/signed-url.mjs +133 -0
  194. package/src/gcp/storage.mjs +220 -0
  195. package/src/graph/command.mjs +41 -0
  196. package/src/graph/execution.mjs +97 -0
  197. package/src/graph/model.mjs +37 -0
  198. package/src/graph/presentation.mjs +110 -0
  199. package/src/graph/query.mjs +159 -0
  200. package/src/graph/research-relations.mjs +69 -0
  201. package/src/graph/source-page.mjs +12 -0
  202. package/src/graph/source-preview.mjs +34 -0
  203. package/src/graph/validate.mjs +76 -0
  204. package/src/job.mjs +496 -0
  205. package/src/network/autodl-routing-proxy.mjs +462 -0
  206. package/src/network/egress-proxy.mjs +158 -0
  207. package/src/observability/event-contract.mjs +230 -0
  208. package/src/observability/pipeline-monitor.mjs +166 -0
  209. package/src/pipeline/orchestrator.mjs +1281 -0
  210. package/src/pipeline/recovery-error.mjs +11 -0
  211. package/src/pipeline/replay.mjs +304 -0
  212. package/src/pipeline/shared-execution.mjs +115 -0
  213. package/src/pipeline/stage-checkpoint.mjs +86 -0
  214. package/src/pipeline/stage-recovery.mjs +101 -0
  215. package/src/pipeline/targets.mjs +110 -0
  216. package/src/process.mjs +143 -0
  217. package/src/protocol.mjs +312 -0
  218. package/src/provider/codex-account.mjs +44 -0
  219. package/src/provider/codex-completion.mjs +49 -0
  220. package/src/provider/completion.mjs +292 -0
  221. package/src/provider/model-client.mjs +44 -0
  222. package/src/provider/model-route.mjs +29 -0
  223. package/src/provider/openrouter-readiness.mjs +189 -0
  224. package/src/provider/reader-bridge.mjs +35 -0
  225. package/src/provider/relay.mjs +263 -0
  226. package/src/provider/runtime-auth.mjs +40 -0
  227. package/src/public/cap.d.mts +90 -0
  228. package/src/public/cap.mjs +12 -0
  229. package/src/public/contracts.d.mts +2 -0
  230. package/src/public/host.mjs +171 -0
  231. package/src/public/operations.d.mts +11 -0
  232. package/src/public/presentation.d.mts +4 -0
  233. package/src/records/views.mjs +26 -0
  234. package/src/remote/command.mjs +178 -0
  235. package/src/remote/ssh.mjs +59 -0
  236. package/src/repository-origin.mjs +81 -0
  237. package/src/reproduction/evidence-feedback.mjs +96 -0
  238. package/src/reproduction/incomplete-initialization.mjs +25 -0
  239. package/src/reproduction/lifecycle.mjs +253 -0
  240. package/src/reproduction/plan.mjs +132 -0
  241. package/src/reproduction/prompts.mjs +70 -0
  242. package/src/reproduction/runner.mjs +188 -0
  243. package/src/reproduction/summary.mjs +130 -0
  244. package/src/reproduction/workspace-mode.mjs +7 -0
  245. package/src/research/automatic-admission.mjs +156 -0
  246. package/src/research/compiler-coverage.mjs +85 -0
  247. package/src/research/compiler-failure.mjs +24 -0
  248. package/src/research/compiler-normalization-guards.mjs +112 -0
  249. package/src/research/compiler-repair.mjs +3 -0
  250. package/src/research/compiler.mjs +853 -0
  251. package/src/research/continuation-selection.mjs +26 -0
  252. package/src/research/execution-graph-context.mjs +43 -0
  253. package/src/research/experiment-importance.mjs +15 -0
  254. package/src/research/inventory-handoff.mjs +104 -0
  255. package/src/research/inventory-revisions.mjs +32 -0
  256. package/src/research/mineru-local.mjs +73 -0
  257. package/src/research/paper-command.mjs +19 -0
  258. package/src/research/paper-markdown.mjs +180 -0
  259. package/src/research/paper-source-map.mjs +69 -0
  260. package/src/research/planning-policy.mjs +88 -0
  261. package/src/research/reference-materials.mjs +11 -0
  262. package/src/research/reproduction-scope.mjs +30 -0
  263. package/src/research/research-map.mjs +94 -0
  264. package/src/research/research-objects.mjs +88 -0
  265. package/src/research/source-discovery.mjs +646 -0
  266. package/src/research/source-observations.mjs +75 -0
  267. package/src/research/source-review-cli-mcp.mjs +26 -0
  268. package/src/research/source-review-input.mjs +209 -0
  269. package/src/research/source-review-local-codex.mjs +36 -0
  270. package/src/research/source-review-model.mjs +70 -0
  271. package/src/research/source-review.mjs +173 -0
  272. package/src/research/structure.mjs +3163 -0
  273. package/src/research-card/renderer.mjs +277 -0
  274. package/src/research-card/verified-conclusion.mjs +143 -0
  275. package/src/results/output-registry.mjs +183 -0
  276. package/src/runtime/claude-code.mjs +52 -0
  277. package/src/runtime/codex-capacity-retry.mjs +87 -0
  278. package/src/runtime/codex.mjs +64 -0
  279. package/src/runtime/config.mjs +157 -0
  280. package/src/runtime/final-output.mjs +40 -0
  281. package/src/runtime/index.mjs +21 -0
  282. package/src/runtime/local-codex.mjs +74 -0
  283. package/src/runtime/opencode.mjs +95 -0
  284. package/src/runtime/prompt.mjs +13 -0
  285. package/src/sandbox/docker.mjs +363 -0
  286. package/src/settings/command.mjs +297 -0
  287. package/src/settings/store.mjs +119 -0
  288. package/src/telemetry/pricing.mjs +68 -0
  289. package/src/telemetry/usage.mjs +265 -0
  290. package/src/terminal/events.mjs +97 -0
  291. package/src/terminal/input.mjs +40 -0
  292. package/src/terminal/plain.mjs +40 -0
  293. package/src/terminal/remote-stream.mjs +22 -0
  294. package/src/terminal/screen.mjs +214 -0
  295. package/src/terminal/transcript.mjs +69 -0
  296. package/src/util.mjs +107 -0
  297. package/src/verification/ai-assessor.mjs +534 -0
  298. package/src/verification/claim-evaluator.mjs +242 -0
  299. package/src/verification/evidence-context.mjs +165 -0
  300. package/src/verification/evidence-reader.mjs +95 -0
  301. package/src/verification/integrity.mjs +570 -0
  302. package/src/verification/tolerance.mjs +32 -0
  303. package/src/workloads/cpu-research-preparation.mjs +56 -0
  304. package/src/workloads/definition.mjs +74 -0
  305. package/src/workloads/phase-aware-reproduction.mjs +46 -0
  306. package/src/workloads/reproduction.mjs +85 -0
  307. package/src/workspace/command.mjs +242 -0
  308. package/src/workspace/control.mjs +49 -0
  309. package/src/workspace/entry.mjs +28 -0
  310. package/src/workspace/input.mjs +93 -0
  311. package/src/workspace/interactive.mjs +94 -0
  312. package/src/workspace/jobs.mjs +418 -0
  313. package/src/workspace/session.mjs +97 -0
  314. package/src/workspace/worker.mjs +137 -0
  315. package/ui/arkgraph/ambient-motion.mjs +10 -0
  316. package/ui/arkgraph/app.jsx +153 -0
  317. package/ui/arkgraph/boot.js +6 -0
  318. package/ui/arkgraph/camera-motion.mjs +20 -0
  319. package/ui/arkgraph/context-reveal.mjs +39 -0
  320. package/ui/arkgraph/details.css +3 -0
  321. package/ui/arkgraph/entry.jsx +28 -0
  322. package/ui/arkgraph/experiment-curves.mjs +17 -0
  323. package/ui/arkgraph/experiment-selection.mjs +15 -0
  324. package/ui/arkgraph/experiment-style.css +26 -0
  325. package/ui/arkgraph/experiment-ui.jsx +32 -0
  326. package/ui/arkgraph/frame.html +1 -0
  327. package/ui/arkgraph/graph-gestures.mjs +62 -0
  328. package/ui/arkgraph/label-layout.mjs +57 -0
  329. package/ui/arkgraph/locales/en.json +229 -0
  330. package/ui/arkgraph/locales/source-types.json +15 -0
  331. package/ui/arkgraph/localization-build.mjs +27 -0
  332. package/ui/arkgraph/material-build.mjs +23 -0
  333. package/ui/arkgraph/material-colors.mjs +39 -0
  334. package/ui/arkgraph/material-style.css +15 -0
  335. package/ui/arkgraph/open-graph.jsx +326 -0
  336. package/ui/arkgraph/outline.jsx +49 -0
  337. package/ui/arkgraph/package-lock.json +888 -0
  338. package/ui/arkgraph/package.json +17 -0
  339. package/ui/arkgraph/reading-layout.mjs +130 -0
  340. package/ui/arkgraph/reading-presentation.mjs +73 -0
  341. package/ui/arkgraph/record-detail.css +51 -0
  342. package/ui/arkgraph/record-details.jsx +29 -0
  343. package/ui/arkgraph/research-types.mjs +31 -0
  344. package/ui/arkgraph/selection-mark.jsx +6 -0
  345. package/ui/arkgraph/soft-spine.mjs +26 -0
  346. package/ui/arkgraph/steering-style.css +187 -0
  347. package/ui/arkgraph/style.css +272 -0
@@ -0,0 +1,213 @@
1
+ import { cp, mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ import { buildRunnerAudit } from "../execution/runner-audit.mjs";
6
+ import { ensureFinalWorkspaceCapture, updateRunState } from "../job.mjs";
7
+ import { readAgentUsage } from "../telemetry/usage.mjs";
8
+ import { CiteArkError, pathExists, readJson, writeJson } from "../util.mjs";
9
+ import { defineAgentWorkload } from "../workloads/definition.mjs";
10
+ import { validateAssetPreparationManifest } from "./manifest.mjs";
11
+ import { initialAssetPreparationPrompt, resumeAssetPreparationPrompt } from "./prompts.mjs";
12
+
13
+ const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
14
+
15
+ export function createAssetPreparationWorkload(plan) {
16
+ return defineAgentWorkload({
17
+ workload: "asset-preparation",
18
+ agentBoundary: {
19
+ mode: "bounded",
20
+ decisionRights: [
21
+ "select_files_within_the_immutable_asset_plan",
22
+ "install_or_replace_task_local_dependencies",
23
+ "resume_and_verify_declared_public_transports",
24
+ "debug_asset_loaders_and_environment_checks",
25
+ ],
26
+ immutableConstraints: [
27
+ "asset_identity_and_required_file_scope",
28
+ "no_scientific_experiment_execution",
29
+ "allocated_compute_time_and_storage_ceiling",
30
+ "manifest_and_audit_protocol",
31
+ ],
32
+ },
33
+ validateScientificComputeDecision: false,
34
+ controllerValidationRetries: 0,
35
+ completionRelativePath: "output/asset-preparation-manifest.json",
36
+ completionHasEvidence: false,
37
+ completionValidatorRelativePath: "input/validate-asset-preparation.py",
38
+ completionSuccessJq: '.kind == "citeark.asset-preparation-manifest" and (.manifestDigest | startswith("sha256:"))',
39
+ preserveRebuildableCache: true,
40
+ finalCheckpointKind: "full",
41
+ finalCheckpointReason: "asset-preparation",
42
+ recoverFinalMessage: false,
43
+ async prepare(bundle) {
44
+ await writeJson(path.join(bundle.directories.input, "asset-preparation-plan.json"), plan);
45
+ await Promise.all([
46
+ cp(
47
+ path.join(PACKAGE_ROOT, "scripts", "validate-asset-preparation.py"),
48
+ path.join(bundle.directories.input, "validate-asset-preparation.py"),
49
+ ),
50
+ cp(
51
+ path.join(PACKAGE_ROOT, "scripts", "deterministic-asset-preparation.py"),
52
+ path.join(bundle.directories.input, "deterministic-asset-preparation.py"),
53
+ ),
54
+ cp(
55
+ path.join(PACKAGE_ROOT, "scripts", "run-asset-preparation.sh"),
56
+ path.join(bundle.directories.input, "run-asset-preparation.sh"),
57
+ ),
58
+ ]);
59
+ await updateRunState(bundle, {
60
+ workload: "asset-preparation",
61
+ assetPreparation: { planDigest: plan.planDigest, status: "prepared" },
62
+ });
63
+ },
64
+ wrapInvocation({ invocation }) {
65
+ return {
66
+ command: "/bin/bash",
67
+ args: [
68
+ "/job/input/run-asset-preparation.sh",
69
+ "/job/input/deterministic-asset-preparation.py",
70
+ invocation.command,
71
+ ...(Array.isArray(invocation.args) ? invocation.args : []),
72
+ ],
73
+ prompt: invocation.prompt,
74
+ promptArgument: invocation.promptArgument,
75
+ };
76
+ },
77
+ instructions: async () => [
78
+ "You are CiteArk's dedicated asset-preparation Agent.",
79
+ "Only prepare and verify the immutable asset plan. Do not execute the full scientific experiment and do not change its scope.",
80
+ "Preserve complete operational evidence. The runner independently validates the manifest before it can be reused.",
81
+ ].join("\n"),
82
+ prompt({ bundle, attempt, validation }) {
83
+ if (attempt === 1) return initialAssetPreparationPrompt(bundle);
84
+ return [
85
+ resumeAssetPreparationPrompt(bundle),
86
+ "The previous manifest failed deterministic validation:",
87
+ ...validation.issues.map((issue) => `- ${issue}`),
88
+ "Repair only the failed acquisition, environment or evidence records; retain valid downloads and logs.",
89
+ ].join("\n");
90
+ },
91
+ resumePrompt({ bundle }) {
92
+ return resumeAssetPreparationPrompt(bundle);
93
+ },
94
+ async validate({ bundle, completionPath }) {
95
+ if (!(await pathExists(completionPath))) {
96
+ return { result: null, issues: ["缺少资产准备清单"], protocolVerification: null };
97
+ }
98
+ try {
99
+ const manifest = await readJson(completionPath);
100
+ return {
101
+ result: manifest,
102
+ issues: validateAssetPreparationManifest(plan, manifest),
103
+ protocolVerification: null,
104
+ };
105
+ } catch (error) {
106
+ return {
107
+ result: null,
108
+ issues: [error instanceof Error ? error.message : String(error)],
109
+ protocolVerification: null,
110
+ };
111
+ }
112
+ },
113
+ isSucceeded(result, issues) {
114
+ return issues.length === 0 && result?.kind === "citeark.asset-preparation-manifest";
115
+ },
116
+ async finalize({
117
+ bundle,
118
+ validation,
119
+ attempts,
120
+ timedOut,
121
+ sandboxImageIdentity,
122
+ cloudExecution,
123
+ checkpoint,
124
+ }) {
125
+ await ensureFinalWorkspaceCapture(bundle);
126
+ const usage = await readAgentUsage(path.join(bundle.directories.execution, "trace.jsonl"), {
127
+ runtimeHome: bundle.directories.runtimeHome,
128
+ model: bundle.runtimeAgent.model,
129
+ });
130
+ const valid = validation.issues.length === 0 && !timedOut;
131
+ await updateRunState(bundle, {
132
+ status: valid ? "completed" : timedOut ? "timed_out" : "invalid_result",
133
+ finishedAt: new Date().toISOString(),
134
+ attempts,
135
+ validationIssues: validation.issues,
136
+ sandboxImageIdentity,
137
+ cloudExecution,
138
+ usage,
139
+ assetPreparation: {
140
+ planDigest: plan.planDigest,
141
+ manifestDigest: validation.result?.manifestDigest ?? null,
142
+ status: valid ? "completed" : "failed",
143
+ checkpoint,
144
+ },
145
+ });
146
+ const runnerAudit = await buildRunnerAudit({
147
+ runDirectory: bundle.directories.run,
148
+ runtime: bundle.runtimeAgent.runtime,
149
+ sandbox: "gcp-batch",
150
+ });
151
+ if (!valid) {
152
+ const error = new CiteArkError(`资产准备未通过确定性校验:\n- ${validation.issues.join("\n- ")}`, {
153
+ exitCode: 2,
154
+ retryable: !timedOut,
155
+ failureCode: timedOut
156
+ ? "asset_preparation.runtime_budget_exhausted"
157
+ : "asset_preparation.manifest_invalid",
158
+ failureCategory: timedOut ? "timeout" : "preflight",
159
+ });
160
+ if (checkpoint) error.recoveryCheckpoint = checkpoint;
161
+ throw error;
162
+ }
163
+ if (!checkpoint || checkpoint.kind !== "full") {
164
+ throw new CiteArkError("资产准备完成但没有留下可供 GPU 复用的完整检查点", {
165
+ retryable: true,
166
+ failureCode: "asset_preparation.checkpoint_missing",
167
+ failureCategory: "publication",
168
+ });
169
+ }
170
+ return {
171
+ dryRun: false,
172
+ bundle,
173
+ manifest: validation.result,
174
+ validation,
175
+ attempts,
176
+ runnerAudit,
177
+ checkpoint,
178
+ preparationMode: validation.result?.preparationMode === "deterministic"
179
+ ? "deterministic"
180
+ : "agent",
181
+ };
182
+ },
183
+ });
184
+ }
185
+
186
+ export async function recordAssetCacheHit({ runsDirectory, runId, plan, manifest, cache }) {
187
+ const runDirectory = path.resolve(runsDirectory, runId);
188
+ await Promise.all([
189
+ mkdir(path.join(runDirectory, "input"), { recursive: true }),
190
+ mkdir(path.join(runDirectory, "output"), { recursive: true }),
191
+ mkdir(path.join(runDirectory, "execution"), { recursive: true }),
192
+ ]);
193
+ await Promise.all([
194
+ writeJson(path.join(runDirectory, "input", "asset-preparation-plan.json"), plan),
195
+ writeJson(path.join(runDirectory, "output", "asset-preparation-manifest.json"), manifest),
196
+ writeJson(path.join(runDirectory, "execution", "asset-cache.json"), cache),
197
+ writeJson(path.join(runDirectory, "run.json"), {
198
+ schemaVersion: "0.1",
199
+ runId,
200
+ workload: "asset-preparation",
201
+ status: "completed",
202
+ cacheHit: true,
203
+ createdAt: new Date().toISOString(),
204
+ updatedAt: new Date().toISOString(),
205
+ assetPreparation: {
206
+ planDigest: plan.planDigest,
207
+ manifestDigest: manifest.manifestDigest,
208
+ checkpoint: cache.checkpoint,
209
+ },
210
+ }),
211
+ ]);
212
+ return { run: runDirectory };
213
+ }
@@ -0,0 +1,242 @@
1
+ import { sha256Value } from "../util.mjs";
2
+ import { validateSelectedSource } from "./source-policy.mjs";
3
+
4
+ export function validateAssetPreparationManifest(plan, manifest) {
5
+ const issues = [];
6
+ if (manifest?.schemaVersion !== "0.1") issues.push("manifest.schemaVersion 必须是 0.1");
7
+ if (manifest?.kind !== "citeark.asset-preparation-manifest") {
8
+ issues.push("manifest.kind 无效");
9
+ }
10
+ if (manifest?.planDigest !== plan?.planDigest) issues.push("manifest 与资产计划摘要不一致");
11
+ const records = Array.isArray(manifest?.assets) ? manifest.assets : [];
12
+ const byId = new Map(records.map((record) => [record?.assetId, record]));
13
+ if (byId.size !== records.length) issues.push("资产清单包含重复 assetId");
14
+ const plannedAssetIds = new Set((plan?.assets ?? []).map((asset) => asset.id));
15
+ for (const record of records) {
16
+ if (!plannedAssetIds.has(record?.assetId)) issues.push(`资产清单包含计划外记录:${record?.assetId ?? "unknown"}`);
17
+ }
18
+ for (const asset of Array.isArray(plan?.assets) ? plan.assets : []) {
19
+ const record = byId.get(asset.id);
20
+ if (!record) {
21
+ issues.push(`缺少资产准备记录:${asset.id}`);
22
+ continue;
23
+ }
24
+ if (record.localPath !== asset.localPath) {
25
+ issues.push(`资产 ${asset.id} 的本地绑定路径发生变化`);
26
+ }
27
+ validateAssetIdentity(asset, record, issues);
28
+ const accepted = asset.decision.action === "metadata"
29
+ ? new Set(["metadata_verified", "prepared"])
30
+ : asset.decision.action === "stream"
31
+ ? new Set(["stream_ready", "prepared"])
32
+ : asset.decision.action === "inspect" && asset.supportsStreaming
33
+ ? new Set(["prepared", "stream_ready"])
34
+ : asset.decision.action === "blocked"
35
+ ? new Set(["blocked"])
36
+ : new Set(["prepared"]);
37
+ if (!accepted.has(record.status)) {
38
+ issues.push(`资产 ${asset.id} 状态 ${record.status ?? "missing"} 不满足计划 ${asset.decision.action}`);
39
+ }
40
+ if (new Set(["prepared", "stream_ready"]).has(record.status)) {
41
+ validateAcquisitionRecord(asset, record.acquisition, issues, record.sourceLocator);
42
+ validatePreparedRecord(asset, record, issues);
43
+ }
44
+ }
45
+ const downloadedBytes = records.reduce(
46
+ (sum, record) => sum + (
47
+ Number.isSafeInteger(record?.acquisition?.downloadBytes)
48
+ ? record.acquisition.downloadBytes
49
+ : 0
50
+ ),
51
+ 0,
52
+ );
53
+ if (downloadedBytes > (plan?.limits?.totalDownloadBytes ?? Number.POSITIVE_INFINITY)) {
54
+ issues.push("资产准备总下载字节数超过任务批准上限");
55
+ }
56
+ const preparedBytes = records.reduce(
57
+ (sum, record) => sum + (Number.isSafeInteger(record?.totalBytes) ? record.totalBytes : 0),
58
+ 0,
59
+ );
60
+ if (preparedBytes > (plan?.limits?.totalExpandedBytes ?? Number.POSITIVE_INFINITY)) {
61
+ issues.push("资产准备总落盘字节数超过任务批准上限");
62
+ }
63
+ const checks = Array.isArray(manifest?.checks) ? manifest.checks : [];
64
+ const checksById = new Map(checks.map((record) => [record?.checkId, record]));
65
+ if (checksById.size !== checks.length) issues.push("资产清单包含重复 checkId");
66
+ const plannedCheckIds = new Set((plan?.checks ?? []).map((check) => check.id));
67
+ for (const record of checks) {
68
+ if (!plannedCheckIds.has(record?.checkId)) issues.push(`资产清单包含计划外检查:${record?.checkId ?? "unknown"}`);
69
+ }
70
+ for (const check of Array.isArray(plan?.checks) ? plan.checks : []) {
71
+ const record = checksById.get(check.id);
72
+ if (!record) {
73
+ issues.push(`缺少资产准备检查记录:${check.id}`);
74
+ continue;
75
+ }
76
+ if (record.kind !== check.kind) issues.push(`检查 ${check.id} 的类型发生变化`);
77
+ if (record.status !== "passed") issues.push(`检查 ${check.id} 未通过真实预检`);
78
+ if (!Array.isArray(record.commands) || record.commands.length === 0) {
79
+ issues.push(`检查 ${check.id} 没有记录实际命令`);
80
+ }
81
+ if (!Array.isArray(record.evidence) || record.evidence.length === 0) {
82
+ issues.push(`检查 ${check.id} 没有可核验输出`);
83
+ } else {
84
+ for (const evidence of record.evidence) validateEvidenceDescriptor(check.id, evidence, issues);
85
+ }
86
+ }
87
+ validateRuntimeEnvironment(manifest?.runtimeEnvironment, issues);
88
+ const body = { ...manifest };
89
+ delete body.manifestDigest;
90
+ const expected = `sha256:${sha256Value(body)}`;
91
+ if (manifest?.manifestDigest !== expected) issues.push("manifestDigest 与清单内容不一致");
92
+ return issues;
93
+ }
94
+
95
+ function validateAssetIdentity(asset, record, issues) {
96
+ if (record.identity !== asset.identity) issues.push(`资产 ${asset.id} 的科学身份不一致`);
97
+ if (asset.revision && record.revision !== asset.revision) {
98
+ issues.push(`资产 ${asset.id} 没有固定到计划 revision`);
99
+ }
100
+ const sources = new Set((asset.sourceLocators ?? []).map((item) => item.url));
101
+ if (sources.size && !sources.has(record.sourceLocator)) {
102
+ issues.push(`资产 ${asset.id} 的来源不在计划允许列表中`);
103
+ }
104
+ const verification = record.verification;
105
+ if (verification?.status !== "passed") {
106
+ issues.push(`资产 ${asset.id} 没有通过身份校验`);
107
+ return;
108
+ }
109
+ if (!Array.isArray(verification.commands) || verification.commands.length === 0) {
110
+ issues.push(`资产 ${asset.id} 没有记录身份校验命令`);
111
+ }
112
+ if (!Array.isArray(verification.evidence) || verification.evidence.length === 0) {
113
+ issues.push(`资产 ${asset.id} 没有身份校验证据`);
114
+ } else {
115
+ for (const evidence of verification.evidence) {
116
+ validateEvidenceDescriptor(`asset:${asset.id}`, evidence, issues);
117
+ }
118
+ }
119
+ }
120
+
121
+ function validateEvidenceDescriptor(checkId, value, issues) {
122
+ if (!safeRelativePath(String(value?.path ?? ""))) {
123
+ issues.push(`检查 ${checkId} 包含不安全证据路径`);
124
+ }
125
+ if (!Number.isSafeInteger(value?.bytes) || value.bytes < 0) {
126
+ issues.push(`检查 ${checkId} 的证据大小无效`);
127
+ }
128
+ if (!/^sha256:[0-9a-f]{64}$/.test(String(value?.digest))) {
129
+ issues.push(`检查 ${checkId} 的证据摘要无效`);
130
+ }
131
+ }
132
+
133
+ function validateAcquisitionRecord(asset, value, issues, sourceLocator) {
134
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
135
+ issues.push(`资产 ${asset.id} 缺少传输审计记录`);
136
+ return;
137
+ }
138
+ if (!Number.isSafeInteger(value.downloadBytes) || value.downloadBytes < 0) {
139
+ issues.push(`资产 ${asset.id} 的实际下载字节数无效`);
140
+ } else if (value.downloadBytes > asset.maximumDownloadBytes) {
141
+ issues.push(`资产 ${asset.id} 超过批准的下载上限`);
142
+ }
143
+ if (!Array.isArray(value.commands) || value.commands.length === 0) {
144
+ issues.push(`资产 ${asset.id} 没有记录实际传输命令`);
145
+ }
146
+ if (!Array.isArray(value.evidence) || value.evidence.length === 0) {
147
+ issues.push(`资产 ${asset.id} 没有传输证据`);
148
+ } else {
149
+ for (const evidence of value.evidence) {
150
+ validateEvidenceDescriptor(`acquisition:${asset.id}`, evidence, issues);
151
+ }
152
+ }
153
+ issues.push(...validateSelectedSource(asset, {
154
+ ...value,
155
+ sourceLocator,
156
+ }));
157
+ }
158
+
159
+ function validateRuntimeEnvironment(value, issues) {
160
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
161
+ issues.push("manifest 缺少任务隔离运行环境记录");
162
+ return;
163
+ }
164
+ if (value.path !== "/job/runtime-venv") {
165
+ issues.push("任务依赖环境必须绑定到 /job/runtime-venv");
166
+ }
167
+ if (typeof value.pythonVersion !== "string" || !value.pythonVersion.trim()) {
168
+ issues.push("任务依赖环境缺少 Python 版本");
169
+ }
170
+ if (!/^sha256:[0-9a-f]{64}$/.test(String(value.lockDigest))) {
171
+ issues.push("任务依赖环境缺少有效锁定摘要");
172
+ }
173
+ if (!/^sha256:[0-9a-f]{64}$/.test(String(value.packageInventoryDigest))) {
174
+ issues.push("任务依赖环境缺少包清单摘要");
175
+ }
176
+ }
177
+
178
+ export function finalizeAssetPreparationManifest(value) {
179
+ const body = {
180
+ schemaVersion: "0.1",
181
+ kind: "citeark.asset-preparation-manifest",
182
+ ...value,
183
+ };
184
+ delete body.manifestDigest;
185
+ return { ...body, manifestDigest: `sha256:${sha256Value(body)}` };
186
+ }
187
+
188
+ function validatePreparedRecord(asset, record, issues) {
189
+ if (!Array.isArray(record.files) || record.files.length === 0) {
190
+ issues.push(`已准备资产 ${asset.id} 没有文件清单`);
191
+ return;
192
+ }
193
+ let totalBytes = 0;
194
+ const paths = new Set();
195
+ for (const file of record.files) {
196
+ if (typeof file?.path !== "string" || !safeRelativePath(file.path)) {
197
+ issues.push(`资产 ${asset.id} 包含不安全文件路径`);
198
+ } else if (paths.has(file.path)) {
199
+ issues.push(`资产 ${asset.id} 文件路径重复:${file.path}`);
200
+ } else {
201
+ paths.add(file.path);
202
+ }
203
+ if (!Number.isSafeInteger(file?.bytes) || file.bytes < 0) {
204
+ issues.push(`资产 ${asset.id} 文件大小无效:${file?.path ?? "unknown"}`);
205
+ } else {
206
+ totalBytes += file.bytes;
207
+ }
208
+ if (!/^sha256:[0-9a-f]{64}$/.test(String(file?.digest))) {
209
+ issues.push(`资产 ${asset.id} 文件摘要无效:${file?.path ?? "unknown"}`);
210
+ }
211
+ }
212
+ if (record.totalBytes !== totalBytes) issues.push(`资产 ${asset.id} 总字节数与文件清单不一致`);
213
+ if (totalBytes > asset.maximumExpandedBytes) issues.push(`资产 ${asset.id} 超过批准的落盘上限`);
214
+ // requiredPaths is a backward-compatible prefetch selection hint. Older
215
+ // Research Plans may list alternative checkpoint formats as separate
216
+ // patterns (for example safetensors and pytorch_model.bin). A cache manifest
217
+ // records what was actually fetched; scientific format sufficiency is owned
218
+ // by the complete reproduction Agent and later evidence validation.
219
+ for (const pattern of asset.excludedPaths ?? []) {
220
+ if ([...paths].some((candidate) => globMatches(pattern, candidate))) {
221
+ issues.push(`资产 ${asset.id} 包含排除文件模式:${pattern}`);
222
+ }
223
+ }
224
+ }
225
+
226
+ function globMatches(pattern, value) {
227
+ const source = pattern
228
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
229
+ .replaceAll("**", "\u0000")
230
+ .replaceAll("*", "[^/]*")
231
+ .replaceAll("?", "[^/]")
232
+ .replaceAll("\u0000", ".*");
233
+ return new RegExp(`^${source}$`).test(value);
234
+ }
235
+
236
+ function safeRelativePath(value) {
237
+ return value.length > 0
238
+ && !value.startsWith("/")
239
+ && !value.includes("\\")
240
+ && !value.split("/").includes("..")
241
+ && !/[\u0000-\u001f]/.test(value);
242
+ }
@@ -0,0 +1,81 @@
1
+ import { assetPreparationPlanFailures } from "./plan.mjs";
2
+
3
+ /**
4
+ * Decide whether the cache optimizer is worth starting. This decision never
5
+ * changes the immutable experiment and never decides whether the autonomous
6
+ * reproduction Agent may run.
7
+ */
8
+ export function decideOpportunisticAssetPreparation({ plan, admission, executor }) {
9
+ const constraints = assetPreparationPlanFailures(plan).filter((failure) =>
10
+ String(failure?.reasonCode ?? "").startsWith("asset.")
11
+ && !String(failure.reasonCode).startsWith("asset.requirements_"));
12
+ if (constraints.length) {
13
+ return {
14
+ action: "defer",
15
+ reasonCode: constraints[0].reasonCode,
16
+ message: `预下载已跳过:${constraints.map((failure) => failure.message).join(";")}最终复现 Agent 仍可自行处理。`,
17
+ constraints,
18
+ };
19
+ }
20
+
21
+ const summary = admission?.summary ?? admission ?? {};
22
+ const unavailable = count(
23
+ summary.transportUnavailableAssetCount
24
+ ?? summary.terminalCount
25
+ ?? summary.blockedCount,
26
+ );
27
+ const retryable = count(
28
+ summary.transportRetryableAssetCount
29
+ ?? summary.retryableCount,
30
+ );
31
+ if (unavailable > 0 || retryable > 0) {
32
+ return {
33
+ action: "defer",
34
+ reasonCode: unavailable > 0
35
+ ? "asset.prefetch_transport_unavailable"
36
+ : "asset.prefetch_transport_transient",
37
+ message: unavailable > 0
38
+ ? "部分原始链接当前不可下载;已跳过预下载并把链接记录交给最终复现 Agent 自主处理。"
39
+ : "部分链接暂时异常;本次不创建新的 Worker 重试,已交给最终复现 Agent 自主处理。",
40
+ constraints: [],
41
+ };
42
+ }
43
+
44
+ if (executor !== "gcp-batch") {
45
+ return {
46
+ action: "defer",
47
+ reasonCode: "asset.prefetch_checkpoint_unsupported",
48
+ message: `执行器 ${executor} 不支持独立缓存检查点;资料由最终复现 Agent 在执行环境内准备。`,
49
+ constraints: [],
50
+ };
51
+ }
52
+
53
+ return {
54
+ action: "attempt",
55
+ reasonCode: "asset.prefetch_candidate",
56
+ message: "公开传输可用且预算允许,尝试在低成本环境中预先准备可复用缓存。",
57
+ constraints: [],
58
+ };
59
+ }
60
+
61
+ export function assetPreparationFallback(error) {
62
+ const raw = error instanceof Error ? error.message : String(error);
63
+ const detail = raw.replaceAll(/\s+/g, " ").trim().slice(0, 360);
64
+ return {
65
+ state: "deferred",
66
+ preparationMode: "reproduction-agent-fallback",
67
+ reasonCode: error?.failureCode ?? "asset.prefetch_failed",
68
+ message: detail
69
+ ? `资料预下载未完成(${detail})。这只是缓存优化失败;最终复现 Agent 将从原始链接继续。`
70
+ : "资料预下载未完成;最终复现 Agent 将从原始链接继续。",
71
+ };
72
+ }
73
+
74
+ export function mustAbortAfterAssetPreparationFailure(error) {
75
+ return error?.processingLeaseLost === true || error?.cancelled === true;
76
+ }
77
+
78
+ function count(value) {
79
+ const numeric = Number(value);
80
+ return Number.isSafeInteger(numeric) && numeric >= 0 ? numeric : 0;
81
+ }