@leuduan/lagent 0.0.0-stage → 0.1.2

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 (327) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +144 -2
  3. package/dist/chunks/2O7ZGEIT.js +1 -0
  4. package/dist/chunks/2OSESBIL.js +1 -0
  5. package/dist/chunks/34KW6VNQ.js +1 -0
  6. package/dist/chunks/37YOGDGY.js +1 -0
  7. package/dist/chunks/3LQHQRIU.js +6 -0
  8. package/dist/chunks/3QCW4WDJ.js +1 -0
  9. package/dist/chunks/4XVRUSCQ.js +1 -0
  10. package/dist/chunks/6ECI2GGV.js +1 -0
  11. package/dist/chunks/74HKUGRR.js +1 -0
  12. package/dist/chunks/ADHERZLW.js +2 -0
  13. package/dist/chunks/AP6Q4EPT.js +36 -0
  14. package/dist/chunks/BM3S37EZ.js +1 -0
  15. package/dist/chunks/C5LYCXJG.js +1 -0
  16. package/dist/chunks/CDQG7RKA.js +1 -0
  17. package/dist/chunks/D7E6EWIE.js +3 -0
  18. package/dist/chunks/DDANMY45.js +3 -0
  19. package/dist/chunks/DRYAN665.js +1 -0
  20. package/dist/chunks/DXFXAYDN.js +17 -0
  21. package/dist/chunks/EGZI4XQX.js +24 -0
  22. package/dist/chunks/ENWFSU27.js +41 -0
  23. package/dist/chunks/G6RXC3AL.js +1 -0
  24. package/dist/chunks/G74AGRAJ.js +15 -0
  25. package/dist/chunks/GQGNVSKB.js +1 -0
  26. package/dist/chunks/IJ2WNMD5.js +7 -0
  27. package/dist/chunks/J5S4URAW.js +1 -0
  28. package/dist/chunks/JPZFKSWT.js +1 -0
  29. package/dist/chunks/KESCTXGO.js +5 -0
  30. package/dist/chunks/L3N4FIEN.js +1 -0
  31. package/dist/chunks/NAOUTU7A.js +4 -0
  32. package/dist/chunks/NDIM7MEW.js +1 -0
  33. package/dist/chunks/O4PPOM5Z.js +2 -0
  34. package/dist/chunks/OVZFGILJ.js +1 -0
  35. package/dist/chunks/P5ZHHOOM.js +6 -0
  36. package/dist/chunks/PUSUPTAT.js +1 -0
  37. package/dist/chunks/QMMLQJBS.js +1 -0
  38. package/dist/chunks/RK3VP2Q4.js +3 -0
  39. package/dist/chunks/SGGMBSBA.js +1 -0
  40. package/dist/chunks/SL2YLB2F.js +1 -0
  41. package/dist/chunks/TOOIB6J2.js +1 -0
  42. package/dist/chunks/TYTQRLTX.js +1 -0
  43. package/dist/chunks/UC3FVVJ2.js +5 -0
  44. package/dist/chunks/UCTEU62F.js +1 -0
  45. package/dist/chunks/UD3VJER6.js +1 -0
  46. package/dist/chunks/UKXMCHHT.js +1 -0
  47. package/dist/chunks/WUUKTSRT.js +7 -0
  48. package/dist/chunks/X65X4KP5.js +7 -0
  49. package/dist/chunks/YIR5MYGU.js +1 -0
  50. package/dist/chunks/YLNJXQ3Z.js +1 -0
  51. package/dist/context.d.ts +101 -0
  52. package/dist/index.d.ts +47 -0
  53. package/dist/index.js +77 -0
  54. package/dist/journal/catalog.d.ts +112 -0
  55. package/dist/journal/forkChain.d.ts +16 -0
  56. package/dist/journal/index.d.ts +15 -0
  57. package/dist/journal/journal.d.ts +475 -0
  58. package/dist/journal/projection.d.ts +87 -0
  59. package/dist/journal/store.d.ts +181 -0
  60. package/dist/kit/claim.d.ts +13 -0
  61. package/dist/kit/drain.d.ts +10 -0
  62. package/dist/kit/extension.d.ts +180 -0
  63. package/dist/kit/grants.d.ts +9 -0
  64. package/dist/kit/modes.d.ts +65 -0
  65. package/dist/kit/retries.d.ts +25 -0
  66. package/dist/kit/scope.d.ts +32 -0
  67. package/dist/kit/service.d.ts +7 -0
  68. package/dist/kit/strategy.d.ts +10 -0
  69. package/dist/kit/timers.d.ts +43 -0
  70. package/dist/kit/tool.d.ts +72 -0
  71. package/dist/llm/client.d.ts +135 -0
  72. package/dist/llm/content.d.ts +52 -0
  73. package/dist/llm/door.d.ts +21 -0
  74. package/dist/llm/door.js +1 -0
  75. package/dist/llm/failure.d.ts +82 -0
  76. package/dist/llm/index.d.ts +16 -0
  77. package/dist/llm/primitives.d.ts +286 -0
  78. package/dist/llm/prompt.d.ts +21 -0
  79. package/dist/llm/provider.d.ts +63 -0
  80. package/dist/llm/readLedger.d.ts +24 -0
  81. package/dist/llm/request.d.ts +58 -0
  82. package/dist/loop/agent.d.ts +134 -0
  83. package/dist/loop/auxiliary.d.ts +54 -0
  84. package/dist/loop/chain.d.ts +46 -0
  85. package/dist/loop/chunks.d.ts +27 -0
  86. package/dist/loop/continuation.d.ts +166 -0
  87. package/dist/loop/decide.d.ts +64 -0
  88. package/dist/loop/errors.d.ts +162 -0
  89. package/dist/loop/forks.d.ts +61 -0
  90. package/dist/loop/holds.d.ts +104 -0
  91. package/dist/loop/hooks.d.ts +241 -0
  92. package/dist/loop/inbox.d.ts +188 -0
  93. package/dist/loop/index.d.ts +37 -0
  94. package/dist/loop/limits.d.ts +14 -0
  95. package/dist/loop/opening.d.ts +42 -0
  96. package/dist/loop/prepare.d.ts +30 -0
  97. package/dist/loop/projections.d.ts +307 -0
  98. package/dist/loop/replace.d.ts +33 -0
  99. package/dist/loop/requests.d.ts +129 -0
  100. package/dist/loop/route.d.ts +53 -0
  101. package/dist/loop/runtime.d.ts +85 -0
  102. package/dist/loop/state.d.ts +70 -0
  103. package/dist/loop/strategy.d.ts +71 -0
  104. package/dist/loop/summary.d.ts +3 -0
  105. package/dist/loop/surface.d.ts +153 -0
  106. package/dist/loop/threadState.d.ts +72 -0
  107. package/dist/loop/tool.d.ts +101 -0
  108. package/dist/loop/toolCalls.d.ts +42 -0
  109. package/dist/loop/wake.d.ts +32 -0
  110. package/dist/models/config/agent.d.ts +18 -0
  111. package/dist/models/config/prompt.d.ts +18 -0
  112. package/dist/models/door.d.ts +12 -0
  113. package/dist/models/door.js +1 -0
  114. package/dist/models/index.d.ts +7 -0
  115. package/dist/models/jsonSchema.d.ts +7 -0
  116. package/dist/models/wire/journal.d.ts +2772 -0
  117. package/dist/models/wire/primitives.d.ts +65 -0
  118. package/dist/plugin.d.ts +53 -0
  119. package/dist/plugin.js +1 -0
  120. package/dist/plugins/agentsMd.d.ts +76 -0
  121. package/dist/plugins/agentsMd.js +1 -0
  122. package/dist/plugins/ask/askQuestion.d.ts +9 -0
  123. package/dist/plugins/ask/index.d.ts +26 -0
  124. package/dist/plugins/ask/index.js +1 -0
  125. package/dist/plugins/ask/service.d.ts +125 -0
  126. package/dist/plugins/commands/background.d.ts +8 -0
  127. package/dist/plugins/commands/foreground.d.ts +4 -0
  128. package/dist/plugins/commands/index.d.ts +40 -0
  129. package/dist/plugins/commands/index.js +1 -0
  130. package/dist/plugins/commands/output.d.ts +115 -0
  131. package/dist/plugins/commands/record.d.ts +549 -0
  132. package/dist/plugins/commands/service.d.ts +314 -0
  133. package/dist/plugins/commands/shell.d.ts +25 -0
  134. package/dist/plugins/compaction/checkpoint.d.ts +91 -0
  135. package/dist/plugins/compaction/config.d.ts +133 -0
  136. package/dist/plugins/compaction/estimate.d.ts +29 -0
  137. package/dist/plugins/compaction/index.d.ts +2 -0
  138. package/dist/plugins/compaction/index.js +7 -0
  139. package/dist/plugins/compaction/log.d.ts +61 -0
  140. package/dist/plugins/compaction/planner.d.ts +207 -0
  141. package/dist/plugins/compaction/preset.d.ts +86 -0
  142. package/dist/plugins/compaction/prune.d.ts +9 -0
  143. package/dist/plugins/compaction/records.d.ts +227 -0
  144. package/dist/plugins/compaction/segments.d.ts +23 -0
  145. package/dist/plugins/compaction/shared.d.ts +14 -0
  146. package/dist/plugins/compaction/summarize.d.ts +13 -0
  147. package/dist/plugins/dateAndBranch.d.ts +47 -0
  148. package/dist/plugins/dateAndBranch.js +1 -0
  149. package/dist/plugins/delegations/answers.d.ts +39 -0
  150. package/dist/plugins/delegations/assignmentKey.d.ts +22 -0
  151. package/dist/plugins/delegations/cleanup.d.ts +161 -0
  152. package/dist/plugins/delegations/constraint.d.ts +76 -0
  153. package/dist/plugins/delegations/index.d.ts +39 -0
  154. package/dist/plugins/delegations/index.js +1 -0
  155. package/dist/plugins/delegations/notices.d.ts +261 -0
  156. package/dist/plugins/delegations/obligations.d.ts +210 -0
  157. package/dist/plugins/delegations/record.d.ts +632 -0
  158. package/dist/plugins/delegations/request.d.ts +381 -0
  159. package/dist/plugins/delegations/role.d.ts +30 -0
  160. package/dist/plugins/delegations/service.d.ts +562 -0
  161. package/dist/plugins/delegations/standing.d.ts +19 -0
  162. package/dist/plugins/delegations/stopCheck.d.ts +21 -0
  163. package/dist/plugins/delegations/testing.d.ts +16 -0
  164. package/dist/plugins/delegations/tools.d.ts +71 -0
  165. package/dist/plugins/delegations/waitBook.d.ts +116 -0
  166. package/dist/plugins/delegations/waits.d.ts +118 -0
  167. package/dist/plugins/diagnostics/digest.d.ts +14 -0
  168. package/dist/plugins/diagnostics/index.d.ts +68 -0
  169. package/dist/plugins/diagnostics/index.js +1 -0
  170. package/dist/plugins/historyRecall/history.d.ts +9 -0
  171. package/dist/plugins/historyRecall/index.d.ts +31 -0
  172. package/dist/plugins/historyRecall/index.js +1 -0
  173. package/dist/plugins/historyRecall/render.d.ts +34 -0
  174. package/dist/plugins/historyRecall/tools.d.ts +4 -0
  175. package/dist/plugins/mcp/catalog.d.ts +36 -0
  176. package/dist/plugins/mcp/config.d.ts +63 -0
  177. package/dist/plugins/mcp/connection.d.ts +53 -0
  178. package/dist/plugins/mcp/errors.d.ts +32 -0
  179. package/dist/plugins/mcp/index.d.ts +33 -0
  180. package/dist/plugins/mcp/index.js +5 -0
  181. package/dist/plugins/mcp/mount.d.ts +98 -0
  182. package/dist/plugins/mcp/names.d.ts +25 -0
  183. package/dist/plugins/mcp/render.d.ts +29 -0
  184. package/dist/plugins/mcp/slots.d.ts +15 -0
  185. package/dist/plugins/mcp/stdio.d.ts +49 -0
  186. package/dist/plugins/mcp/tool.d.ts +41 -0
  187. package/dist/plugins/providers/anthropic.d.ts +175 -0
  188. package/dist/plugins/providers/anthropicMessages.d.ts +65 -0
  189. package/dist/plugins/providers/codex.d.ts +60 -0
  190. package/dist/plugins/providers/codexAuth.d.ts +116 -0
  191. package/dist/plugins/providers/deepseek.d.ts +55 -0
  192. package/dist/plugins/providers/door.d.ts +61 -0
  193. package/dist/plugins/providers/door.js +1 -0
  194. package/dist/plugins/providers/failure.d.ts +23 -0
  195. package/dist/plugins/providers/gateway.d.ts +23 -0
  196. package/dist/plugins/providers/index.d.ts +6 -0
  197. package/dist/plugins/providers/openaiChat.d.ts +62 -0
  198. package/dist/plugins/providers/openaiResponses.d.ts +100 -0
  199. package/dist/plugins/providers/opencodeCopilot.d.ts +23 -0
  200. package/dist/plugins/providers/opencodeGo.d.ts +98 -0
  201. package/dist/plugins/providers/shared.d.ts +104 -0
  202. package/dist/plugins/providers/stream.d.ts +154 -0
  203. package/dist/plugins/routeContext.d.ts +22 -0
  204. package/dist/plugins/routeContext.js +1 -0
  205. package/dist/plugins/schedules/index.d.ts +21 -0
  206. package/dist/plugins/schedules/index.js +5 -0
  207. package/dist/plugins/schedules/record.d.ts +396 -0
  208. package/dist/plugins/schedules/service.d.ts +120 -0
  209. package/dist/plugins/schedules/time.d.ts +26 -0
  210. package/dist/plugins/schedules/tools.d.ts +6 -0
  211. package/dist/plugins/skills/discovery.d.ts +54 -0
  212. package/dist/plugins/skills/index.d.ts +31 -0
  213. package/dist/plugins/skills/index.js +1 -0
  214. package/dist/plugins/skills/tool.d.ts +11 -0
  215. package/dist/plugins/store/durableObject.d.ts +23 -0
  216. package/dist/plugins/store/durableObject.js +1 -0
  217. package/dist/plugins/store/durableObjectConnection.d.ts +27 -0
  218. package/dist/plugins/store/memory.d.ts +29 -0
  219. package/dist/plugins/store/sql.d.ts +59 -0
  220. package/dist/plugins/store/sqlite.d.ts +31 -0
  221. package/dist/plugins/store/sqlite.js +1 -0
  222. package/dist/plugins/subAgents/availableRoutes.d.ts +53 -0
  223. package/dist/plugins/subAgents/fork.d.ts +32 -0
  224. package/dist/plugins/subAgents/index.d.ts +67 -0
  225. package/dist/plugins/subAgents/index.js +1 -0
  226. package/dist/plugins/subAgents/tool.d.ts +38 -0
  227. package/dist/plugins/toolPolicy/index.d.ts +61 -0
  228. package/dist/plugins/toolPolicy/index.js +1 -0
  229. package/dist/plugins/tools/editFiles.d.ts +128 -0
  230. package/dist/plugins/tools/fsRead.d.ts +17 -0
  231. package/dist/plugins/tools/html.d.ts +23 -0
  232. package/dist/plugins/tools/index.d.ts +59 -0
  233. package/dist/plugins/tools/index.js +1 -0
  234. package/dist/plugins/tools/network.d.ts +23 -0
  235. package/dist/plugins/tools/ripgrep.d.ts +20 -0
  236. package/dist/plugins/tools/textEdit.d.ts +67 -0
  237. package/dist/plugins/tools/web.d.ts +32 -0
  238. package/dist/plugins/truncateToolOutput.d.ts +26 -0
  239. package/dist/plugins/truncateToolOutput.js +1 -0
  240. package/dist/plugins/usage/index.d.ts +24 -0
  241. package/dist/plugins/usage/index.js +1 -0
  242. package/dist/plugins/usage/tracker.d.ts +34 -0
  243. package/dist/plugins/verify/facts.d.ts +356 -0
  244. package/dist/plugins/verify/index.d.ts +75 -0
  245. package/dist/plugins/verify/index.js +1 -0
  246. package/dist/plugins/verify/service.d.ts +90 -0
  247. package/dist/plugins/workflows/assignment.d.ts +16 -0
  248. package/dist/plugins/workflows/bindings.d.ts +95 -0
  249. package/dist/plugins/workflows/cleanup.d.ts +38 -0
  250. package/dist/plugins/workflows/definition.d.ts +184 -0
  251. package/dist/plugins/workflows/fold.d.ts +373 -0
  252. package/dist/plugins/workflows/index.d.ts +28 -0
  253. package/dist/plugins/workflows/index.js +6 -0
  254. package/dist/plugins/workflows/observations.d.ts +81 -0
  255. package/dist/plugins/workflows/participants.d.ts +143 -0
  256. package/dist/plugins/workflows/policy.d.ts +112 -0
  257. package/dist/plugins/workflows/providers.d.ts +146 -0
  258. package/dist/plugins/workflows/record.d.ts +2863 -0
  259. package/dist/plugins/workflows/routing.d.ts +116 -0
  260. package/dist/plugins/workflows/schema.d.ts +26 -0
  261. package/dist/plugins/workflows/service.d.ts +477 -0
  262. package/dist/plugins/workflows/submit.d.ts +8 -0
  263. package/dist/plugins/workflows/view.d.ts +103 -0
  264. package/dist/plugins/workflows/work.d.ts +21 -0
  265. package/dist/plugins/workspaceContext.d.ts +38 -0
  266. package/dist/plugins/workspaceContext.js +1 -0
  267. package/dist/presets/agents.d.ts +7 -0
  268. package/dist/presets/base.d.ts +10 -0
  269. package/dist/presets/codex.d.ts +60 -0
  270. package/dist/presets/index.d.ts +4 -0
  271. package/dist/presets/prompts.d.ts +56 -0
  272. package/dist/sandbox/absent.d.ts +32 -0
  273. package/dist/sandbox/client.d.ts +39 -0
  274. package/dist/sandbox/files.d.ts +28 -0
  275. package/dist/sandbox/index.d.ts +49 -0
  276. package/dist/sandbox/index.js +4 -0
  277. package/dist/sandbox/mode.d.ts +57 -0
  278. package/dist/sandbox/policy.d.ts +86 -0
  279. package/dist/sandbox/protocol.d.ts +107 -0
  280. package/dist/sandbox/service.d.ts +143 -0
  281. package/dist/sandbox/worker.d.ts +12 -0
  282. package/dist/sandbox/worker.js +1 -0
  283. package/dist/services/admission.d.ts +174 -0
  284. package/dist/services/agents.d.ts +37 -0
  285. package/dist/services/birth.d.ts +220 -0
  286. package/dist/services/contributions.d.ts +73 -0
  287. package/dist/services/core.d.ts +34 -0
  288. package/dist/services/journal.d.ts +26 -0
  289. package/dist/services/launches.d.ts +104 -0
  290. package/dist/services/llm.d.ts +80 -0
  291. package/dist/services/owner.d.ts +367 -0
  292. package/dist/services/preset.d.ts +154 -0
  293. package/dist/services/presets.d.ts +139 -0
  294. package/dist/services/prompts.d.ts +67 -0
  295. package/dist/services/runEvents.d.ts +79 -0
  296. package/dist/services/thread.d.ts +267 -0
  297. package/dist/services/threadActivation.d.ts +100 -0
  298. package/dist/services/threadDirs.d.ts +38 -0
  299. package/dist/services/threadView.d.ts +92 -0
  300. package/dist/services/threads.d.ts +449 -0
  301. package/dist/services/tools.d.ts +41 -0
  302. package/dist/sys/environment.d.ts +47 -0
  303. package/dist/sys/git.d.ts +60 -0
  304. package/dist/sys/paths.d.ts +56 -0
  305. package/dist/sys/spawn.d.ts +176 -0
  306. package/dist/testing/clock.d.ts +17 -0
  307. package/dist/testing/fakeLlm.d.ts +74 -0
  308. package/dist/testing/fedLlm.d.ts +32 -0
  309. package/dist/testing/helpers.d.ts +344 -0
  310. package/dist/testing/index.d.ts +13 -0
  311. package/dist/testing/index.js +1 -0
  312. package/dist/testing/processes.d.ts +13 -0
  313. package/dist/testing/sandbox.d.ts +71 -0
  314. package/dist/testing/settlement.d.ts +6 -0
  315. package/dist/testing/tmpDirs.d.ts +17 -0
  316. package/dist/util/async.d.ts +8 -0
  317. package/dist/util/diff.d.ts +25 -0
  318. package/dist/util/dispatch.d.ts +8 -0
  319. package/dist/util/errors.d.ts +28 -0
  320. package/dist/util/foldState.d.ts +17 -0
  321. package/dist/util/freeze.d.ts +2 -0
  322. package/dist/util/ids.d.ts +2 -0
  323. package/dist/util/json.d.ts +37 -0
  324. package/dist/util/log.d.ts +6 -0
  325. package/dist/util/text.d.ts +21 -0
  326. package/dist/util/version.d.ts +2 -0
  327. package/package.json +175 -3
