@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,87 @@
1
+ import { spawn } from "node:child_process";
2
+ import { setTimeout as sleep } from "node:timers/promises";
3
+ import { pathToFileURL } from "node:url";
4
+
5
+ const CONTINUE_PROMPT = "Continue only the unfinished work in this session after a temporary model-capacity error. Preserve completed work, the original task, and its resource and evidence requirements.";
6
+
7
+ export function resumeCapacityArguments(args, threadId) {
8
+ const resumed = [...args];
9
+ const index = resumed.indexOf("exec");
10
+ if (index < 0 || !threadId) return resumed;
11
+ if (resumed[index + 1] === "resume") {
12
+ const last = resumed.indexOf("--last", index + 2);
13
+ if (last >= 0) resumed.splice(last, 1);
14
+ else resumed.splice(index + 2, 1);
15
+ resumed.splice(index + 2, 0, threadId);
16
+ } else resumed.splice(index + 1, 0, "resume", threadId);
17
+ resumed[resumed.length - 1] = CONTINUE_PROMPT;
18
+ return resumed;
19
+ }
20
+
21
+ // This supervisor stays in the existing VM, UID, account lock and runtime
22
+ // deadline. Only an explicit terminal capacity error permits another CLI turn.
23
+ export async function runCodexWithCapacityRetry({ args, command = "codex", commandPrefix = [],
24
+ retryDelayMs = 10_000, maxRetries = 30, stdout = process.stdout, stderr = process.stderr,
25
+ signal, wait = sleep }) {
26
+ if (!Number.isInteger(retryDelayMs) || retryDelayMs < 0 || retryDelayMs > 60_000
27
+ || !Number.isInteger(maxRetries) || maxRetries < 0 || maxRetries > 30) {
28
+ throw new Error("Invalid Codex capacity recovery limits");
29
+ }
30
+ let currentArgs = [...args], threadId = null;
31
+ const event = (type, details) => stdout.write(`${JSON.stringify({ type, ...details, timestamp: new Date().toISOString() })}\n`);
32
+ for (let retries = 0; ; retries++) {
33
+ if (signal?.aborted) return 143;
34
+ let pending = "", capacityFailure = false;
35
+ const observe = (line) => {
36
+ let entry;
37
+ try { entry = JSON.parse(line); } catch { return; }
38
+ if (entry.type === "thread.started" && typeof entry.thread_id === "string") threadId = entry.thread_id;
39
+ if (entry.type === "turn.failed") {
40
+ capacityFailure = /^Selected model is at capacity\. Please try a different model\.?$/i.test(entry.error?.message ?? "");
41
+ }
42
+ };
43
+ const child = spawn(command, [...commandPrefix, ...currentArgs], { stdio: ["ignore", "pipe", "pipe"] });
44
+ child.stdout.pipe(stdout, { end: false });
45
+ child.stderr.pipe(stderr, { end: false });
46
+ child.stdout.on("data", chunk => {
47
+ pending += chunk.toString();
48
+ let newline;
49
+ while ((newline = pending.indexOf("\n")) >= 0) {
50
+ observe(pending.slice(0, newline));
51
+ pending = pending.slice(newline + 1);
52
+ }
53
+ if (pending.length > 1_048_576) pending = pending.slice(-262_144);
54
+ });
55
+ const abort = () => child.kill("SIGTERM");
56
+ signal?.addEventListener("abort", abort, { once: true });
57
+ if (signal?.aborted) abort();
58
+ let result;
59
+ try {
60
+ result = await new Promise((resolve, reject) => {
61
+ child.once("error", reject);
62
+ child.once("close", (code, stoppedBy) => resolve({ code: code ?? 143, stoppedBy }));
63
+ });
64
+ } finally { signal?.removeEventListener("abort", abort); }
65
+ observe(pending);
66
+ if (pending) stdout.write("\n");
67
+ if (signal?.aborted || result.stoppedBy || result.code === 0 || !capacityFailure) return result.code;
68
+ if (retries >= maxRetries) {
69
+ event("citeark.codex_capacity_retries_exhausted", { retries, retryDelayMs, error: { message: "Codex capacity retry limit exhausted" } });
70
+ return result.code;
71
+ }
72
+ event("citeark.codex_capacity_retry_scheduled", { retry: retries + 1, maxRetries, retryDelayMs });
73
+ try { await wait(retryDelayMs, undefined, { signal }); }
74
+ catch (error) { if (signal?.aborted) return 143; throw error; }
75
+ currentArgs = resumeCapacityArguments(currentArgs, threadId);
76
+ }
77
+ }
78
+
79
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
80
+ const [delay, retries, ...args] = process.argv.slice(2);
81
+ const controller = new AbortController();
82
+ process.once("SIGTERM", () => controller.abort());
83
+ process.once("SIGINT", () => controller.abort());
84
+ runCodexWithCapacityRetry({ args, retryDelayMs: Number(delay), maxRetries: Number(retries), signal: controller.signal })
85
+ .then(code => { process.exitCode = code; })
86
+ .catch(error => { console.error(error.message); process.exitCode = 1; });
87
+ }
@@ -0,0 +1,64 @@
1
+ import { modelRoute } from "../provider/model-route.mjs";
2
+ import { composeAgentPrompt } from "./prompt.mjs";
3
+ import { CODEX_FINAL_MESSAGE_PATH } from "./final-output.mjs";
4
+
5
+ export async function buildCodexInvocation({
6
+ bundle,
7
+ attempt,
8
+ prompt,
9
+ instructions,
10
+ providerSession,
11
+ }) {
12
+ const agent = bundle.runtimeAgent;
13
+ const route = modelRoute(agent);
14
+ const provider = route.transport === "codex_subscription"
15
+ ? ["--config", 'model_provider="openai"', "--config", 'forced_login_method="chatgpt"', "--config", 'cli_auth_credentials_store="file"']
16
+ : codexProviderArguments(providerSession.containerBaseUrl);
17
+ const common = [
18
+ "--json",
19
+ "--ignore-user-config",
20
+ "--ignore-rules",
21
+ "--skip-git-repo-check",
22
+ "--dangerously-bypass-approvals-and-sandbox",
23
+ "--model",
24
+ route.nativeModel ?? agent.model,
25
+ "--output-last-message",
26
+ CODEX_FINAL_MESSAGE_PATH,
27
+ "--config",
28
+ `model_reasoning_effort=${JSON.stringify(agent.effort)}`,
29
+ ...provider,
30
+ ];
31
+ const fullPrompt = composeAgentPrompt(instructions, prompt);
32
+ return {
33
+ command: "codex",
34
+ capacityRecovery: { retryDelayMs: (agent.capacityRetryDelaySeconds ?? 10) * 1_000, maxRetries: agent.capacityMaxRetries ?? 30 },
35
+ args:
36
+ attempt === 1
37
+ ? ["--search", "exec", ...common, fullPrompt]
38
+ : ["--search", "exec", "resume", "--last", ...common, fullPrompt],
39
+ prompt,
40
+ promptArgument: fullPrompt,
41
+ };
42
+ }
43
+
44
+ function codexProviderArguments(baseUrl) {
45
+ return [
46
+ "--config",
47
+ 'model_provider="citeark"',
48
+ "--config",
49
+ 'model_providers.citeark.name="CiteArk Relay"',
50
+ "--config",
51
+ `model_providers.citeark.base_url=${JSON.stringify(`${baseUrl}/v1`)}`,
52
+ "--config",
53
+ 'model_providers.citeark.env_key="OPENAI_API_KEY"',
54
+ "--config",
55
+ 'model_providers.citeark.wire_api="responses"',
56
+ ];
57
+ }
58
+
59
+ export function freshCodexInvocation(invocation) {
60
+ const args = [...invocation.args];
61
+ const execIndex = args.indexOf("exec");
62
+ if (invocation.command === "codex" && execIndex >= 0 && args[execIndex + 1] === "resume" && args[execIndex + 2] === "--last") args.splice(execIndex + 1, 2);
63
+ return { ...invocation, args };
64
+ }
@@ -0,0 +1,157 @@
1
+ import { CiteArkError } from "../util.mjs";
2
+
3
+ export const AGENT_RUNTIMES = Object.freeze({
4
+ "claude-code": {
5
+ apiProtocol: "anthropic-messages",
6
+ apiLabel: "Anthropic Messages API",
7
+ },
8
+ codex: {
9
+ apiProtocol: "openai-responses",
10
+ apiLabel: "OpenAI Responses API",
11
+ },
12
+ opencode: {
13
+ apiProtocol: "openai-chat-completions",
14
+ apiLabel: "OpenAI Chat Completions API",
15
+ },
16
+ });
17
+
18
+ export function resolveAgentRuntime({
19
+ taskAgent = {},
20
+ runtime,
21
+ apiBaseUrl,
22
+ apiKey,
23
+ apiKeySource = "parameter",
24
+ billingMode,
25
+ codexAccountId,
26
+ model,
27
+ subagentModel,
28
+ effort,
29
+ reasoningMode,
30
+ maxTurns,
31
+ maxBudgetUsd,
32
+ capacityRetryDelaySeconds,
33
+ capacityMaxRetries,
34
+ requireApi = true,
35
+ } = {}) {
36
+ const selectedRuntime = runtime ?? taskAgent.runtime ?? "opencode";
37
+ const definition = AGENT_RUNTIMES[selectedRuntime];
38
+ if (!definition) {
39
+ throw new CiteArkError(
40
+ `agent must be one of ${Object.keys(AGENT_RUNTIMES).join(", ")}`,
41
+ );
42
+ }
43
+
44
+ const selectedModel = nonEmpty(model) ?? nonEmpty(taskAgent.model);
45
+ const selectedBaseUrl = nonEmpty(apiBaseUrl);
46
+ const selectedApiKey = nonEmpty(apiKey);
47
+ const selectedEffort = effort ?? taskAgent.effort ?? "high";
48
+ const selectedReasoningMode = reasoningMode ?? taskAgent.reasoningMode ?? "standard";
49
+ const requestedMaxTurns = maxTurns ?? taskAgent.maxTurns ?? 200;
50
+ const requestedMaxBudgetUsd = maxBudgetUsd ?? taskAgent.maxBudgetUsd ?? 20;
51
+ const selectedMaxTurns = boundedTaskLimit(requestedMaxTurns, taskAgent.budgetCaps?.maxTurns);
52
+ const selectedMaxBudgetUsd = boundedTaskLimit(
53
+ requestedMaxBudgetUsd,
54
+ taskAgent.budgetCaps?.maxBudgetUsd,
55
+ );
56
+ const issues = [];
57
+ const selectedCapacityDelay = capacityRetryDelaySeconds ?? taskAgent.capacityRetryDelaySeconds ?? 10;
58
+ const selectedCapacityRetries = capacityMaxRetries ?? taskAgent.capacityMaxRetries ?? 30;
59
+ if (!Number.isInteger(selectedCapacityDelay) || selectedCapacityDelay < 1 || selectedCapacityDelay > 60) issues.push("capacityRetryDelaySeconds must be 1–60");
60
+ if (!Number.isInteger(selectedCapacityRetries) || selectedCapacityRetries < 0 || selectedCapacityRetries > 30) issues.push("capacityMaxRetries must be 0–30");
61
+ if (codexAccountId && (selectedRuntime !== "codex" || !/^[a-z0-9][a-z0-9-]{0,47}$/.test(codexAccountId))) issues.push("Invalid Codex account configuration");
62
+ if (codexAccountId && selectedReasoningMode !== "standard") issues.push("Subscription sign-in uses native Codex reasoning. Select standard mode.");
63
+ if (codexAccountId && selectedModel?.replace(/^openai\//, "").includes("/")) issues.push("Subscription sign-in requires a native Codex model name");
64
+ if (!selectedModel) issues.push("Missing model");
65
+ if (requireApi && !codexAccountId && !selectedBaseUrl) issues.push("Missing API base URL");
66
+ if (requireApi && !codexAccountId && !selectedApiKey) issues.push("Missing API key");
67
+ if (selectedBaseUrl) validateBaseUrl(selectedBaseUrl, issues);
68
+ if (!new Set(["low", "medium", "high", "xhigh", "max"]).has(selectedEffort)) {
69
+ issues.push("effort must be low, medium, high, xhigh, or max");
70
+ }
71
+ if (!new Set(["standard", "pro"]).has(selectedReasoningMode)) {
72
+ issues.push("reasoningMode must be standard or pro");
73
+ }
74
+ if (selectedReasoningMode === "pro" && selectedRuntime === "claude-code") {
75
+ issues.push("Pro reasoning supports Codex and OpenCode");
76
+ }
77
+ if (!Number.isInteger(selectedMaxTurns) || selectedMaxTurns < 1) {
78
+ issues.push("maxTurns must be a positive integer");
79
+ }
80
+ if (typeof selectedMaxBudgetUsd !== "number" || !Number.isFinite(selectedMaxBudgetUsd) || selectedMaxBudgetUsd <= 0) {
81
+ issues.push("maxBudgetUsd must be greater than 0");
82
+ }
83
+ if (issues.length) {
84
+ throw new CiteArkError(`Invalid Agent configuration: \n- ${issues.join("\n- ")}`);
85
+ }
86
+
87
+ return {
88
+ runtime: selectedRuntime,
89
+ ...(codexAccountId ? { codexAccountId, billingMode: "subscription" } : {}),
90
+ ...(!codexAccountId && billingMode ? { billingMode } : {}),
91
+ model: selectedModel ?? "<model>",
92
+ subagentModel:
93
+ nonEmpty(subagentModel) ?? nonEmpty(taskAgent.subagentModel) ?? selectedModel ?? "<model>",
94
+ autoCompactWindow: taskAgent.autoCompactWindow ?? 786432,
95
+ effort: selectedEffort,
96
+ reasoningMode: selectedReasoningMode,
97
+ maxTurns: selectedMaxTurns,
98
+ maxBudgetUsd: selectedMaxBudgetUsd,
99
+ validationRetries: taskAgent.validationRetries ?? 0,
100
+ capacityRetryDelaySeconds: selectedCapacityDelay,
101
+ capacityMaxRetries: selectedCapacityRetries,
102
+ api: {
103
+ protocol: definition.apiProtocol,
104
+ label: definition.apiLabel,
105
+ baseUrl: selectedBaseUrl ?? "https://api.invalid",
106
+ apiKey: selectedApiKey ?? null,
107
+ credentialSource: apiKeySource,
108
+ },
109
+ };
110
+ }
111
+
112
+ function boundedTaskLimit(requested, hardCap) {
113
+ if (typeof hardCap !== "number" || !Number.isFinite(hardCap) || hardCap <= 0) return requested;
114
+ if (typeof requested !== "number" || !Number.isFinite(requested)) return requested;
115
+ return Math.min(requested, hardCap);
116
+ }
117
+
118
+ export function publicAgentRuntime(runtimeAgent) {
119
+ return {
120
+ runtime: runtimeAgent.runtime,
121
+ ...(runtimeAgent.codexAccountId ? { codexAccountId: runtimeAgent.codexAccountId, billingMode: "subscription" } : {}),
122
+ ...(!runtimeAgent.codexAccountId && runtimeAgent.billingMode ? { billingMode: runtimeAgent.billingMode } : {}),
123
+ model: runtimeAgent.model,
124
+ subagentModel: runtimeAgent.subagentModel,
125
+ effort: runtimeAgent.effort,
126
+ reasoningMode: runtimeAgent.reasoningMode,
127
+ maxTurns: runtimeAgent.maxTurns,
128
+ maxBudgetUsd: runtimeAgent.maxBudgetUsd,
129
+ validationRetries: runtimeAgent.validationRetries,
130
+ capacityRetryDelaySeconds: runtimeAgent.capacityRetryDelaySeconds,
131
+ capacityMaxRetries: runtimeAgent.capacityMaxRetries,
132
+ api: {
133
+ protocol: runtimeAgent.api.protocol,
134
+ baseUrl: runtimeAgent.api.baseUrl,
135
+ credentialSource: runtimeAgent.api.credentialSource,
136
+ credentialRecorded: false,
137
+ },
138
+ };
139
+ }
140
+
141
+ function validateBaseUrl(value, issues) {
142
+ try {
143
+ const url = new URL(value);
144
+ if (!new Set(["http:", "https:"]).has(url.protocol)) {
145
+ issues.push("apiBaseUrl must use HTTP(S)");
146
+ }
147
+ if (url.username || url.password || url.search || url.hash) {
148
+ issues.push("apiBaseUrl cannot contain credentials, query parameters, or fragments");
149
+ }
150
+ } catch {
151
+ issues.push("apiBaseUrl is not a valid URL");
152
+ }
153
+ }
154
+
155
+ function nonEmpty(value) {
156
+ return typeof value === "string" && value.trim() ? value.trim() : null;
157
+ }
@@ -0,0 +1,40 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { pathExists } from "../util.mjs";
5
+
6
+ export const CODEX_FINAL_MESSAGE_PATH = "/job/execution/codex-final-message.txt";
7
+
8
+ export async function recoverJsonFromFinalMessage({
9
+ finalMessagePath,
10
+ outputPath,
11
+ }) {
12
+ if (await pathExists(outputPath)) return false;
13
+
14
+ let raw;
15
+ try {
16
+ raw = await readFile(finalMessagePath, "utf8");
17
+ } catch {
18
+ return false;
19
+ }
20
+ const candidate = unwrapSingleJsonFence(raw.trim());
21
+ if (!candidate) return false;
22
+
23
+ let parsed;
24
+ try {
25
+ parsed = JSON.parse(candidate);
26
+ } catch {
27
+ return false;
28
+ }
29
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
30
+
31
+ await mkdir(path.dirname(outputPath), { recursive: true });
32
+ await writeFile(outputPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
33
+ return true;
34
+ }
35
+
36
+ function unwrapSingleJsonFence(value) {
37
+ if (!value.startsWith("```")) return value;
38
+ const match = value.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i);
39
+ return match?.[1]?.trim() ?? "";
40
+ }
@@ -0,0 +1,21 @@
1
+ import { researchInstructions } from '../workspace/control.mjs';
2
+ import { buildClaudeCodeInvocation } from "./claude-code.mjs";
3
+ import { buildCodexInvocation } from "./codex.mjs";
4
+ import { buildOpenCodeInvocation } from "./opencode.mjs";
5
+ import { CiteArkError } from "../util.mjs";
6
+
7
+ export async function buildAgentInvocation(options) {
8
+ const notes = await researchInstructions();
9
+ if (notes) options = { ...options, prompt: `${options.prompt}\n\nUser follow-up instructions:\n${notes}\nApply these within the selected experiments, resource limits and recorded evidence requirements. Explain any request that needs a new plan or authorization.` };
10
+ const runtime = options.bundle.runtimeAgent.runtime;
11
+ if (runtime === "claude-code") return buildClaudeCodeInvocation(options);
12
+ if (runtime === "codex") return buildCodexInvocation(options);
13
+ if (runtime === "opencode") return buildOpenCodeInvocation(options);
14
+ throw new CiteArkError(`未实现的 Agent 运行器:${runtime}`);
15
+ }
16
+
17
+ export function agentInvocationPromptArgument(invocation) {
18
+ if (typeof invocation?.promptArgument === "string") return invocation.promptArgument;
19
+ if (typeof invocation?.prompt === "string") return invocation.prompt;
20
+ throw new TypeError("Agent invocation 缺少可持久化的 prompt 参数");
21
+ }
@@ -0,0 +1,74 @@
1
+ import { hasSessionEvents, createRuntimeStream } from '../terminal/events.mjs';
2
+ import { CLI_COMMUNICATION } from './prompt.mjs';
3
+ import { spawn } from "node:child_process";
4
+ import { createWriteStream } from "node:fs";
5
+ import { mkdir, readFile } from "node:fs/promises";
6
+ import path from "node:path";
7
+
8
+ // Reuse the user's ChatGPT login. Do not inherit provider keys, relay endpoints,
9
+ // cloud credentials, or the parent Codex task's internal runtime settings.
10
+ export function localCodexEnvironment(environment = process.env) {
11
+ return Object.fromEntries(["HOME", "PATH", "TMPDIR", "LANG", "LC_ALL", "TERM"]
12
+ .filter((key) => environment[key] !== undefined).map((key) => [key, environment[key]]));
13
+ }
14
+
15
+ export async function runLocalCodex({ prompt, cwd, directory, model, effort = "medium", writableDirectories = [],
16
+ readOnly = false, config = [], environment, outputSchemaPath, timeoutMs = 14_400_000, command = "codex", progress = () => {}, signal }) {
17
+ await mkdir(directory, { recursive: true });
18
+ const answerPath = path.join(directory, "answer.txt");
19
+ const tracePath = path.join(directory, "trace.jsonl");
20
+ const args = ["exec", "--ignore-user-config", "--ignore-rules", "--ephemeral", "--skip-git-repo-check", "--json",
21
+ "--model", model, "--config", `model_reasoning_effort=${JSON.stringify(effort)}`,
22
+ "--config", "features.multi_agent=false", "--sandbox", readOnly ? "read-only" : "workspace-write",
23
+ "--config", "sandbox_workspace_write.network_access=true", "--cd", cwd,
24
+ "--output-last-message", answerPath,
25
+ ...(outputSchemaPath ? ["--output-schema", outputSchemaPath] : []),
26
+ ...writableDirectories.flatMap((entry) => ["--add-dir", entry]),
27
+ ...config.flatMap((entry) => ["--config", entry]), "-"];
28
+ const stdout = createWriteStream(tracePath);
29
+ const stderr = createWriteStream(path.join(directory, "stderr.log"));
30
+ const startedAt = new Date().toISOString();
31
+ const child = spawn(command, args, { cwd, env: { ...localCodexEnvironment(environment ?? process.env),
32
+ ...(environment?.CODEX_HOME ? { CODEX_HOME: environment.CODEX_HOME } : {}) }, detached: true, stdio: ["pipe", "pipe", "pipe"] });
33
+ let buffer = "", usage = null, sessionId = null, timedOut = false, aborted = false;
34
+ const stop = () => { try { process.kill(-child.pid, "SIGTERM"); } catch {} };
35
+ const abort = () => { aborted = true; stop(); };
36
+ signal?.addEventListener("abort", abort, { once: true });
37
+ if (signal?.aborted) abort();
38
+ const timer = setTimeout(() => { timedOut = true; stop(); }, timeoutMs);
39
+ const interrupt = () => stop();
40
+ process.on("SIGINT", interrupt); process.on("SIGTERM", interrupt);
41
+ const stream = hasSessionEvents() ? createRuntimeStream({ source: directory, runtime: 'codex' }) : null;
42
+ child.stdout.pipe(stdout); child.stderr.pipe(stderr);
43
+ child.stderr.on('data', chunk => stream?.stderr(chunk));
44
+ child.stdout.on("data", (bytes) => {
45
+ stream?.write(bytes);
46
+ buffer += bytes.toString();
47
+ let newline;
48
+ while ((newline = buffer.indexOf("\n")) >= 0) {
49
+ const line = buffer.slice(0, newline); buffer = buffer.slice(newline + 1);
50
+ try {
51
+ const event = JSON.parse(line);
52
+ if (event.type === "thread.started") sessionId = event.thread_id;
53
+ if (event.type === "turn.completed") usage = event.usage;
54
+ if (!stream && event.type === "item.completed" && event.item?.type === "agent_message") progress(event.item.text);
55
+ } catch {}
56
+ }
57
+ });
58
+ child.stdin.on("error", () => {});
59
+ child.stdin.end(hasSessionEvents() ? `${CLI_COMMUNICATION}\n\n${prompt}` : prompt);
60
+ let result;
61
+ try {
62
+ result = await new Promise((resolve, reject) => {
63
+ child.once("error", reject);
64
+ child.once("close", (code, signal) => resolve({ code, signal }));
65
+ });
66
+ } finally {
67
+ clearTimeout(timer); process.off("SIGINT", interrupt); process.off("SIGTERM", interrupt);
68
+ signal?.removeEventListener("abort", abort);
69
+ stream?.end(); stdout.end(); stderr.end();
70
+ }
71
+ return { ...result, timedOut, aborted, startedAt, finishedAt: new Date().toISOString(), sessionId, usage, tracePath,
72
+ answer: await readFile(answerPath, "utf8").catch(() => ""),
73
+ invocation: { command, args, authentication: "existing_chatgpt_login", inheritedProviderKeys: false } };
74
+ }
@@ -0,0 +1,95 @@
1
+ import { composeAgentPrompt } from "./prompt.mjs";
2
+
3
+ export async function buildOpenCodeInvocation({
4
+ bundle,
5
+ attempt,
6
+ prompt,
7
+ instructions,
8
+ }) {
9
+ const agent = bundle.runtimeAgent;
10
+ const fullPrompt = composeAgentPrompt(instructions, prompt);
11
+ const reasoningVariant = openCodeReasoningVariant(agent);
12
+ return {
13
+ command: "opencode",
14
+ args: [
15
+ "run",
16
+ "--pure",
17
+ "--auto",
18
+ ...(attempt > 1 ? ["--continue"] : []),
19
+ "--format",
20
+ "json",
21
+ "--model",
22
+ openCodeModelReference(agent),
23
+ ...(reasoningVariant ? ["--variant", reasoningVariant] : []),
24
+ fullPrompt,
25
+ ],
26
+ prompt,
27
+ promptArgument: fullPrompt,
28
+ };
29
+ }
30
+
31
+ export function openCodeModelDefinition(agent) {
32
+ const model = agent.model;
33
+ if (model.startsWith("deepseek-")) {
34
+ return {
35
+ name: model,
36
+ reasoning: true,
37
+ tool_call: true,
38
+ interleaved: { field: "reasoning_content" },
39
+ };
40
+ }
41
+ if (openRouterReasoningProvider(agent)) {
42
+ return {
43
+ name: model,
44
+ ...(["openai/gpt-6-astra", "openai/gpt-5.6-sol"].includes(model)
45
+ ? { modalities: { input: ["text", "image"], output: ["text"] } }
46
+ : {}),
47
+ reasoning: true,
48
+ tool_call: true,
49
+ variants: {
50
+ low: { reasoningEffort: "low" },
51
+ medium: { reasoningEffort: "medium" },
52
+ high: { reasoningEffort: "high" },
53
+ },
54
+ };
55
+ }
56
+ return { name: model };
57
+ }
58
+
59
+ export function openCodeReasoningVariant(agent) {
60
+ if (nativeDeepSeekProvider(agent)) return agent.effort;
61
+ if (!openRouterReasoningProvider(agent)) return null;
62
+ return new Set(["low", "medium", "high"]).has(agent.effort)
63
+ ? agent.effort
64
+ : "high";
65
+ }
66
+
67
+ export function openCodeModelReference(agent) {
68
+ return nativeDeepSeekProvider(agent)
69
+ ? `deepseek/${agent.model}`
70
+ : `citeark/${agent.model}`;
71
+ }
72
+
73
+ export function nativeDeepSeekProvider(agent) {
74
+ if (!agent?.model?.startsWith("deepseek-")) return false;
75
+ try {
76
+ const url = new URL(agent.api.baseUrl);
77
+ return (
78
+ url.protocol === "https:" &&
79
+ url.hostname === "api.deepseek.com" &&
80
+ new Set(["", "/", "/v1", "/v1/"]).has(url.pathname)
81
+ );
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+
87
+ function openRouterReasoningProvider(agent) {
88
+ if (!/^(?:google\/gemini-3(?:[.-]|$)|openai\/gpt-[56](?:[.-]|$))/.test(agent?.model ?? "")) return false;
89
+ try {
90
+ const url = new URL(agent.api.baseUrl);
91
+ return url.protocol === "https:" && url.hostname === "openrouter.ai";
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
@@ -0,0 +1,13 @@
1
+ import { hasSessionEvents } from '../terminal/events.mjs';
2
+
3
+ export const CLI_COMMUNICATION = 'Use English for user-facing messages. Explain meaningful actions and findings as you work. Preserve source quotations, code, paths, and user-provided text verbatim.';
4
+
5
+ export function composeAgentPrompt(instructions, prompt) {
6
+ return [
7
+ "CiteArk Agent execution instructions:",
8
+ instructions.trim(),
9
+ ...(hasSessionEvents() ? [CLI_COMMUNICATION] : []),
10
+ "Current task:",
11
+ prompt.trim(),
12
+ ].join("\n\n");
13
+ }