@@ -0,0 +1,103 @@
1
+ import type { ThinkingEffort } from '../../llm/index.js';
2
+ import type { ReadonlyJsonValue } from '../../util/json.js';
3
+ import type { WorkflowDefinition } from './definition.js';
4
+ import { type AssignmentState, type InstanceState, type PendingDecision, type ResultDecision } from './fold.js';
5
+ import type { StartState } from './participants.js';
6
+ import { type Citation } from './record.js';
7
+ import { type Barrier } from './routing.js';
8
+ import type { ReadonlyState } from '../../util/foldState.js';
9
+ /** An instance as a host reads it (§9 of the design): derived at each read, never recorded. */
10
+ export type InstanceView = {
11
+ /** The id of the definition it runs by, recorded at opening. */
12
+ readonly definition: string;
13
+ /** The instance's input, recorded at opening: what a host compares a repeated start with. */
14
+ readonly input: ReadonlyJsonValue;
15
+ /**
16
+ * Each isolated participant's model as its opening pinned it, the definition's or the starter's
17
+ * choice: what a host compares a repeated start's models with.
18
+ */
19
+ readonly models: Readonly<Record<string, {
20
+ readonly provider: string;
21
+ readonly model: string;
22
+ readonly thinkingEffort: ThinkingEffort | null;
23
+ }>>;
24
+ readonly status: 'running' | 'waiting' | 'blocked' | 'completed' | 'cancelled';
25
+ /** The step being worked or decided; `null` once the instance ended. */
26
+ readonly step: string | null;
27
+ readonly attempt: {
28
+ readonly id: string;
29
+ readonly ordinal: number;
30
+ } | null;
31
+ readonly assignments: readonly {
32
+ readonly id: string;
33
+ readonly participant: string;
34
+ readonly state: AssignmentState;
35
+ /** The thread it runs in: the root, or the isolated participant's child. */
36
+ readonly thread: string;
37
+ /** The delegation task an isolated participant works it as; `null` for the root's own. */
38
+ readonly task: string | null;
39
+ /** The participant generation an isolated assignment was pinned to; `null` for the root's own. */
40
+ readonly generation: number | null;
41
+ }[];
42
+ readonly results: readonly {
43
+ readonly revision: string;
44
+ readonly step: string;
45
+ readonly outputs: Readonly<Record<string, ReadonlyJsonValue>>;
46
+ readonly decision: ResultDecision | null;
47
+ /** Neither retired by its step's re-entry nor stale through what it was bound to. */
48
+ readonly current: boolean;
49
+ /** The inputs its attempt bound at entry. */
50
+ readonly inputs: Readonly<Record<string, Citation | null>>;
51
+ }[];
52
+ readonly pending: PendingDecision | null;
53
+ readonly blocked: null | {
54
+ readonly reason: 'missing-binding' | 'entry-refused' | 'cleanup';
55
+ readonly detail: string;
56
+ };
57
+ readonly waitingOn: null | 'decision' | 'dispatch' | 'participant' | 'cleanup' | 'person-input';
58
+ };
59
+ /**
60
+ * What the view reads besides the root's rows: the evidence barrier an admitted cancellation, or a
61
+ * pending recovery, waits on, as the commands and delegations plugins answer it now; whether the
62
+ * root is settled (idle or held), so an open assignment of its own waits on a person; where its
63
+ * isolated assignments' starts stand; and what the providers it pinned say now.
64
+ */
65
+ export type RootFacts = {
66
+ readonly barrier: Barrier;
67
+ readonly settled: boolean;
68
+ /** Where each open isolated assignment's start stands, by assignment (`Participants.states`). */
69
+ readonly starts: ReadonlyMap<string, StartState>;
70
+ /**
71
+ * Why a provider cannot serve the instance's pin now (see `Providers.problem`), or `null`: a check
72
+ * provider by the participant whose assignments list it, an evidence provider by its name.
73
+ */
74
+ readonly provider: (binding: {
75
+ readonly check: string;
76
+ readonly participant: string;
77
+ } | {
78
+ readonly evidence: string;
79
+ }) => string | null;
80
+ /** The latest refusal of an automatic transition's entry over evidence acquired for it, if any. */
81
+ readonly entryRefusal: {
82
+ readonly transition: string;
83
+ readonly reason: string;
84
+ } | null;
85
+ };
86
+ /**
87
+ * The instance as a host reads it, derived from recorded facts and what is registered now
88
+ * (`registered`, looked up by the recorded id). Without a definition it can continue on
89
+ * ({@link heldBy}), execution is blocked (`missing-binding`, with why): the recorded copy still
90
+ * renders results and pending subjects, but no decision is offered; a terminal instance stays
91
+ * terminal. An admitted cancellation waits on its
92
+ * cleanup (`cleanup`), whatever is registered, and is `blocked` on it once a command's stop failed
93
+ * or its termination is unknown; a pending recovery likewise, offering no verdict until its cleanup
94
+ * is established. `waitingOn` is `person-input` while the root's own assignment is open and the
95
+ * root is settled: idle, held by a Stop, or failed, whether a candidate's check is still owed, a
96
+ * rejection or a spent reminder left it active, or its activation input is gone; otherwise
97
+ * `dispatch` while an open isolated assignment's task is not started yet (its start in flight, or
98
+ * waiting for a slot or its conversation's previous task), and `participant` while isolated
99
+ * participants work their started tasks. A start held (a binding it runs on unavailable, a pinned
100
+ * configuration its child conflicts with) blocks the instance (`missing-binding`), as a missing
101
+ * provider does.
102
+ */
103
+ export declare function instanceView(state: ReadonlyState<InstanceState>, registered: WorkflowDefinition | undefined, root: RootFacts): InstanceView;
@@ -0,0 +1,21 @@
1
+ import type { Context } from '@leuduan/cordis';
2
+ import { type CommandWork } from '../commands/index.js';
3
+ import type { Origins } from '../../journal/index.js';
4
+ /**
5
+ * What stands between the threads `scope` names, under `threadId` and including it, and their end,
6
+ * each item saying why, as the plugins that own that work answer it from durable evidence whether or
7
+ * not they are mounted: `draining`, work that is ending or will end on its own (a command running or
8
+ * stopping, a sub-agent's task open, draining a late turn or being cleaned up, a stop obligation not
9
+ * yet acknowledged); `unresolved`, work whose end nothing establishes (a command whose end is not
10
+ * known, a task or command record that cannot be read). Both empty: everything there is known to
11
+ * have ended. A stop obligation on `threadId` outside `scope` counts while it targets a thread in it.
12
+ * What submission's quiescence, cancellation's cleanup and a recovery's barrier read before
13
+ * certifying quiet.
14
+ */
15
+ export declare function workUnder(ctx: Context, threadId: string, scope: ReadonlySet<string>): CommandWork;
16
+ /**
17
+ * `threadId` and every thread its work started, at any depth: under the instance's `root`, neither
18
+ * the root's isolated participants nor anything under them, which are the workflow's work, not the
19
+ * root's.
20
+ */
21
+ export declare function ownWork(origins: Origins, threadId: string, root: string): Set<string>;
@@ -0,0 +1,38 @@
1
+ import type { Plugin } from '@leuduan/cordis';
2
+ import { z } from 'zod';
3
+ declare const WorkspaceSchema: z.ZodObject<{
4
+ cwd: z.ZodString;
5
+ read_roots: z.ZodArray<z.ZodString>;
6
+ }, z.core.$strict>;
7
+ /** Where a thread works: its `cwd` and the read roots beyond it. */
8
+ export type Workspace = z.output<typeof WorkspaceSchema>;
9
+ /**
10
+ * Briefs an agent on where it works: its thread's `cwd`, the read roots its environment names and
11
+ * the operating system.
12
+ *
13
+ * Only the operating system goes into the prompt, which is recorded once and must not depend on
14
+ * which thread it is (see `PromptRenderInput`). The working directory and the read roots are told as
15
+ * a conversation message at the next model step that is already due, whenever they differ from the
16
+ * latest notice the model can still see: on its first step, again if they change, and again after a
17
+ * replacement took that notice off the surface. The cached part of the request ahead of the history
18
+ * is never rewritten, and threads in one workspace are told the same notice.
19
+ *
20
+ * Every notice is the whole workspace, with a working directory that moved since the notice the
21
+ * model can still see noted as previously, so the latest visible notice establishes all of it. A
22
+ * fork inherits what its source was told, so it is told again only when its workspace differs.
23
+ *
24
+ * It deliberately says nothing that changes while the thread lives — no directory listing, no git
25
+ * status, no date. An agent that needs the layout lists it with its tools.
26
+ *
27
+ * Mounted on the root it briefs every thread; mounted through `thread.ctx` it briefs that thread
28
+ * only. The notice is per thread, so it reaches a role child too; the prompt section is for every
29
+ * global agent, so it does not.
30
+ */
31
+ export declare const workspaceContext: Plugin.Object<undefined>;
32
+ /**
33
+ * What a thread is told: its whole workspace, every time, with a working directory that differs
34
+ * from `told`, the notice the model can still see, noted as previously.
35
+ */
36
+ export declare function renderWorkspaceNotice(workspace: Workspace, told: Workspace | null): string;
37
+ export declare function renderEnvironmentInfo(): string;
38
+ export {};
@@ -0,0 +1 @@
1
+ import{a,b,c}from"../chunks/ADHERZLW.js";import"../chunks/RK3VP2Q4.js";import"../chunks/DRYAN665.js";import"../chunks/2OSESBIL.js";import"../chunks/YLNJXQ3Z.js";import"../chunks/DDANMY45.js";import"../chunks/37YOGDGY.js";import"../chunks/KESCTXGO.js";import"../chunks/TYTQRLTX.js";import"../chunks/D7E6EWIE.js";export{c as renderEnvironmentInfo,b as renderWorkspaceNotice,a as workspaceContext};
@@ -0,0 +1,7 @@
1
+ import type { AgentDefinitionInput } from '../models/index.js';
2
+ /** The builtin tools define these; the compositions here name them. */
3
+ export { READ_ONLY_TOOLS, WEB_TOOLS } from '../plugins/tools/index.js';
4
+ /** Tools that create or modify files. */
5
+ export declare const WRITE_TOOLS: readonly ["edit_files"];
6
+ /** `base`'s one agent, registered with no grants: a preset equips it. */
7
+ export declare const mainAgent: AgentDefinitionInput;
@@ -0,0 +1,10 @@
1
+ import type { Plugin } from '@leuduan/cordis';
2
+ /**
3
+ * The plumbing a host mounts on the root beside `core` and a provider: one
4
+ * `main` agent, granted nothing; the workspace notice; output truncation; and writes and started
5
+ * commands held for confirmation. It registers no tools and decides nothing about what an agent
6
+ * can do: a host registers the tools beside it, ungranted (`builtinTools`, `commands`), and a preset
7
+ * such as `codexPreset` grants them. Root-only, since it registers an agent; mount it before any
8
+ * thread activates.
9
+ */
10
+ export declare const base: Plugin.Object<undefined>;
@@ -0,0 +1,60 @@
1
+ import { z } from 'zod';
2
+ export declare const CodexPresetConfigSchema: z.ZodObject<{
3
+ explore: z.ZodPrefault<z.ZodObject<{
4
+ web: z.ZodDefault<z.ZodBoolean>;
5
+ }, z.core.$strict>>;
6
+ agentsMd: z.ZodObject<{
7
+ fileNames: z.ZodArray<z.ZodString>;
8
+ rootMarkers: z.ZodArray<z.ZodString>;
9
+ maxBytes: z.ZodNumber;
10
+ }, z.core.$strict>;
11
+ }, z.core.$strict>;
12
+ /** The explorer's role id, which is also the agent its children run on. */
13
+ export declare const EXPLORE_ROLE_ID = "codex.explore";
14
+ /** The general sub-agent's role id, which `delegate` starts. */
15
+ export declare const GENERAL_ROLE_ID = "codex.general";
16
+ /** The reviewer's role id, which `review` starts. */
17
+ export declare const REVIEW_ROLE_ID = "codex.review";
18
+ /**
19
+ * Equips a thread's agent for autonomous coding: the workspace tools that read and write, shell
20
+ * commands, web fetch and search, skills, questions to the user, the route notice, the date and
21
+ * branch at the start of each turn (`dateAndBranch`, for the agents it equips and not handed down),
22
+ * one `subAgents` with four endpoints, an `explore` sub-agent that only reads, a `delegate`
23
+ * sub-agent with a fresh context for a self-contained task, a `fork` of the caller, and a `review`
24
+ * sub-agent with the general sub-agent's tools and a reviewer's persona (`workerTools`),
25
+ * `message_agent`, `list_agents`, `read_agent` and `stop_agent` to continue, list, read and stop any
26
+ * of them, and a coding prompt that replaces the agent's base prompt. A sub-agent's role is frozen
27
+ * on it, so a reviewer continued with `message_agent` stays a reviewer; nothing but its prompt keeps
28
+ * it from repairing, and the host's permission policy decides what its calls may do.
29
+ * It grants the builtin tools, the command tools, `skill` and the `delegations` tools rather than
30
+ * registering them: it relies on the host registering `builtinTools`, `commands`, `skills` and
31
+ * `delegations` on the root, where its endpoints also find the tools they grant their children, and
32
+ * mounting the `ask` service there, which `ask_question` asks through and refuses to mount without.
33
+ * `skills` searches the host's skill roots, which a configuration may not record, so codex refuses
34
+ * to mount without it. The `subAgents` codex mounts refuses to mount without `delegations`, which
35
+ * owns every delegation and registers its tools.
36
+ *
37
+ * It equips the agent of the thread it is placed on: installed there, mounted from the setup of a
38
+ * host preset placed there, or chosen by a root mount for an agent selector.
39
+ *
40
+ * Repository instructions (`agentsMd`): it tells its thread. Installed, its own installation or the
41
+ * host preset's that mounts it, it also hands the `agents-md` preset down with the same settings, so
42
+ * every sub-agent the thread starts, the explorer included, and their children in turn, are told
43
+ * too; so it refuses to mount unless `agentsMdPreset` is registered. Selected, it hands nothing
44
+ * down, since a selection is process policy rather than the thread's recorded choice: a child is
45
+ * then told only if a root selector reaches its agent.
46
+ *
47
+ * Safe per thread: tools, grants, prompt sections and step listeners, all in the thread's own
48
+ * layer. A thread records its prompt when it first runs, so an installation applied later adds its
49
+ * tools but not its prompt sections.
50
+ */
51
+ export declare const codexPreset: import("../services/preset.js").Preset<z.ZodObject<{
52
+ explore: z.ZodPrefault<z.ZodObject<{
53
+ web: z.ZodDefault<z.ZodBoolean>;
54
+ }, z.core.$strict>>;
55
+ agentsMd: z.ZodObject<{
56
+ fileNames: z.ZodArray<z.ZodString>;
57
+ rootMarkers: z.ZodArray<z.ZodString>;
58
+ maxBytes: z.ZodNumber;
59
+ }, z.core.$strict>;
60
+ }, z.core.$strict>>;
@@ -0,0 +1,4 @@
1
+ export * from './agents.js';
2
+ export * from './base.js';
3
+ export * from './codex.js';
4
+ export * from './prompts.js';
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The prompt text `codexPreset` contributes, its sub-agents' included, adapted from Codex CLI's base
3
+ * instructions and its model templates. Each block is exported so a consumer can reuse one in an
4
+ * agent of its own. None assumes how an answer is drawn: a host whose renderer has rules of its own,
5
+ * such as which diagrams or images it shows, contributes a section saying so.
6
+ */
7
+ export declare const CODE_ROLE_PROMPT = "You are a coding agent working in the user's workspace. You and the user share its files: with the tools you are given, you read, search and change them and run commands there. Your job is to carry the user's task through to a result they can review.";
8
+ export declare const AUTONOMY_PROMPT = "- Carry the task through to the end within the turn: understand it, make the change, validate it, and report. Do not stop at analysis, a proposal or a half-finished fix.\n- Unless the user asks a question, asks for a plan or a review, or is brainstorming, assume they want the change made, and make it rather than describe it.\n- When you hit a blocker, try to work through it yourself first. Ask the user, with ask_question, only when the answer changes what you would do and you cannot find it out yourself.\n- Do not guess or make up an answer: read the code, run the command, look it up.\n- Messages may arrive while you work. When they conflict, the newest one steers; otherwise honour every request since your last answer, and make sure your final answer responds to the newest.";
9
+ export declare const PREAMBLES_PROMPT = "Before a group of related tool calls, write one short line saying what you are about to do, and after the first, how it follows from what you found; for example \"The loader is in src/config.ts; now checking its callers.\" Group related calls under one line instead of narrating each, and write none before a trivial read. Before a large edit, say what you are changing.";
10
+ export declare const CODEBASE_PROMPT = "- Read the code you are about to change, and let it show you how to change it: follow the repository's existing patterns, helpers and style.\n- Fix the problem at its root cause rather than patching the symptom, and keep the solution as simple as the problem allows. Add an abstraction only when it removes real complexity.\n- Follow the AGENTS.md files you are told for the files you touch. Each governs its directory's tree and the deeper one wins on a conflict; the user's direct instructions beat any of them. Working below your working directory, look for AGENTS.md there too.\n- Keep the change to what the task needs. Do not fix unrelated bugs or failing tests; mention them in your final answer.\n- Update the documentation your change makes wrong.\n- Default to ASCII in files, and add a comment only where the code does not explain itself.\n- Never add copyright or licence headers unless asked. Do not commit or create branches unless asked.";
11
+ export declare const EDITING_PROMPT = "- Make every change to a file with edit_files: creating, updating, moving or deleting it. Never write a file through a command, such as a shell heredoc, `echo >`, `sed -i` or a script; running the project's own formatter or code generator is fine.\n- Read the lines you change before editing them: an edit's old text must match the file as it is now.\n- edit_files answers with the diff it applied. Trust it, and do not re-read the file to check.\n- If an edit is interrupted, or applies only some of its files, re-read the files it named before editing them again.";
12
+ export declare const DIRTY_WORKTREE_PROMPT = "The worktree may hold changes you did not make. Assume they are the user's, and never revert them unless asked.\n- Leave changes unrelated to your task alone.\n- In files you are working on, read the changes carefully and work with them.\n- Never run `git reset --hard`, `git checkout --`, `git restore`, `git clean` or anything else that discards changes unless the user clearly asked for that operation; when the request is ambiguous, ask first.\n- If those changes make your task impossible, ask the user how to proceed.";
13
+ export declare const VALIDATION_PROMPT = "- When the project can be built or tested, use that to check your work. Start with the tests closest to what you changed, then widen as you gain confidence.\n- Let coverage scale with risk: focused for a narrow change, broader when the change touches shared behaviour, contracts between modules, or what users do.\n- Add a test where the codebase has an obvious place for one. Do not add a test suite or a formatter to a repository that has none, and do not write tests that only mirror the implementation.\n- Run the project's formatter and linter on the files you changed when it has them.\n- A failure your change did not cause is not yours to fix: mention it.";
14
+ /** The delegation section: when to hand work to a sub-agent, and how. */
15
+ export declare const DELEGATION_PROMPT = "- Independent tool calls can run in parallel: make every call that does not need another's result in the same response. When a call depends on an earlier one's output, wait for that result first.\n- Hand work to a sub-agent when you do not need to see its steps, so your conversation keeps only its outcome:\n - explore: find and understand things in the workspace, such as where something is handled, how a module works or what a change would affect. It only reads.\n - delegate: a self-contained task that needs nothing from this conversation but the task you write, including one that changes files or runs commands, such as updating every call site of a function and making the tests pass, or finding out why a command fails and fixing it.\n - fork: a task of several steps that needs your context: answering a question by experiment, working out why something fails, checking whether an approach works.\n - review: a second reading of a change, or of any code, when the user asks for one or a change is large or subtle enough that one helps; never as a routine step. Its findings are evidence: weigh each against the code before acting on it. To get them fixed, delegate the findings with their evidence. Check the repository's status before asking for a review of uncommitted work: an empty change still starts a reviewer.\n- Work directly when one or two calls will do, when you need the raw output yourself (the exact lines you are about to edit, command output you must reason over), when the next step waits on a decision, or when the answer is already in the conversation.\n- Give independent parts separate calls in one response, so they run concurrently. Write each task as an outcome: what to find out or do, and what to return, such as \"the function that validates tokens, with its file and line\" rather than \"look at the auth code\". Explore, delegate and review see only the task you write; a fork sees your conversation too. Either way, name the target (for a review, \"the uncommitted changes\", \"the current work against main\", \"commit abc123\" or the code to read), the outcome you expect, the constraints, and which files you or other sub-agents are changing and which commands share outputs, such as test discovery, a build directory or a server port.\n- Start a review only after the work it reviews has settled, in a later response than the calls that make that work: a waiting call does not stop the others in its response.\n- In a forked task, do the work yourself rather than forking again.";
16
+ export declare const LONG_WORK_PROMPT = "A long task can outgrow your context. The conversation may then be compacted: a checkpoint stands in for the messages it condensed. Compaction does not end the task. Continue from the checkpoint without restarting or redoing finished work, and keep the original objective together with every correction the user made since.";
17
+ /** Added to {@link LONG_WORK_PROMPT} when the agent may call the recall tools. */
18
+ export declare const HISTORY_RECALL_PROMPT = "When you need the exact text of something condensed, such as the user's wording or a command's output, read it back with history_read or find it with history_search rather than reconstructing it.";
19
+ export declare const SAFETY_PROMPT = "- Your file tools read and change files in the working directory and the application data directory, and also read the read roots your workspace notice names. Do not go looking through the rest of the machine, such as other projects or the home directory, unless the task needs it.\n- Avoid destructive or irreversible commands, such as deleting what you did not create, force-pushing or dropping data, unless the user asked for them.\n- Do not push, publish, deploy or send anything to others unless asked.\n- Do not search for, print or copy out secrets such as credentials, API keys and tokens.";
20
+ export declare const AMBITION_PRECISION_PROMPT = "- For a task with no prior context, where the user is starting something new, be ambitious and show creativity in the implementation.\n- In an existing codebase, do exactly what the user asks with surgical precision. Treat the surrounding code with respect and do not overstep, for example by renaming files or variables unnecessarily, while still being proactive enough to finish the task well.\n- Use judicious initiative to choose the right level of detail and complexity for the user's needs: high-value, creative touches when the scope is vague; surgical, targeted work when it is tightly specified; no gold-plating either way.";
21
+ export declare const FINAL_ANSWER_PROMPT = "- Lead with the outcome, then give what the user needs to trust it and act on it, like a concise teammate handing off work.\n- Size the answer by the change: a sentence or two for a small fix, a short walkthrough grouped by theme for a large one, a plain conversational reply to a casual question. Even a large one keeps to the points that matter, well under fifty lines.\n- Say what you ran to validate the work, and what you did not run and why.\n- Point to code as `path:line`, with the path relative to the working directory and a single line rather than a range.\n- Do not paste before-and-after code or the contents of files you wrote: the user has the files. Never ask them to save or copy anything.\n- Mention the problems you noticed but left alone, and anything you could not do.\n- When there is an obvious next step, such as running the wider test suite, committing, or building the next piece, offer it as a short question rather than doing it unasked.";
22
+ export declare const COMMUNICATION_GUIDANCE_PROMPT = "- Write in English unless the user asks for another language.\n- Be direct and concise, and state the assumptions you made. Leave out flattery, filler and needless apologies.\n- Use plain characters: no emoji unless asked, and no look-alike or invisible Unicode, such as an en dash for a hyphen.";
23
+ /** Markdown conventions any renderer draws; what a particular one adds is its host's to say. */
24
+ export declare const FORMATTING_PROMPT = "- Answer in Markdown, with only as much structure as helps: short paragraphs by default, flat lists for parallel items, and a heading only when a long answer has distinct parts.\n- Put code, commands and multi-line output in fenced code blocks labelled with their language.\n- Wrap file paths, commands, environment variables and code identifiers in backticks.";
25
+ /**
26
+ * The explorer's base prompt, naming the search tools only when `has` says they are registered: they
27
+ * are provided only where the host has `rg`.
28
+ */
29
+ export declare const exploreRolePrompt: (has: (tool: string) => boolean) => string;
30
+ export declare const EXPLORE_TOOL_DESCRIPTION = "Sub-agent that explores the workspace without changing it: codebase exploration, file discovery and code understanding. It reports its findings.";
31
+ export declare const FORK_TOOL_DESCRIPTION = "Fork yourself to execute one sub-task in isolation. The forked thread gets a clone of your current conversation context, executes the task independently, and its result is returned to you. Use this when you want to 'clone yourself' to do a sub-task without polluting your main conversation thread. Call this tool once per task; several calls in one response run concurrently.";
32
+ export declare const FORKING_PROMPT = "Sub-agents inherit your permissions and share your working directory. Give sub-agents that run at the same time disjoint files to write, or let only one of them write; disjoint files still share test discovery, build output and ports, so do not run tests or builds in two of them at once.";
33
+ /** The general sub-agent's opening: one delegated task, and no view of the caller's conversation. */
34
+ export declare const GENERAL_ROLE_OPENING = "You are a sub-agent: another agent handed you one task, which you carry out in the user's workspace with the tools you are given, reading, searching and changing its files and running commands there. You do not see the conversation that led to the task: the task is all you know of it. Your answer goes back to the agent that asked, not to the user.";
35
+ /** What every sub-agent codex starts with tools follows, since it answers an agent and cannot ask the user. */
36
+ export declare const SUB_AGENT_RULES_PROMPT = "- Where these instructions say to ask the user, you cannot: stop there, and put the question in your answer, with what you found and what each answer would change.\n- Before you answer, wait for every background command whose result you rely on, and stop every background command you started.";
37
+ /** How the general sub-agent answers: the whole of what its caller gets back. */
38
+ export declare const SUB_AGENT_ANSWER_PROMPT = "Your answer is all the agent that asked gets back, so make it complete on its own:\n- Lead with the outcome: what you did, or what you found.\n- Point to code as `path:line`, with the path relative to the working directory.\n- Say what you ran to check it, each command exactly, and what it showed.\n- Say what is left undone, what you could not do, and what you are unsure of.";
39
+ /** The reviewer's opening, adapted from Codex CLI's review rubric (\`prompts/templates/review/rubric.md\`). */
40
+ export declare const REVIEW_ROLE_OPENING = "You are a code review sub-agent: another agent asked you for a second reading of code in the user's workspace, a change or code as it stands, and you report the problems you find, with their evidence. You do not see the conversation that led to the task: the task names what to review and anything to focus on. Your answer goes back to the agent that asked, not to the user.";
41
+ /** What the reviewer reads, and how it may gather evidence without repairing anything. */
42
+ export declare const REVIEW_EVIDENCE_PROMPT = "- Read the change with git through run_command: a diff of the uncommitted changes, of the current work against a branch's merge base, or of one commit, with the repository's status and log. Note which commits you compared. Read the code around each change, and the code that depends on it, as far as you need to judge it. When the task names code rather than a change, review that code as it stands.\n- Review and report; do not fix. Run a command only when a finding needs the evidence: an existing test, the type checker, a linter, or a small reproduction. Prefer existing tests.\n- When a check needs a file inside the repository, create a new, uniquely named file with edit_files. Never change a file that existed before you started, the user's untracked files included.\n- Clean up what you created. Just before deleting a temporary file, read it again, and delete it only if it is still exactly what you wrote. Never restore the workspace wholesale, such as with `git checkout`, `git restore`, `git stash` or `git clean`.\n- Running tests writes caches and build output, which is fine: what you keep intact is the user's work.\n- When the target is a commit, or anything but the current work, your commands run on the checkout, not on the reviewed revision. Say which HEAD and which local changes they ran on, and do not claim that a check passing there shows the reviewed revision passes.\n- If files your findings rely on change while you review, check those findings again, or mark them uncertain.";
43
+ /** What the reviewer flags and how it reports, adapted from Codex CLI's review rubric. */
44
+ export declare const REVIEW_RUBRIC_PROMPT = "Flag a problem only when all of these hold:\n- It meaningfully affects the correctness, performance, security or maintainability of the code.\n- It is discrete and actionable: one issue, not a remark about the codebase in general or several issues together.\n- When the task names a change, the change introduced it: problems that were there before are not flagged. When it names code, the problem is in that code.\n- You can show it from the code or from what you ran. Speculating that something may break elsewhere is not enough: name the code that is affected. It must not rest on assumptions about the codebase or the author's intent that you have not stated.\n- It is clearly not a deliberate choice, and the author would fix it if they knew.\n- Fixing it does not demand more rigour than the rest of the codebase shows.\n\nIgnore style, formatting, naming and typos unless they hide a bug or break a rule the repository's AGENTS.md files state. When a rule supports a finding, cite the AGENTS.md file and line it comes from.\n\nReport every finding the author would want to fix, not only the first; when nothing clearly qualifies, report none. For each finding:\n- A short title tagged with its priority: [P0] blocks a release or major use, whatever the inputs; [P1] urgent, for the next cycle; [P2] normal, to fix eventually; [P3] low, nice to have.\n- Its location as `path:line` in the reviewed code, with the path relative to the repository, keeping the range as short as possible.\n- One short paragraph saying why it is a problem and the inputs, scenarios or environments it needs, so its severity is clear, and the evidence: what you read or ran. Claim no more severity than it has, quote no more than three lines of code, and keep the tone matter-of-fact, with no praise.\n\nWhen the task asks for a design assessment, alternatives or improvements, give them after the findings, under a heading of their own, apart from the problems you showed. When it asks for a severity scale or an output format, follow it instead of these.\n\nEnd with:\n- the scope you reviewed, and for a git target the commits you compared;\n- the checks you ran, each command exactly, with its result;\n- every experiment, what it left behind, and where its reproduction is kept, with how to run it;\n- the limits of the review: what you did not read or could not check.\nThen a one-line verdict: whether the reviewed code is correct, meaning existing code and tests will not break and it has no blocking problem. Non-blocking issues such as style do not count against it. \"No qualifying findings\" is not a guarantee of correctness: when you found none, say so plainly, with what you covered.\n\nAnswer in plain text, not JSON. The task may narrow what to look at, and the repository's AGENTS.md files may add rules; both take precedence over these guidelines.";
45
+ /**
46
+ * The general sub-agent's base prompt: one delegated task, carried out with the workspace, command,
47
+ * web and skill tools, by codex's own working rules, answered to the agent that asked.
48
+ */
49
+ export declare const GENERAL_ROLE_PROMPT: string;
50
+ /**
51
+ * The reviewer's base prompt: the same tools as the general sub-agent, used to gather evidence, never
52
+ * to repair; none of the blocks that tell an agent to fix, document or add tests.
53
+ */
54
+ export declare const REVIEW_ROLE_PROMPT: string;
55
+ export declare const DELEGATE_TOOL_DESCRIPTION = "Sub-agent that carries out one self-contained task in the workspace with a fresh context: it reads, changes files, runs commands, and reports what it did and found. It sees only the task you write, not this conversation, so state the target, the outcome you expect and any constraints.";
56
+ export declare const REVIEW_TOOL_DESCRIPTION = "Sub-agent that reviews code in the workspace with a fresh context: a change (the uncommitted changes, the current work against a branch such as main, or one commit) or code as it stands. It may run tests and reproductions to gather evidence, changes nothing of yours, and reports the problems it can show, each tagged [P0] to [P3] at a file and line. Name the target and any focus in the task.";
@@ -0,0 +1,32 @@
1
+ import type { Plugin } from '@leuduan/cordis';
2
+ import { z } from 'zod';
3
+ declare const AbsentConfigSchema: z.ZodObject<{
4
+ drainTimeoutMs: z.ZodNumber;
5
+ }, z.core.$strict>;
6
+ export type SandboxAbsentConfig = z.input<typeof AbsentConfigSchema>;
7
+ /**
8
+ * For a host that records sandbox modes but started without the sandbox. A process with no launch
9
+ * handler would run every command plain, so a conversation recorded as confined would run unconfined
10
+ * silently after such a restart. This is the launch handler of core's `ctx.launches` for that host,
11
+ * which is what makes the refusal cover every caller of the seam, `commands` and a host calling
12
+ * `ctx.launches` directly alike: a launch for a conversation recorded as confined is refused with a
13
+ * message for the model, and a launch for one recorded as unconfined, or with no mode at all, runs as
14
+ * plain `/bin/sh -c` with provenance that says so (`unconfined`, under this plugin's own launcher),
15
+ * which a host's display marks. The model is told through the sandbox's notice: the unavailable
16
+ * guidance when confined, and the lift a restart may have left owed otherwise.
17
+ *
18
+ * The refusal happens when the launch is prepared, after any confirmation the tool call needed, so
19
+ * a call a person approved can still be refused: rare, since the notice says so at the first step.
20
+ * It does not cover what spawns outside the seam: MCP stdio servers and lagent's own spawns.
21
+ *
22
+ * The recorded mode is read once, when preparation starts, from the journal's fold, which needs the
23
+ * thread's history loaded: a tool call has it, and a host launching directly must keep it so. A thread
24
+ * the journal does not hold, a caller chain that does not reach its conversation root and a mode row
25
+ * this build cannot read refuse the launch with that error, never allow it.
26
+ *
27
+ * Mount it unscoped, after `core` and before threads start, so a failed composition is refused before
28
+ * recovery. It excludes `sandbox` in either mount order. Disposing it releases its handler, which
29
+ * stops every command it let run, within `drainTimeoutMs`.
30
+ */
31
+ export declare const sandboxAbsent: Plugin.Object<SandboxAbsentConfig>;
32
+ export {};
@@ -0,0 +1,39 @@
1
+ import type { WorkerMessage, WorkerValues } from './protocol.js';
2
+ /**
3
+ * The main thread's end of the sandbox worker: it owns the thread and every request in flight. A
4
+ * request has an id and a deadline; a worker that errors or exits rejects every request at once and
5
+ * tells `onDeath` once, and a reply that arrives for a request already settled is dropped. Nothing
6
+ * here knows what the messages mean.
7
+ */
8
+ export declare class WorkerClient {
9
+ private readonly worker;
10
+ private readonly pending;
11
+ private nextId;
12
+ private ended;
13
+ private closing;
14
+ private readonly onDeath;
15
+ /**
16
+ * Starts the worker with exactly `env`, which it never inherits. `onDeath` runs once when the
17
+ * worker ends other than through {@link terminate}.
18
+ */
19
+ constructor(entry: URL | string, env: Record<string, string>, onDeath: (error: Error) => void);
20
+ get alive(): boolean;
21
+ /**
22
+ * Sends `message` and resolves with its reply. Rejects at `timeoutMs`, when `signal` aborts, or
23
+ * when the worker ends; the first two also ask the worker to abandon the work.
24
+ */
25
+ request<M extends WorkerMessage & {
26
+ type: keyof WorkerValues;
27
+ }>(message: M, options: {
28
+ timeoutMs: number;
29
+ signal?: AbortSignal;
30
+ }): Promise<WorkerValues[M['type']]>;
31
+ /** Ends the worker on purpose: pending requests reject, and `onDeath` is not told. */
32
+ terminate(): Promise<void>;
33
+ /** Lets the process exit while the worker still runs: for a worker kept after a failed drain. */
34
+ unref(): void;
35
+ private send;
36
+ private settle;
37
+ private end;
38
+ private rejectAll;
39
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What the sandbox keeps on disk under its temporary root, which no command may write: the
3
+ * worker's private directory and the per-key scratch directories. Created by the host, never by a
4
+ * confined process, and never through a link.
5
+ */
6
+ /** The directory the worker runs in: sandbox-runtime's socket files and the published Java agent. */
7
+ export declare const privateDirectory: (tmpRoot: string) => string;
8
+ /** A key's temporary directory. The hash gives every key one safe, fixed-length segment of its own. */
9
+ export declare const scratchPath: (tmpRoot: string, key: string) => string;
10
+ /** `<tmpRoot>` and `<tmpRoot>/.srt`, created. */
11
+ export declare function ensurePrivateDirectory(tmpRoot: string): string;
12
+ /** The scratch directory of `key`, created. */
13
+ export declare function ensureScratchDirectory(tmpRoot: string, key: string): string;
14
+ /**
15
+ * Removes the socket files sandbox-runtime left in `directory` for host processes that are gone,
16
+ * which a SIGKILL leaves behind, and nothing else. Returns what it removed.
17
+ */
18
+ export declare function removeDeadSockets(directory: string): string[];
19
+ /**
20
+ * Publishes the Java agent into `directory` as `srt-proxy-agent-<sha256>.jar`, the one a JVM in the
21
+ * sandbox loads. Several hosts may share a temporary root, so a name is never rewritten: the bytes
22
+ * go to a temporary name and are linked into place, which fails rather than replace, and a file
23
+ * already there is reused only after its digest checks.
24
+ */
25
+ export declare function publishJar(directory: string, source: string): {
26
+ path: string;
27
+ sha256: string;
28
+ };
@@ -0,0 +1,49 @@
1
+ import type { Plugin } from '@leuduan/cordis';
2
+ import { type SandboxConfigInput } from './service.js';
3
+ export { sandboxAbsent, type SandboxAbsentConfig } from './absent.js';
4
+ export { sandboxRecorded, sandboxRecordedOn, type SandboxMode } from './mode.js';
5
+ export { SandboxConfigSchema, type SandboxConfigInput, type SandboxHealth, type SandboxService } from './service.js';
6
+ /**
7
+ * An optional OS sandbox for `run_command` and `start_command`, through Anthropic's sandbox-runtime
8
+ * (`@anthropic-ai/sandbox-runtime`, an optional peer dependency: only the worker module loads it).
9
+ * Mounting `sandbox` registers it as the launch handler of core's `ctx.launches`, so everything
10
+ * `commands` launches afterwards goes through it, and each confined launch is limited to writing its thread's working directory, the host's
11
+ * extra roots and a per-thread temporary directory, and, in `allowlist` network mode, to reaching the
12
+ * host's allowed domains (`unrestricted` leaves the network open: only the filesystem rules bind). A
13
+ * host mounts it before anything launches: once it is registered, no launch runs without it, though a
14
+ * conversation set to run unconfined launches plain through it.
15
+ *
16
+ * Each conversation is confined or unconfined, as its durable mode says: `ctx.sandbox.opening(mode)`
17
+ * records the first choice in the write that creates it, `ctx.sandbox.setMode` switches it, and
18
+ * `ctx.sandbox.mode` is the one effective value, which the host's `unconfined: 'refused'` forces to
19
+ * `confined`. `sandboxRecorded` reads what the journal says, mounted sandbox or not. A host that
20
+ * records modes but starts without the sandbox mounts `sandboxAbsent` instead: the two exclude each
21
+ * other.
22
+ *
23
+ * sandbox-runtime runs on a worker thread of the host, started once per process. The host says
24
+ * where the worker is (`sandboxWorker` from `dist`) and which Java agent to publish
25
+ * (`srtJavaAgentJar()` from `node_modules`); a compiled host embeds both itself.
26
+ *
27
+ * ```ts
28
+ * await root.plugin(sandbox, {
29
+ * worker: sandboxWorker,
30
+ * searchPath: '/usr/bin:/bin:/usr/sbin:/sbin',
31
+ * tmpRoot,
32
+ * javaAgentJar: srtJavaAgentJar(),
33
+ * unconfined: 'allowed',
34
+ * filesystem,
35
+ * network: { mode: 'allowlist', allowedDomains: ['registry.npmjs.org'], deniedDomains: [], parentProxy: 'none' },
36
+ * })
37
+ * await root.plugin(commands, { environment })
38
+ * ```
39
+ *
40
+ * Shell confinement only: the file tools and every other spawn are unchanged. macOS only for now.
41
+ */
42
+ export declare const sandbox: Plugin.Constructor<SandboxConfigInput>;
43
+ /** The worker entry built beside this module, for a host that runs lagent from `dist`. */
44
+ export declare const sandboxWorker: URL;
45
+ /**
46
+ * The JVM proxy agent sandbox-runtime's package ships, for a host that runs from `node_modules`.
47
+ * Resolved when called, so a host without the package fails here and not on import.
48
+ */
49
+ export declare function srtJavaAgentJar(): string;
@@ -0,0 +1,4 @@
1
+ import{a as Q,b as Z}from"../chunks/CDQG7RKA.js";import{c as b}from"../chunks/G6RXC3AL.js";import{b as T,c as z}from"../chunks/GQGNVSKB.js";import{c as J}from"../chunks/DXFXAYDN.js";import{b as V,c as Y,e as K}from"../chunks/DRYAN665.js";import{d as v}from"../chunks/2OSESBIL.js";import"../chunks/YLNJXQ3Z.js";import{d as E}from"../chunks/DDANMY45.js";import{d as X}from"../chunks/37YOGDGY.js";import"../chunks/KESCTXGO.js";import"../chunks/TYTQRLTX.js";import"../chunks/D7E6EWIE.js";import{createRequire as st}from"node:module";import{dirname as it,join as at}from"node:path";import{randomUUID as Ye}from"node:crypto";import{homedir as Ke}from"node:os";import{isAbsolute as O}from"node:path";import{Service as xe}from"@leuduan/cordis";import{z as i}from"zod";import{Worker as Ae}from"node:worker_threads";var A=class{worker;pending=new Map;nextId=1;ended=null;closing=!1;onDeath;constructor(e,n,r){this.onDeath=r,this.worker=new Ae(e,{env:n}),this.worker.on("message",o=>this.settle(o)),this.worker.on("error",o=>this.end(new Error(`The sandbox worker failed: ${o.message}`))),this.worker.on("exit",o=>this.end(new Error(`The sandbox worker exited with code ${o}`)))}get alive(){return this.ended===null&&!this.closing}request(e,n){if(this.ended!==null)return Promise.reject(this.ended);if(this.closing)return Promise.reject(new Error("The sandbox worker is shutting down"));let{signal:r}=n;if(r?.aborted)return Promise.reject(r.reason instanceof Error?r.reason:new Error("aborted"));let o=this.nextId++;return new Promise((s,a)=>{let d=p=>{this.pending.delete(o)&&(clearTimeout(l),c(),e.type==="wrap"&&this.send({type:"cancel",id:o}),a(p))},m=()=>d(r?.reason instanceof Error?r.reason:new Error("aborted")),l=setTimeout(()=>d(new Error(`The sandbox worker did not answer ${e.type} within ${n.timeoutMs} ms`)),n.timeoutMs),c=()=>r?.removeEventListener("abort",m);r?.addEventListener("abort",m,{once:!0}),this.pending.set(o,{resolve:s,reject:a,timer:l,cleanup:c}),this.send({...e,id:o})})}async terminate(){this.closing=!0,this.rejectAll(new Error("The sandbox worker is shutting down")),await this.worker.terminate()}unref(){this.worker.unref()}send(e){try{this.worker.postMessage(e)}catch(n){this.end(new Error(`The sandbox worker could not be reached: ${n instanceof Error?n.message:n}`))}}settle(e){let n=this.pending.get(e.id);n!==void 0&&(this.pending.delete(e.id),clearTimeout(n.timer),n.cleanup(),e.ok?n.resolve(e.value):n.reject(new Error(e.error)))}end(e){this.ended===null&&(this.ended=e,this.rejectAll(e),this.closing||this.onDeath(e))}rejectAll(e){let n=[...this.pending.values()];this.pending.clear();for(let r of n)clearTimeout(r.timer),r.cleanup(),r.reject(e)}};import{createHash as M,randomUUID as Se}from"node:crypto";import{existsSync as De,linkSync as ke,lstatSync as te,mkdirSync as ne,readdirSync as _e,readFileSync as q,unlinkSync as re,writeFileSync as $e}from"node:fs";import{join as g}from"node:path";var ee=t=>g(t,".srt"),Re=(t,e)=>g(t,"scratch",M("sha256").update(e).digest("hex"));function L(t){try{ne(t,{mode:448})}catch(n){if(!E(n,"EEXIST"))throw n}let e=te(t);if(!e.isDirectory()||e.uid!==process.getuid?.())throw new Error(`${t} is not a directory owned by this user`)}function oe(t){return ne(t,{recursive:!0,mode:448}),L(ee(t)),ee(t)}function C(t,e){L(g(t,"scratch"));let n=Re(t,e);return L(n),n}function se(t){let e=[];for(let n of _e(t)){let r=/^srt-mux-(\d+)-[0-9a-z]+\.sock$/.exec(n);if(!(r===null||Oe(Number(r[1]))))try{re(g(t,n)),e.push(n)}catch{}}return e}function Oe(t){if(t===process.pid)return!0;try{return process.kill(t,0),!0}catch(e){return E(e,"EPERM")}}function ie(t,e){let n=q(e),r=M("sha256").update(n).digest("hex"),o=g(t,`srt-proxy-agent-${r}.jar`);if(!De(o)){let a=g(t,`.publish-${Se()}.tmp`);$e(a,n,{flag:"wx",mode:292});try{ke(a,o)}catch(d){if(!E(d,"EEXIST"))throw d}finally{re(a)}}if(!te(o).isFile()||M("sha256").update(q(o)).digest("hex")!==r)throw new Error(`${o} exists and is not the Java agent it is named for`);return{path:o,sha256:r}}import{createHash as Ne}from"node:crypto";import{existsSync as ce,realpathSync as de}from"node:fs";import{basename as Pe,dirname as ae,isAbsolute as je,join as x,resolve as Me}from"node:path";var Le=/^(LD_.*|DYLD_.*|BASH_ENV|ENV|SHELLOPTS|BASHOPTS|BASH_FUNC_.*)$/;function le(t){let e=Object.keys(t).filter(n=>Le.test(n));if(e.length>0)throw new Error(`The command sandbox refuses an environment that sets ${e.join(", ")}: they run code before the sandbox holds`)}var H=128*1024;function h(t){let e=Me(t),n=[];for(;!ce(e)&&ae(e)!==e;)n.unshift(Pe(e)),e=ae(e);return x(de.native(e),...n)}var u=t=>({path:t,literal:!0}),Ce=/[*?[\]]/,He=["__GLOBSTAR_SLASH__","__GLOBSTAR__"];function he(t){if(!je(t))throw new Error(`The command sandbox needs an absolute root, not ${t}`);let e=h(t);if(Ce.test(e)||He.some(n=>e.includes(n)))throw new Error(`The command sandbox refuses ${e} as a root: its name holds glob characters, which sandbox-runtime would read as a pattern`);return e}var Ie=[".gitconfig",".gitmodules",".bashrc",".bash_profile",".zshrc",".zprofile",".profile",".ripgreprc",".mcp.json"],Ue=[".vscode",".idea",".claude/commands",".claude/agents"];function We(t){let e=[];for(let n of Ie)e.push(u(x(t,n)),`${t}/**/${n}`);for(let n of Ue)e.push(u(x(t,n)),`${t}/**/${n}/**`);return e.push(u(x(t,".git/hooks")),`${t}/**/.git/hooks/**`),e.push(u(x(t,".git/config")),`${t}/**/.git/config`),e}var Be=["env","which","log","/bin/sh","/usr/bin/sandbox-exec"];function me(t){let e=t.split(":"),n=Be.flatMap(r=>(r.startsWith("/")?[r]:e.map(o=>x(o,r))).filter(o=>ce(o)).map(o=>de.native(o)));return[...e,...n]}function I(t,e,n){let r=(o,s)=>b(o,s)||b(s,o);for(let o of t){let s=e.find(a=>r(a,o));if(s!==void 0)throw new Error(`The command sandbox refuses to let commands write ${o}: it overlaps ${s}, which the sandbox runs before confinement`);if(r(n,o))throw new Error(`The command sandbox refuses to let commands write ${o}: it overlaps the temporary root`)}}function ue(t,e,n){return{allowWrite:[e,...t.allowWrite,n].map(u),denyWrite:[...[...t.denyWrite,t.dataDir,...t.conveniences,"/tmp/claude","/private/tmp/claude",t.privateDirectory].map(u),...We(e)],denyRead:t.denyRead.map(u)}}var U=['if [ -n "${LAGENT_SANDBOX_PATH+x}" ]; then PATH=$LAGENT_SANDBOX_PATH; export PATH; else unset PATH; fi',"TMPDIR=$LAGENT_SANDBOX_TMPDIR; export TMPDIR",'set -- "$LAGENT_SANDBOX_COMMAND"',"unset LAGENT_SANDBOX_PATH LAGENT_SANDBOX_TMPDIR LAGENT_SANDBOX_COMMAND",'exec /bin/sh -c "$1"'].join("; ");function fe(t,e,n,r){let{PATH:o,...s}=t;return{...s,PATH:e,LAGENT_SANDBOX_TMPDIR:n,LAGENT_SANDBOX_COMMAND:r,...o===void 0?{}:{LAGENT_SANDBOX_PATH:o}}}var S="lagent-srt",Ge="5",pe=t=>`${S}/${Ge} sandbox-runtime/${t}`;function we(t){return`sha256:${Ne("sha256").update(X({...t,bootstrap:U})).digest("hex")}`}function ge(t){let e=t.filesystem.allowWrite.length===0?"":`, in ${t.filesystem.allowWrite.join(", ")}`,{network:n}=t,r=n.mode==="unrestricted"?"They have unrestricted network access.":n.allowedDomains.length===0?"They have no network access.":`They reach the network only through a proxy, and only these hosts: ${n.allowedDomains.join(", ")}; any other host is refused with HTTP 403. Tools that ignore HTTP_PROXY cannot connect. Refused requests are usually, not always, listed after the command's output.`;return[`run_command and start_command run in an OS sandbox. They can write only inside the conversation's working directory${e}, and in $TMPDIR. Writes elsewhere fail with "Operation not permitted", which is all a refused write reports. Inside the working directory, git hooks, .git/config, shell startup files and editor settings cannot be written from a command.`,r,"A refusal is the sandbox, not a fault to work around: say what you needed instead."].join(" ")}import{z as W}from"zod";var f=Z({name:"lagent:sandbox",authority:"conversation",initial:"confined",modes:["confined","unconfined"]});function k(t,e){if(t.journal.summary(e)===void 0)throw new Error(`Unknown thread: ${e}`);return f.recorded(t.journal,f.authorityOf(t,e))}var Fe=(t,e)=>f.recorded(t,e),Xe=W.strictObject({mode:W.enum(["confined","unconfined"]),guidance:W.string().nullable()}),Je=V({plugin:"lagent:sandbox",kind:"notice",version:1,schema:Xe}),ze="The sandbox is off: commands you start from now on run with the user's full permissions and network; commands already preparing or running keep the confinement they started with.",Ve="Commands you start from now on are sandboxed; commands already preparing or running keep how they were launched.",B="The sandbox is unavailable on this host: run_command and start_command are refused for this conversation.";function _(t,e){K(t,{event:Je,agents:"all",rank:1,current:n=>{try{return e(n.threadId)}catch(r){if(r instanceof Q)return;throw r}},render:(n,r,{notices:o})=>{let s=Y(o)?.value??null;return n.mode==="unconfined"?(r??(s?.mode==="confined"?s:null))?.mode==="confined"?ze:null:n.guidance===null?null:n.guidance===B?n.guidance:`${Ve} ${n.guidance}`}})}var D=new WeakMap;function $(t,e){let n=t.reflect.target,r=D.get(n);if(r!==void 0)throw new Error(`${e} cannot mount: ${r} already owns this application's sandbox, and the two exclude each other`);D.set(n,e),t.effect(()=>()=>{D.get(n)===e&&D.delete(n)})}var y=i.string().refine(O,{message:"Expected an absolute path"}),be=i.url({protocol:/^https?$/}).refine(t=>new URL(t).username===""&&new URL(t).password==="",{message:"A parent proxy URL carrying credentials is not supported"}),Ee=i.strictObject({worker:i.union([i.instanceof(URL),i.string().min(1)]),searchPath:i.string().refine(t=>t.split(":").every(O),{message:"Every searchPath entry must be absolute"}),tmpRoot:y,javaAgentJar:y,unconfined:i.enum(["allowed","refused"]),filesystem:i.strictObject({allowWrite:i.array(y),denyRead:i.array(y),denyWrite:i.array(y)}),network:i.discriminatedUnion("mode",[i.strictObject({mode:i.literal("allowlist"),allowedDomains:i.array(i.string().min(1)),deniedDomains:i.array(i.string().min(1)),parentProxy:i.union([i.literal("none"),i.strictObject({http:be.optional(),https:be.optional(),noProxy:i.string().optional()})])}),i.strictObject({mode:i.literal("unrestricted")})]),drainTimeoutMs:i.number().int().positive().default(2e4)});function Qe(t){if(t.mode==="unrestricted")return{deniedDomains:[]};let{parentProxy:e}=t;return{allowedDomains:t.allowedDomains,deniedDomains:t.deniedDomains,...e==="none"?{}:{parentProxy:e}}}function Ze(t,e,n){return t==="allowlist"?e.isCopy?[]:[`sandbox-runtime does not advertise the Java agent copy ${n}`]:e.flags===0?[]:["sandbox-runtime advertises a Java agent although the network is unrestricted"]}var R=3e4,qe=15e3,et=5e3,ye=!1,N=class extends xe{static inject=["threadDirs","launches","journal","threads"];guidance;config;dataDir;state="new";failure=null;admitting=!0;client=null;host=null;handle;releasing=null;constructor(e,n){super(e,"sandbox"),this.dataDir=e.threadDirs.require("sandbox"),v(e,"sandbox"),this.config=Ee.parse(n),this.guidance=ge(this.config),$(e,"sandbox"),_(e,r=>{let o=this.mode(r);return{mode:o,guidance:o==="confined"?this.guidance:null}}),this.handle=e.launches.handle(this),e.fiber.beforeUnload(()=>this.closeAndRelease())}async[xe.init](){try{await this.start()}catch(e){this.state="failed",this.admitting=!1;let n=this.releaseHandle();throw this.announceFailure(),await n,await this.client?.terminate(),this.client=null,e}return()=>this.release()}get unconfined(){return this.config.unconfined}get health(){return this.state==="ready"&&this.admitting?"ready":"failed"}mode(e){return this.config.unconfined==="refused"?"confined":f.of(this.ctx,e)}async setMode(e,n){this.refuseGated(n);let r=this.ctx.journal.summary(e);if(r===void 0)throw new Error(`Unknown thread: ${e}`);if(r.origin!==null)throw new Error(`Thread ${e} is in its conversation's sandbox mode`);await f.set(this.ctx,e,n)}opening(e){return this.refuseGated(e),f.opening(e)}refuseGated(e){if(e==="unconfined"&&this.config.unconfined==="refused")throw new Error("This host refuses unconfined commands")}async prepare(e){if(this.requireOpen(),this.ctx.journal.summary(e.threadId)===void 0)throw new Error(`The command sandbox cannot launch for unknown thread ${e.threadId}`);if(!O(e.workdir))throw new Error(`The command sandbox needs an absolute workdir, not ${e.workdir}`);return this.mode(e.threadId)==="unconfined"?this.plain(e):this.build(e,!1)}plain(e){let n=this.host;if(n===null)throw new Error("The command sandbox is not running");return{argv:["/bin/sh","-c",e.program.shell],cwd:e.workdir,env:e.environment,provenance:{launcher:S,version:n.version,policy:T},violations:async()=>null}}async start(){if(process.platform!=="darwin")throw new Error(`The command sandbox supports macOS only; on ${process.platform}, sandbox-runtime's launches sharing a directory can remove each other's protective mount points`);if(ye)throw new Error("The command sandbox starts once per process: sandbox-runtime keeps process-wide state and is never restarted, so restart the host");ye=!0,this.state="starting";let{config:e}=this,n=h(e.tmpRoot),r=h(this.dataDir);if(b(n,r))throw new Error("tmpRoot must be outside the data directory, which commands may not write");let o=e.searchPath.split(":").map(h).join(":"),s=me(o),a=e.filesystem.allowWrite.map(h);I(a,s,n);let d=e.filesystem.denyWrite.map(h),m=e.filesystem.denyRead.map(h),l=Ke(),c=oe(n);se(c);let p=ie(c,e.javaAgentJar),P=new A(e.worker,{PATH:o,HOME:l,TMPDIR:c,CLAUDE_CODE_TMPDIR:c},j=>this.onWorkerDeath(j));this.client=P;let G=j=>({path:j,literal:!0}),Te={network:Qe(e.network),filesystem:{denyRead:m.map(G),allowWrite:[],denyWrite:[...d,r].map(G)},javaAgentJarPath:p.path},w=await P.request({type:"init",config:Te,expect:{tmpdir:c,home:l}},{timeoutMs:R}),F=[...w.supported?[]:["this platform is not supported"],...w.errors,...w.warnings,...Ze(e.network.mode,w.javaAgent,p.path)];if(F.length>0)throw new Error(`The command sandbox cannot start here: ${F.join("; ")}`);if(this.host={tmpRoot:n,cwd:process.cwd(),home:l,searchPath:o,trusted:s,extraRoots:e.filesystem.allowWrite,facts:{allowWrite:a,denyWrite:d,denyRead:m,dataDir:r,conveniences:w.conveniences,privateDirectory:c},version:pe(w.version),javaAgentSha256:p.sha256},await this.selfCheck(n),!P.alive||this.failure!==null)throw new Error(`The command sandbox worker ended while it started${this.failure===null?"":`: ${this.failure.message}`}`);this.state="ready"}async selfCheck(e){let n=C(e,"self-check"),r=await this.build({program:{shell:"exit 0"},workdir:n,root:n,scratch:"self-check",environment:{},signal:AbortSignal.timeout(R)},!0),o=await J({command:r.argv,cwd:r.cwd,env:r.env,signal:AbortSignal.timeout(R),timeoutMs:R});if(o.exitCode!==0){let s=o.exitSignal===null?`exit code ${o.exitCode}`:`signal ${o.exitSignal}`;throw new Error(`The command sandbox could not run a confined command: ${o.output.trim()||s}`)}}requireOpen(){if(this.state==="failed")throw new Error(`The command sandbox failed${this.failure===null?"":`: ${this.failure.message}`}. Commands cannot run unconfined; it stays failed until lagent restarts.`);if(this.state==="new"||this.state==="starting")throw new Error("The command sandbox is still starting");if(this.state!=="ready"||!this.admitting)throw new Error("The command sandbox is shutting down")}async build(e,n){let r=this.host,o=this.client;if(r===null||o===null)throw new Error("The command sandbox is not running");if(le(e.environment),!O(e.workdir))throw new Error(`The command sandbox needs an absolute workdir, not ${e.workdir}`);if(Buffer.byteLength(e.program.shell)>H)throw new Error(`The command sandbox refuses a command longer than ${H} bytes`);if(process.cwd()!==r.cwd)throw new Error(`The host changed its working directory from ${r.cwd} to ${process.cwd()}: the command sandbox refuses to launch`);let s=he(e.root),a=r.extraRoots.map(h);I(n?a:[s,...a],r.trusted,r.tmpRoot);let d=C(r.tmpRoot,e.scratch),m={...r.facts,allowWrite:a},l=ue(m,s,d),c=Ye();return{argv:["/bin/sh","-c",`exec ${await o.request({type:"wrap",command:U,commandId:c,commandText:e.program.shell.slice(0,1e3),config:{filesystem:l}},{timeoutMs:qe,signal:e.signal})}`],cwd:e.workdir,env:fe(e.environment,r.searchPath,d,e.program.shell),provenance:{launcher:S,version:r.version,policy:we({filesystem:l,network:this.config.network,searchPath:r.searchPath,cwd:r.cwd,home:r.home,conveniences:r.facts.conveniences,javaAgent:r.javaAgentSha256,version:r.version})},violations:()=>this.violationsOf(c)}}async violationsOf(e){if(this.client===null)return null;let n=await this.client.request({type:"violations",commandId:e},{timeoutMs:z});return n.length===0?null:`<sandbox_violations>
2
+ ${n.join(`
3
+ `)}
4
+ </sandbox_violations>`}onWorkerDeath(e){this.failure??=e,this.state==="ready"&&(this.state="failed",this.admitting=!1,this.ctx.reportError(e),this.releaseHandle(),this.announceFailure())}announceFailure(){this.ctx.parallel("lagent/sandbox/health","failed").catch(e=>this.ctx.reportError(e))}async closeAndRelease(){this.admitting=!1,this.state==="ready"&&(this.state="stopping"),await this.releaseHandle()}releaseHandle(){return this.releasing??=this.handle.release(this.config.drainTimeoutMs).then(e=>(e||this.ctx.reportError(new Error(`A command could not be confirmed stopped within ${this.config.drainTimeoutMs} ms: a confined process may still run, so the sandbox worker is kept until the process exits`)),e)),this.releasing}async release(){let e=this.client;if(e!==null){if(!await this.releaseHandle()){e.unref();return}e.alive&&await e.request({type:"reset"},{timeoutMs:et}).catch(()=>{}),await e.terminate(),this.client=null}}};import{z as ve}from"zod";var tt=ve.strictObject({drainTimeoutMs:ve.number().int().positive()}),nt="lagent-sandbox-absent",rt="1",ot={name:"lagent:sandbox-absent",inject:["journal","threads","launches"],apply(t,e){v(t,"sandboxAbsent");let n=tt.parse(e);$(t,"sandboxAbsent");let r=t.launches.handle({async prepare(s){if(k(t,s.threadId)==="confined")throw new Error("This conversation is sandboxed, and the host started without a sandbox, so its commands are refused.");return{argv:["/bin/sh","-c",s.program.shell],cwd:s.workdir,env:s.environment,provenance:{launcher:nt,version:rt,policy:T},violations:async()=>null}}}),o=null;t.fiber.beforeUnload(()=>(o??=r.release(n.drainTimeoutMs).then(s=>(s||t.reportError(new Error(`A command could not be confirmed stopped within ${n.drainTimeoutMs} ms`)),s)),o.then(()=>{}))),_(t,s=>k(t,s)==="confined"?{mode:"confined",guidance:B}:{mode:"unconfined",guidance:null})}};var zt=N,Vt=new URL("./worker.js",import.meta.url);function Yt(){let t=st(import.meta.url).resolve("@anthropic-ai/sandbox-runtime/package.json");return at(it(t),"vendor","java-proxy-agent","srt-proxy-agent.jar")}export{Ee as SandboxConfigSchema,zt as sandbox,ot as sandboxAbsent,k as sandboxRecorded,Fe as sandboxRecordedOn,Vt as sandboxWorker,Yt as srtJavaAgentJar};
@@ -0,0 +1,57 @@
1
+ import type { Context } from '@leuduan/cordis';
2
+ import { z } from 'zod';
3
+ import type { PluginJournal } from '../journal/index.js';
4
+ /**
5
+ * Whether a conversation's shell commands run in the OS sandbox. One vocabulary from lagent to a
6
+ * host's wire; "sandboxed" and "unsandboxed" are a display's words.
7
+ */
8
+ export type SandboxMode = 'confined' | 'unconfined';
9
+ /**
10
+ * The durable mode of each conversation, on its root: a delegated thread is in its conversation's
11
+ * mode, so a sub-agent is never in a mode its conversation is not. Private to this package: the
12
+ * service is its only writer, and `sandboxRecorded` is how a host reads it.
13
+ */
14
+ export declare const sandboxModes: import("../kit/modes.js").Modes<SandboxMode>;
15
+ /**
16
+ * The mode recorded for the conversation `threadId` belongs to, `null` only when none was ever
17
+ * recorded: never the `confined` a thread without a row reads as. For a host deciding what the
18
+ * journal says, whether the sandbox is mounted or not. Throws for a thread the journal does not hold,
19
+ * a caller chain that does not reach its conversation root, and a mode row this build cannot read.
20
+ * Needs the thread's history loaded, as a tool call and a launch it makes already have it.
21
+ */
22
+ export declare function sandboxRecorded(ctx: Context, threadId: string): SandboxMode | null;
23
+ /**
24
+ * The recorded mode in this thread's own fork-lineage fold, without resolving delegation authority:
25
+ * a fork reads what its history recorded up to the cut, and a delegated thread reads its own fold,
26
+ * `null` unless it inherited a row, never its conversation's mode. For a catalog contribution, which
27
+ * is computed from the thread's own folds. A host deciding what the journal says uses {@link sandboxRecorded}.
28
+ */
29
+ export declare const sandboxRecordedOn: (journal: PluginJournal, threadId: string) => SandboxMode | null;
30
+ /** What the model is told about a conversation's shell commands: the mode, and what confined ones may do. */
31
+ declare const SandboxFactSchema: z.ZodObject<{
32
+ mode: z.ZodEnum<{
33
+ unconfined: "unconfined";
34
+ confined: "confined";
35
+ }>;
36
+ guidance: z.ZodNullable<z.ZodString>;
37
+ }, z.core.$strict>;
38
+ export type SandboxFact = z.output<typeof SandboxFactSchema>;
39
+ /**
40
+ * What a confined conversation is told on a host started without a sandbox, where `run_command` and
41
+ * `start_command` are refused for it.
42
+ */
43
+ export declare const ABSENT_GUIDANCE = "The sandbox is unavailable on this host: run_command and start_command are refused for this conversation.";
44
+ /**
45
+ * Tells every agent's threads the fact `current` says at their model steps. The guidance is part of
46
+ * the compared fact, so a changed sandbox file, or a host that lost its sandbox, is told again. A
47
+ * conversation that starts unconfined is told nothing; a lift is still owed when the confined notice
48
+ * that preceded it was compacted away, since its checkpoint may still say confined. Each telling of
49
+ * confinement carries the caveat that launches already preparing or running are not affected.
50
+ */
51
+ export declare function tellSandbox(ctx: Context, current: (threadId: string) => SandboxFact): void;
52
+ /**
53
+ * Claims the root's one sandbox slot for `owner`, released when `ctx` ends. Whichever of `sandbox`
54
+ * and `sandboxAbsent` mounts second fails, in either order, before it registers anything.
55
+ */
56
+ export declare function claimSandbox(ctx: Context, owner: 'sandbox' | 'sandboxAbsent'): void;
57
+ export {};