@aigne/agent-runtime 1.12.0-beta.5

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 (234) hide show
  1. package/LICENSE.md +26 -0
  2. package/README.md +79 -0
  3. package/dist/agent-runners/ai-runner.cjs +133 -0
  4. package/dist/agent-runners/ai-runner.d.cts +33 -0
  5. package/dist/agent-runners/ai-runner.d.cts.map +1 -0
  6. package/dist/agent-runners/ai-runner.d.mts +33 -0
  7. package/dist/agent-runners/ai-runner.d.mts.map +1 -0
  8. package/dist/agent-runners/ai-runner.mjs +134 -0
  9. package/dist/agent-runners/ai-runner.mjs.map +1 -0
  10. package/dist/agent-runners/ash-runner.cjs +272 -0
  11. package/dist/agent-runners/ash-runner.d.cts +30 -0
  12. package/dist/agent-runners/ash-runner.d.cts.map +1 -0
  13. package/dist/agent-runners/ash-runner.d.mts +30 -0
  14. package/dist/agent-runners/ash-runner.d.mts.map +1 -0
  15. package/dist/agent-runners/ash-runner.mjs +273 -0
  16. package/dist/agent-runners/ash-runner.mjs.map +1 -0
  17. package/dist/agent-runners/budget.cjs +71 -0
  18. package/dist/agent-runners/budget.d.cts +40 -0
  19. package/dist/agent-runners/budget.d.cts.map +1 -0
  20. package/dist/agent-runners/budget.d.mts +40 -0
  21. package/dist/agent-runners/budget.d.mts.map +1 -0
  22. package/dist/agent-runners/budget.mjs +67 -0
  23. package/dist/agent-runners/budget.mjs.map +1 -0
  24. package/dist/agent-runners/code-runner.cjs +61 -0
  25. package/dist/agent-runners/code-runner.mjs +61 -0
  26. package/dist/agent-runners/code-runner.mjs.map +1 -0
  27. package/dist/agent-runners/env-whitelist.cjs +36 -0
  28. package/dist/agent-runners/env-whitelist.d.cts +5 -0
  29. package/dist/agent-runners/env-whitelist.d.cts.map +1 -0
  30. package/dist/agent-runners/env-whitelist.d.mts +5 -0
  31. package/dist/agent-runners/env-whitelist.d.mts.map +1 -0
  32. package/dist/agent-runners/env-whitelist.mjs +36 -0
  33. package/dist/agent-runners/env-whitelist.mjs.map +1 -0
  34. package/dist/agent-runners/guide-rails.cjs +47 -0
  35. package/dist/agent-runners/guide-rails.d.cts +16 -0
  36. package/dist/agent-runners/guide-rails.d.cts.map +1 -0
  37. package/dist/agent-runners/guide-rails.d.mts +16 -0
  38. package/dist/agent-runners/guide-rails.d.mts.map +1 -0
  39. package/dist/agent-runners/guide-rails.mjs +48 -0
  40. package/dist/agent-runners/guide-rails.mjs.map +1 -0
  41. package/dist/agent-runners/hook-channel.cjs +55 -0
  42. package/dist/agent-runners/hook-channel.d.cts +38 -0
  43. package/dist/agent-runners/hook-channel.d.cts.map +1 -0
  44. package/dist/agent-runners/hook-channel.d.mts +38 -0
  45. package/dist/agent-runners/hook-channel.d.mts.map +1 -0
  46. package/dist/agent-runners/hook-channel.mjs +55 -0
  47. package/dist/agent-runners/hook-channel.mjs.map +1 -0
  48. package/dist/agent-runners/hooks.cjs +107 -0
  49. package/dist/agent-runners/hooks.d.cts +41 -0
  50. package/dist/agent-runners/hooks.d.cts.map +1 -0
  51. package/dist/agent-runners/hooks.d.mts +41 -0
  52. package/dist/agent-runners/hooks.d.mts.map +1 -0
  53. package/dist/agent-runners/hooks.mjs +107 -0
  54. package/dist/agent-runners/hooks.mjs.map +1 -0
  55. package/dist/agent-runners/memory-afs.cjs +342 -0
  56. package/dist/agent-runners/memory-afs.d.cts +221 -0
  57. package/dist/agent-runners/memory-afs.d.cts.map +1 -0
  58. package/dist/agent-runners/memory-afs.d.mts +221 -0
  59. package/dist/agent-runners/memory-afs.d.mts.map +1 -0
  60. package/dist/agent-runners/memory-afs.mjs +326 -0
  61. package/dist/agent-runners/memory-afs.mjs.map +1 -0
  62. package/dist/agent-runners/memory-archive.cjs +263 -0
  63. package/dist/agent-runners/memory-archive.d.cts +47 -0
  64. package/dist/agent-runners/memory-archive.d.cts.map +1 -0
  65. package/dist/agent-runners/memory-archive.d.mts +47 -0
  66. package/dist/agent-runners/memory-archive.d.mts.map +1 -0
  67. package/dist/agent-runners/memory-archive.mjs +257 -0
  68. package/dist/agent-runners/memory-archive.mjs.map +1 -0
  69. package/dist/agent-runners/orchestrator-runner.cjs +302 -0
  70. package/dist/agent-runners/orchestrator-runner.d.cts +23 -0
  71. package/dist/agent-runners/orchestrator-runner.d.cts.map +1 -0
  72. package/dist/agent-runners/orchestrator-runner.d.mts +23 -0
  73. package/dist/agent-runners/orchestrator-runner.d.mts.map +1 -0
  74. package/dist/agent-runners/orchestrator-runner.mjs +303 -0
  75. package/dist/agent-runners/orchestrator-runner.mjs.map +1 -0
  76. package/dist/agent-runners/orchestrator-state.cjs +68 -0
  77. package/dist/agent-runners/orchestrator-state.d.cts +23 -0
  78. package/dist/agent-runners/orchestrator-state.d.cts.map +1 -0
  79. package/dist/agent-runners/orchestrator-state.d.mts +23 -0
  80. package/dist/agent-runners/orchestrator-state.d.mts.map +1 -0
  81. package/dist/agent-runners/orchestrator-state.mjs +65 -0
  82. package/dist/agent-runners/orchestrator-state.mjs.map +1 -0
  83. package/dist/agent-runners/retry.cjs +30 -0
  84. package/dist/agent-runners/retry.d.cts +13 -0
  85. package/dist/agent-runners/retry.d.cts.map +1 -0
  86. package/dist/agent-runners/retry.d.mts +13 -0
  87. package/dist/agent-runners/retry.d.mts.map +1 -0
  88. package/dist/agent-runners/retry.mjs +30 -0
  89. package/dist/agent-runners/retry.mjs.map +1 -0
  90. package/dist/agent-runners/scratchpad-afs.cjs +276 -0
  91. package/dist/agent-runners/scratchpad-afs.d.cts +103 -0
  92. package/dist/agent-runners/scratchpad-afs.d.cts.map +1 -0
  93. package/dist/agent-runners/scratchpad-afs.d.mts +103 -0
  94. package/dist/agent-runners/scratchpad-afs.d.mts.map +1 -0
  95. package/dist/agent-runners/scratchpad-afs.mjs +271 -0
  96. package/dist/agent-runners/scratchpad-afs.mjs.map +1 -0
  97. package/dist/agent-runners/stream-router.cjs +72 -0
  98. package/dist/agent-runners/stream-router.d.cts +22 -0
  99. package/dist/agent-runners/stream-router.d.cts.map +1 -0
  100. package/dist/agent-runners/stream-router.d.mts +22 -0
  101. package/dist/agent-runners/stream-router.d.mts.map +1 -0
  102. package/dist/agent-runners/stream-router.mjs +72 -0
  103. package/dist/agent-runners/stream-router.mjs.map +1 -0
  104. package/dist/agent-runners/system-prompt.cjs +35 -0
  105. package/dist/agent-runners/system-prompt.d.cts +17 -0
  106. package/dist/agent-runners/system-prompt.d.cts.map +1 -0
  107. package/dist/agent-runners/system-prompt.d.mts +17 -0
  108. package/dist/agent-runners/system-prompt.d.mts.map +1 -0
  109. package/dist/agent-runners/system-prompt.mjs +34 -0
  110. package/dist/agent-runners/system-prompt.mjs.map +1 -0
  111. package/dist/agent-runners/team-modes/aggregates.cjs +36 -0
  112. package/dist/agent-runners/team-modes/aggregates.mjs +35 -0
  113. package/dist/agent-runners/team-modes/aggregates.mjs.map +1 -0
  114. package/dist/agent-runners/team-modes/iterate.cjs +46 -0
  115. package/dist/agent-runners/team-modes/iterate.mjs +47 -0
  116. package/dist/agent-runners/team-modes/iterate.mjs.map +1 -0
  117. package/dist/agent-runners/team-modes/parallel.cjs +59 -0
  118. package/dist/agent-runners/team-modes/parallel.mjs +60 -0
  119. package/dist/agent-runners/team-modes/parallel.mjs.map +1 -0
  120. package/dist/agent-runners/team-modes/reflection.cjs +155 -0
  121. package/dist/agent-runners/team-modes/reflection.mjs +156 -0
  122. package/dist/agent-runners/team-modes/reflection.mjs.map +1 -0
  123. package/dist/agent-runners/team-modes/sequential.cjs +63 -0
  124. package/dist/agent-runners/team-modes/sequential.mjs +64 -0
  125. package/dist/agent-runners/team-modes/sequential.mjs.map +1 -0
  126. package/dist/agent-runners/team-modes/utils.cjs +39 -0
  127. package/dist/agent-runners/team-modes/utils.mjs +36 -0
  128. package/dist/agent-runners/team-modes/utils.mjs.map +1 -0
  129. package/dist/agent-runners/team-runner.cjs +277 -0
  130. package/dist/agent-runners/team-runner.d.cts +34 -0
  131. package/dist/agent-runners/team-runner.d.cts.map +1 -0
  132. package/dist/agent-runners/team-runner.d.mts +34 -0
  133. package/dist/agent-runners/team-runner.d.mts.map +1 -0
  134. package/dist/agent-runners/team-runner.mjs +278 -0
  135. package/dist/agent-runners/team-runner.mjs.map +1 -0
  136. package/dist/agent-runners/template-context.cjs +32 -0
  137. package/dist/agent-runners/template-context.d.cts +43 -0
  138. package/dist/agent-runners/template-context.d.cts.map +1 -0
  139. package/dist/agent-runners/template-context.d.mts +43 -0
  140. package/dist/agent-runners/template-context.d.mts.map +1 -0
  141. package/dist/agent-runners/template-context.mjs +33 -0
  142. package/dist/agent-runners/template-context.mjs.map +1 -0
  143. package/dist/index.cjs +123 -0
  144. package/dist/index.d.cts +29 -0
  145. package/dist/index.d.mts +29 -0
  146. package/dist/index.mjs +29 -0
  147. package/dist/program/agent-action.cjs +496 -0
  148. package/dist/program/agent-action.d.cts +42 -0
  149. package/dist/program/agent-action.d.cts.map +1 -0
  150. package/dist/program/agent-action.d.mts +42 -0
  151. package/dist/program/agent-action.d.mts.map +1 -0
  152. package/dist/program/agent-action.mjs +497 -0
  153. package/dist/program/agent-action.mjs.map +1 -0
  154. package/dist/program/agent-messages-tools.cjs +137 -0
  155. package/dist/program/agent-messages-tools.d.cts +59 -0
  156. package/dist/program/agent-messages-tools.d.cts.map +1 -0
  157. package/dist/program/agent-messages-tools.d.mts +59 -0
  158. package/dist/program/agent-messages-tools.d.mts.map +1 -0
  159. package/dist/program/agent-messages-tools.mjs +130 -0
  160. package/dist/program/agent-messages-tools.mjs.map +1 -0
  161. package/dist/program/agent-runner-registry.cjs +314 -0
  162. package/dist/program/agent-runner-registry.d.cts +52 -0
  163. package/dist/program/agent-runner-registry.d.cts.map +1 -0
  164. package/dist/program/agent-runner-registry.d.mts +52 -0
  165. package/dist/program/agent-runner-registry.d.mts.map +1 -0
  166. package/dist/program/agent-runner-registry.mjs +313 -0
  167. package/dist/program/agent-runner-registry.mjs.map +1 -0
  168. package/dist/program/agent-subscribe.cjs +72 -0
  169. package/dist/program/agent-subscribe.d.cts +18 -0
  170. package/dist/program/agent-subscribe.d.cts.map +1 -0
  171. package/dist/program/agent-subscribe.d.mts +18 -0
  172. package/dist/program/agent-subscribe.d.mts.map +1 -0
  173. package/dist/program/agent-subscribe.mjs +73 -0
  174. package/dist/program/agent-subscribe.mjs.map +1 -0
  175. package/dist/program/agent-tools.cjs +135 -0
  176. package/dist/program/agent-tools.d.cts +35 -0
  177. package/dist/program/agent-tools.d.cts.map +1 -0
  178. package/dist/program/agent-tools.d.mts +35 -0
  179. package/dist/program/agent-tools.d.mts.map +1 -0
  180. package/dist/program/agent-tools.mjs +136 -0
  181. package/dist/program/agent-tools.mjs.map +1 -0
  182. package/dist/program/manifest-nesting.cjs +57 -0
  183. package/dist/program/manifest-nesting.d.cts +13 -0
  184. package/dist/program/manifest-nesting.d.cts.map +1 -0
  185. package/dist/program/manifest-nesting.d.mts +13 -0
  186. package/dist/program/manifest-nesting.d.mts.map +1 -0
  187. package/dist/program/manifest-nesting.mjs +57 -0
  188. package/dist/program/manifest-nesting.mjs.map +1 -0
  189. package/dist/program/result-contract.cjs +55 -0
  190. package/dist/program/result-contract.d.cts +23 -0
  191. package/dist/program/result-contract.d.cts.map +1 -0
  192. package/dist/program/result-contract.d.mts +23 -0
  193. package/dist/program/result-contract.d.mts.map +1 -0
  194. package/dist/program/result-contract.mjs +51 -0
  195. package/dist/program/result-contract.mjs.map +1 -0
  196. package/dist/program/runner-error.cjs +71 -0
  197. package/dist/program/runner-error.d.cts +25 -0
  198. package/dist/program/runner-error.d.cts.map +1 -0
  199. package/dist/program/runner-error.d.mts +25 -0
  200. package/dist/program/runner-error.d.mts.map +1 -0
  201. package/dist/program/runner-error.mjs +72 -0
  202. package/dist/program/runner-error.mjs.map +1 -0
  203. package/dist/program/scoped-afs.cjs +538 -0
  204. package/dist/program/scoped-afs.d.cts +245 -0
  205. package/dist/program/scoped-afs.d.cts.map +1 -0
  206. package/dist/program/scoped-afs.d.mts +245 -0
  207. package/dist/program/scoped-afs.d.mts.map +1 -0
  208. package/dist/program/scoped-afs.mjs +531 -0
  209. package/dist/program/scoped-afs.mjs.map +1 -0
  210. package/dist/program/session-hierarchy.cjs +1 -0
  211. package/dist/program/session-hierarchy.d.cts +2 -0
  212. package/dist/program/session-hierarchy.d.mts +2 -0
  213. package/dist/program/session-hierarchy.mjs +3 -0
  214. package/dist/program/tool-discovery/ash-frontmatter.cjs +83 -0
  215. package/dist/program/tool-discovery/ash-frontmatter.d.cts +21 -0
  216. package/dist/program/tool-discovery/ash-frontmatter.d.cts.map +1 -0
  217. package/dist/program/tool-discovery/ash-frontmatter.d.mts +21 -0
  218. package/dist/program/tool-discovery/ash-frontmatter.d.mts.map +1 -0
  219. package/dist/program/tool-discovery/ash-frontmatter.mjs +84 -0
  220. package/dist/program/tool-discovery/ash-frontmatter.mjs.map +1 -0
  221. package/dist/program/tool-discovery/dot-path-resolver.cjs +60 -0
  222. package/dist/program/tool-discovery/dot-path-resolver.mjs +61 -0
  223. package/dist/program/tool-discovery/dot-path-resolver.mjs.map +1 -0
  224. package/dist/program/tool-discovery/skill-gate.cjs +36 -0
  225. package/dist/program/tool-discovery/skill-gate.d.cts +10 -0
  226. package/dist/program/tool-discovery/skill-gate.d.cts.map +1 -0
  227. package/dist/program/tool-discovery/skill-gate.d.mts +10 -0
  228. package/dist/program/tool-discovery/skill-gate.d.mts.map +1 -0
  229. package/dist/program/tool-discovery/skill-gate.mjs +35 -0
  230. package/dist/program/tool-discovery/skill-gate.mjs.map +1 -0
  231. package/dist/providers/basic/ash/dist/index.cjs +1809 -0
  232. package/dist/providers/basic/ash/dist/index.mjs +1807 -0
  233. package/dist/providers/basic/ash/dist/index.mjs.map +1 -0
  234. package/package.json +67 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-runner.mjs","names":[],"sources":["../../src/agent-runners/orchestrator-runner.ts"],"sourcesContent":["import type { AFSExecResult, AFSRoot } from \"@aigne/afs\";\nimport { parseAgentManifest, resolveMemberPath } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\nimport { getRunnerForType, type RunnerContext } from \"../program/agent-runner-registry.js\";\nimport {\n type AgentScope,\n ensureScopeWithMounts,\n normalizeManifestTools,\n projectForChild,\n resolveParentAgentScope,\n runnerSession,\n} from \"../program/scoped-afs.js\";\nimport {\n createInitialState,\n deserializeState,\n serializeState,\n truncateHistory,\n} from \"./orchestrator-state.js\";\nimport { SCRATCH_SCOPE_ROOT } from \"./scratchpad-afs.js\";\n\nexport interface OrchestratorRunnerResult {\n success: boolean;\n data?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { code: string; message: string };\n _meta?: {\n iterations: number;\n sub_runs: number;\n max_iterations_hit?: boolean;\n truncated?: number;\n keep_recent?: number;\n };\n}\n\ninterface PlannerOutput {\n finished?: boolean;\n nextTasks?: Array<{ description: string; input?: Record<string, unknown> }>;\n parallelTasks?: boolean;\n}\n\nconst MAX_ITERATIONS_CEILING = 30;\nconst DEFAULT_KEEP_RECENT = 20;\nconst DEFAULT_MAX_TOKENS = 100_000;\n\nfunction extractPlannerOutput(raw: unknown): PlannerOutput | null {\n if (!raw || typeof raw !== \"object\") return null;\n const obj = raw as Record<string, unknown>;\n\n const candidates = [obj, (obj as any).data?.result, (obj as any).result, (obj as any).data];\n for (const c of candidates) {\n if (!c) continue;\n let parsed = c;\n if (typeof parsed === \"string\") {\n try {\n parsed = JSON.parse(parsed);\n } catch {\n continue;\n }\n }\n if (typeof (parsed as any)?.reply === \"string\") {\n try {\n parsed = JSON.parse((parsed as any).reply);\n } catch {\n continue;\n }\n }\n if (parsed && typeof parsed === \"object\" && (\"finished\" in parsed || \"nextTasks\" in parsed)) {\n return parsed as PlannerOutput;\n }\n }\n return null;\n}\n\nfunction extractResult(raw: unknown): unknown {\n if (!raw || typeof raw !== \"object\") return raw;\n const obj = raw as any;\n return obj.data?.result ?? obj.result ?? obj.data ?? obj;\n}\n\nasync function renderObjective(\n template: string,\n input: Record<string, unknown>,\n manifest: { name: string; type: string },\n mountPath: string,\n afs: unknown,\n): Promise<string> {\n try {\n const mod = await import(\"@aigne/ash/src/prompt/template.js\");\n return await mod.renderTemplate(\n template,\n { $input: input, $manifest: manifest, $now: new Date().toISOString() },\n { blockletRoot: mountPath, afs: afs as any },\n );\n } catch {\n return template;\n }\n}\n\nfunction metaResult(\n iterations: number,\n subRuns: number,\n maxHit?: boolean,\n): OrchestratorRunnerResult[\"_meta\"] {\n return {\n iterations,\n sub_runs: subRuns,\n max_iterations_hit: maxHit || undefined,\n };\n}\n\nasync function dispatchSubAgent(\n context: RunnerContext,\n memberPath: string,\n input: Record<string, unknown>,\n session: string | undefined,\n parentScope: AgentScope,\n): Promise<AFSExecResult> {\n const runtimeMemberPath = resolveMemberPath(memberPath);\n const agentYmlPath = joinURL(runtimeMemberPath, \"agent.yml\");\n\n const read = await context.afs.read!(agentYmlPath);\n const content = String((read as any)?.data?.content ?? \"\");\n const subManifest = parseAgentManifest(content);\n\n const subAfs = projectForChild(parentScope, {\n memberPath,\n childManifest: subManifest,\n session,\n });\n\n const subContext: RunnerContext = {\n afs: subAfs as unknown as AFSRoot,\n mountPath: \"/packages\",\n manifest: subManifest,\n session,\n // Phase 5 — parentSession follows the parentScope's session (canonical\n // source), not the legacy `context.session` field.\n parentSession: parentScope.scope.session,\n chain: context.chain,\n };\n\n // Bridge the caller's payload into the sub-agent's declared inputKey.\n // Parent orchestrator wraps payloads under its own inputKey (e.g. \"question\"),\n // but planner/worker/completer may each declare a different inputKey\n // (\"state\", \"execution_state\", etc.). Without this remap, sub-agent's\n // ai-runner reads `input[subInputKey]` → undefined → task=\"\" → ash\n // agent-run throws \"requires 'task' parameter as string\". Mirrors the\n // B15 bridge in team-runner.\n const parentInputKey = context.manifest.inputKey ?? \"message\";\n const subInputKey = subManifest.inputKey ?? \"message\";\n const bridgedInput =\n subInputKey !== parentInputKey && input[subInputKey] === undefined\n ? bridgeInput(input, parentInputKey, subInputKey)\n : input;\n\n const runner = getRunnerForType(subManifest.type);\n return runner(bridgedInput, subContext);\n}\n\nfunction bridgeInput(\n input: Record<string, unknown>,\n parentInputKey: string,\n subInputKey: string,\n): Record<string, unknown> {\n const taskValue = input[parentInputKey] ?? input.message ?? input.task ?? input.text;\n if (taskValue === undefined) return input;\n const { [parentInputKey]: _drop, ...rest } = input;\n return { ...rest, [subInputKey]: taskValue };\n}\n\nexport async function runOrchestratorAgent(\n input: Record<string, unknown>,\n context: RunnerContext,\n): Promise<OrchestratorRunnerResult> {\n const { manifest, mountPath } = context;\n // Phase 5 — session id comes from scope first, legacy context only as\n // fallback. Downstream sub-agent dispatch derives its own session ids\n // (e.g. `${session}-planner-${i}`) off this resolved value.\n const session = runnerSession(context.afs, context.session);\n // Bootstrap a scope (+ /scratch/ mount) when the caller hasn't already\n // wrapped its AFS. The orchestrator writes its own state.yml and hook\n // events through `ctx.afs`, so every subsequent afs.* call must hit the\n // scope-local scratch — not the legacy /modules/memory/runs tree.\n const scopedAfs = ensureScopeWithMounts(context.afs, {\n session: session ?? \"root\",\n manifestTools: normalizeManifestTools(manifest),\n scratchRetention: manifest.scratch ? \"session\" : \"run\",\n budget: manifest.budget,\n }) as unknown as AFSRoot;\n const afs = scopedAfs;\n // Subsequent dispatchSubAgent calls must use the scoped AFS so the\n // orchestrator's view — and any child scope derived from it — starts\n // from the scratch-mounted root rather than the caller's raw handle.\n // Phase 5 — the scoped context must also carry the resolved session so\n // that nested scope.sessions stay consistent across dispatch layers.\n const scopedContext: RunnerContext = { ...context, afs: scopedAfs, session };\n const inputKey = manifest.inputKey ?? \"message\";\n const sm = manifest.stateManagement ?? {};\n const maxIter = Math.min(sm.maxIterations ?? MAX_ITERATIONS_CEILING, MAX_ITERATIONS_CEILING);\n const keepRecent = sm.keepRecent ?? DEFAULT_KEEP_RECENT;\n const maxTokens = sm.maxTokens ?? DEFAULT_MAX_TOKENS;\n const concurrency = Math.min(manifest.concurrency ?? 10, 10);\n\n // B12: Runtime AFS projects the blocklet directory at /packages; the\n // external mountPath isn't a valid internal path after activation. Try\n // mountPath first (works in tests + pre-activation), fall back to\n // /packages (production post-activation).\n const objFile = manifest.objective ?? \"objective.md\";\n const objCandidates = [joinURL(mountPath, objFile), joinURL(\"/packages\", objFile)];\n let objective: string | undefined;\n let lastObjPath = objCandidates[0]!;\n for (const candidate of objCandidates) {\n lastObjPath = candidate;\n try {\n const raw = await afs.read!(candidate);\n const content =\n typeof raw === \"string\"\n ? raw\n : String((raw as any)?.data?.content ?? (raw as any)?.data ?? raw ?? \"\");\n if (content) {\n objective = content;\n break;\n }\n } catch {\n // Try next candidate\n }\n }\n if (!objective) {\n return {\n success: false,\n error: { code: \"OBJECTIVE_NOT_FOUND\", message: `Cannot read objective at ${lastObjPath}` },\n };\n }\n\n objective = await renderObjective(\n objective,\n input,\n { name: manifest.name, type: manifest.type },\n mountPath,\n afs,\n );\n\n // Phase 2 — state persists at the scope-local /scratch/state.yml; the\n // scratch overlay routes the read/write to the in-memory provider that\n // `ensureScopeWithMounts` attached above. `session` still gates *whether*\n // to persist (tests bypass state when session is undefined).\n const statePath = session ? joinURL(SCRATCH_SCOPE_ROOT, \"state.yml\") : null;\n let state = createInitialState(objective);\n if (statePath) {\n try {\n const raw = await afs.read!(statePath);\n const content =\n typeof raw === \"string\" ? raw : String((raw as any)?.data?.content ?? raw ?? \"\");\n const loaded = deserializeState(content);\n if (loaded) state = loaded;\n } catch {\n /* fresh start */\n }\n }\n\n const parentScopeForSubs = resolveParentAgentScope({\n afs: scopedAfs,\n manifest,\n session,\n });\n\n let subRuns = 0;\n const plannerPath = manifest.planner?.path ?? null;\n const workerPath = manifest.worker?.path ?? null;\n const completerPath = manifest.completer?.path ?? null;\n let lastPlanKey = \"\";\n\n for (let i = state.iterations; i < maxIter; i++) {\n state.iterations = i + 1;\n state = truncateHistory(state, maxTokens, keepRecent);\n\n let plan: PlannerOutput;\n if (plannerPath) {\n try {\n const raw = await dispatchSubAgent(\n scopedContext,\n plannerPath,\n {\n [inputKey]: JSON.stringify({\n objective: state.objective,\n history: state.history,\n iteration: i,\n summaries: state.summaries,\n }),\n },\n session ? `${session}-planner-${i}` : undefined,\n parentScopeForSubs,\n );\n const parsed = extractPlannerOutput(raw);\n if (!parsed) {\n return {\n success: false,\n error: {\n code: \"PLANNER_OUTPUT_INVALID\",\n message: \"Planner must return 'finished' or 'nextTasks'\",\n },\n _meta: metaResult(state.iterations, subRuns),\n };\n }\n plan = parsed;\n } catch (e: any) {\n return {\n success: false,\n error: { code: \"PLANNER_ERROR\", message: e.message ?? String(e) },\n _meta: metaResult(state.iterations, subRuns),\n };\n }\n } else {\n plan =\n state.history.length > 0\n ? { finished: true }\n : { nextTasks: [{ description: String(input[inputKey] ?? state.objective) }] };\n }\n\n if (plan.finished) break;\n\n if (!plan.nextTasks?.length) {\n return {\n success: false,\n error: {\n code: \"PLANNER_OUTPUT_INVALID\",\n message: \"Planner must return 'finished' or 'nextTasks'\",\n },\n _meta: metaResult(state.iterations, subRuns),\n };\n }\n\n const planKey = JSON.stringify(plan.nextTasks.map((t) => t.description).sort());\n if (planKey === lastPlanKey) {\n return {\n success: false,\n error: {\n code: \"CIRCULAR_PLANNER\",\n message: \"Planner is scheduling the same tasks repeatedly\",\n },\n _meta: metaResult(state.iterations, subRuns),\n };\n }\n lastPlanKey = planKey;\n\n const tasks = plan.nextTasks;\n const runWorker = async (task: (typeof tasks)[0]) => {\n subRuns++;\n if (!workerPath) {\n return { description: task.description, result: null, error: \"NO_WORKER\" };\n }\n try {\n const raw = await dispatchSubAgent(\n scopedContext,\n workerPath,\n {\n ...(task.input ?? {}),\n [inputKey]: task.description,\n },\n session ? `${session}-w-${subRuns}` : undefined,\n parentScopeForSubs,\n );\n return { description: task.description, result: extractResult(raw) };\n } catch (e: any) {\n return { description: task.description, result: null, error: e.message ?? String(e) };\n }\n };\n\n if (plan.parallelTasks && tasks.length > 1) {\n for (let j = 0; j < tasks.length; j += concurrency) {\n const batch = tasks.slice(j, j + concurrency);\n const results = await Promise.all(batch.map(runWorker));\n for (const r of results) {\n state.history.push({\n iteration: i,\n description: r.description,\n result: r.result,\n error: r.error,\n ts: new Date().toISOString(),\n });\n }\n }\n } else {\n for (const task of tasks) {\n const r = await runWorker(task);\n state.history.push({\n iteration: i,\n description: r.description,\n result: r.result,\n error: r.error,\n ts: new Date().toISOString(),\n });\n }\n }\n\n if (statePath) {\n try {\n await afs.write!(statePath, { content: serializeState(state, keepRecent) } as any);\n } catch {\n /* best effort */\n }\n }\n }\n\n const maxHit = state.iterations >= maxIter;\n\n let finalResult: unknown;\n if (completerPath) {\n try {\n const raw = await dispatchSubAgent(\n scopedContext,\n completerPath,\n {\n [inputKey]: JSON.stringify({\n objective: state.objective,\n history: state.history,\n iterations: state.iterations,\n max_iterations_hit: maxHit,\n }),\n },\n session ? `${session}-completer` : undefined,\n parentScopeForSubs,\n );\n finalResult = extractResult(raw);\n } catch (e: any) {\n return {\n success: false,\n error: { code: \"COMPLETER_ERROR\", message: e.message ?? String(e) },\n _meta: {\n iterations: state.iterations,\n sub_runs: subRuns,\n max_iterations_hit: maxHit || undefined,\n keep_recent: keepRecent,\n },\n };\n }\n } else {\n const last = state.history[state.history.length - 1];\n finalResult = last?.result ?? null;\n }\n\n if (statePath) {\n try {\n await afs.write!(statePath, { content: serializeState(state, keepRecent) } as any);\n } catch {\n /* best effort */\n }\n }\n\n const result: OrchestratorRunnerResult = {\n success: true,\n data: { result: finalResult },\n _meta: {\n iterations: state.iterations,\n sub_runs: subRuns,\n max_iterations_hit: maxHit || undefined,\n truncated: state.truncated || undefined,\n keep_recent: keepRecent,\n },\n };\n\n if (manifest.outputKey && finalResult != null) {\n result.result = { [manifest.outputKey]: finalResult };\n }\n\n return result;\n}\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ let js_yaml = require("js-yaml");
2
+
3
+ //#region src/agent-runners/orchestrator-state.ts
4
+ function createInitialState(objective) {
5
+ return {
6
+ objective,
7
+ iterations: 0,
8
+ history: [],
9
+ truncated: 0,
10
+ summaries: []
11
+ };
12
+ }
13
+ function estimateTokens(value) {
14
+ const text = typeof value === "string" ? value : JSON.stringify(value ?? "");
15
+ return Math.max(1, Math.ceil(text.length / 4));
16
+ }
17
+ function truncateHistory(state, maxTokens, keepRecent) {
18
+ if (state.history.length <= keepRecent) return state;
19
+ if (estimateTokens(state.history) <= maxTokens) return state;
20
+ const history = [...state.history];
21
+ const summaries = [...state.summaries];
22
+ let { truncated } = state;
23
+ while (history.length > keepRecent && estimateTokens(history) > maxTokens) {
24
+ const removed = history.shift();
25
+ truncated++;
26
+ summaries.push(`[iter ${removed.iteration}] ${removed.description}: ${removed.error ?? "ok"}`);
27
+ }
28
+ return {
29
+ ...state,
30
+ history,
31
+ truncated,
32
+ summaries
33
+ };
34
+ }
35
+ function serializeState(state, keepRecent) {
36
+ const output = {
37
+ objective: state.objective,
38
+ iterations: state.iterations,
39
+ history: state.history,
40
+ truncated: state.truncated
41
+ };
42
+ if (keepRecent !== void 0) output.keep_recent = keepRecent;
43
+ if (state.summaries.length > 0) output.summaries = state.summaries;
44
+ return (0, js_yaml.dump)(output);
45
+ }
46
+ function deserializeState(yaml) {
47
+ if (!yaml.trim()) return null;
48
+ try {
49
+ const raw = (0, js_yaml.load)(yaml);
50
+ if (!raw || typeof raw !== "object") return null;
51
+ return {
52
+ objective: String(raw.objective ?? ""),
53
+ iterations: Number(raw.iterations ?? 0),
54
+ history: Array.isArray(raw.history) ? raw.history : [],
55
+ truncated: Number(raw.truncated ?? 0),
56
+ summaries: Array.isArray(raw.summaries) ? raw.summaries : []
57
+ };
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ //#endregion
64
+ exports.createInitialState = createInitialState;
65
+ exports.deserializeState = deserializeState;
66
+ exports.estimateTokens = estimateTokens;
67
+ exports.serializeState = serializeState;
68
+ exports.truncateHistory = truncateHistory;
@@ -0,0 +1,23 @@
1
+ //#region src/agent-runners/orchestrator-state.d.ts
2
+ interface TaskResult {
3
+ iteration: number;
4
+ description: string;
5
+ result: unknown;
6
+ error?: string;
7
+ ts: string;
8
+ }
9
+ interface OrchestratorState {
10
+ objective: string;
11
+ iterations: number;
12
+ history: TaskResult[];
13
+ truncated: number;
14
+ summaries: string[];
15
+ }
16
+ declare function createInitialState(objective: string): OrchestratorState;
17
+ declare function estimateTokens(value: unknown): number;
18
+ declare function truncateHistory(state: OrchestratorState, maxTokens: number, keepRecent: number): OrchestratorState;
19
+ declare function serializeState(state: OrchestratorState, keepRecent?: number): string;
20
+ declare function deserializeState(yaml: string): OrchestratorState | null;
21
+ //#endregion
22
+ export { OrchestratorState, TaskResult, createInitialState, deserializeState, estimateTokens, serializeState, truncateHistory };
23
+ //# sourceMappingURL=orchestrator-state.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-state.d.cts","names":[],"sources":["../../src/agent-runners/orchestrator-state.ts"],"mappings":";UAEiB,UAAA;EACf,SAAA;EACA,WAAA;EACA,MAAA;EACA,KAAA;EACA,EAAA;AAAA;AAAA,UAGe,iBAAA;EACf,SAAA;EACA,UAAA;EACA,OAAA,EAAS,UAAA;EACT,SAAA;EACA,SAAA;AAAA;AAAA,iBAGc,kBAAA,CAAmB,SAAA,WAAoB,iBAAA;AAAA,iBAIvC,cAAA,CAAe,KAAA;AAAA,iBAKf,eAAA,CACd,KAAA,EAAO,iBAAA,EACP,SAAA,UACA,UAAA,WACC,iBAAA;AAAA,iBAiBa,cAAA,CAAe,KAAA,EAAO,iBAAA,EAAmB,UAAA;AAAA,iBAYzC,gBAAA,CAAiB,IAAA,WAAe,iBAAA"}
@@ -0,0 +1,23 @@
1
+ //#region src/agent-runners/orchestrator-state.d.ts
2
+ interface TaskResult {
3
+ iteration: number;
4
+ description: string;
5
+ result: unknown;
6
+ error?: string;
7
+ ts: string;
8
+ }
9
+ interface OrchestratorState {
10
+ objective: string;
11
+ iterations: number;
12
+ history: TaskResult[];
13
+ truncated: number;
14
+ summaries: string[];
15
+ }
16
+ declare function createInitialState(objective: string): OrchestratorState;
17
+ declare function estimateTokens(value: unknown): number;
18
+ declare function truncateHistory(state: OrchestratorState, maxTokens: number, keepRecent: number): OrchestratorState;
19
+ declare function serializeState(state: OrchestratorState, keepRecent?: number): string;
20
+ declare function deserializeState(yaml: string): OrchestratorState | null;
21
+ //#endregion
22
+ export { OrchestratorState, TaskResult, createInitialState, deserializeState, estimateTokens, serializeState, truncateHistory };
23
+ //# sourceMappingURL=orchestrator-state.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-state.d.mts","names":[],"sources":["../../src/agent-runners/orchestrator-state.ts"],"mappings":";UAEiB,UAAA;EACf,SAAA;EACA,WAAA;EACA,MAAA;EACA,KAAA;EACA,EAAA;AAAA;AAAA,UAGe,iBAAA;EACf,SAAA;EACA,UAAA;EACA,OAAA,EAAS,UAAA;EACT,SAAA;EACA,SAAA;AAAA;AAAA,iBAGc,kBAAA,CAAmB,SAAA,WAAoB,iBAAA;AAAA,iBAIvC,cAAA,CAAe,KAAA;AAAA,iBAKf,eAAA,CACd,KAAA,EAAO,iBAAA,EACP,SAAA,UACA,UAAA,WACC,iBAAA;AAAA,iBAiBa,cAAA,CAAe,KAAA,EAAO,iBAAA,EAAmB,UAAA;AAAA,iBAYzC,gBAAA,CAAiB,IAAA,WAAe,iBAAA"}
@@ -0,0 +1,65 @@
1
+ import { dump, load } from "js-yaml";
2
+
3
+ //#region src/agent-runners/orchestrator-state.ts
4
+ function createInitialState(objective) {
5
+ return {
6
+ objective,
7
+ iterations: 0,
8
+ history: [],
9
+ truncated: 0,
10
+ summaries: []
11
+ };
12
+ }
13
+ function estimateTokens(value) {
14
+ const text = typeof value === "string" ? value : JSON.stringify(value ?? "");
15
+ return Math.max(1, Math.ceil(text.length / 4));
16
+ }
17
+ function truncateHistory(state, maxTokens, keepRecent) {
18
+ if (state.history.length <= keepRecent) return state;
19
+ if (estimateTokens(state.history) <= maxTokens) return state;
20
+ const history = [...state.history];
21
+ const summaries = [...state.summaries];
22
+ let { truncated } = state;
23
+ while (history.length > keepRecent && estimateTokens(history) > maxTokens) {
24
+ const removed = history.shift();
25
+ truncated++;
26
+ summaries.push(`[iter ${removed.iteration}] ${removed.description}: ${removed.error ?? "ok"}`);
27
+ }
28
+ return {
29
+ ...state,
30
+ history,
31
+ truncated,
32
+ summaries
33
+ };
34
+ }
35
+ function serializeState(state, keepRecent) {
36
+ const output = {
37
+ objective: state.objective,
38
+ iterations: state.iterations,
39
+ history: state.history,
40
+ truncated: state.truncated
41
+ };
42
+ if (keepRecent !== void 0) output.keep_recent = keepRecent;
43
+ if (state.summaries.length > 0) output.summaries = state.summaries;
44
+ return dump(output);
45
+ }
46
+ function deserializeState(yaml) {
47
+ if (!yaml.trim()) return null;
48
+ try {
49
+ const raw = load(yaml);
50
+ if (!raw || typeof raw !== "object") return null;
51
+ return {
52
+ objective: String(raw.objective ?? ""),
53
+ iterations: Number(raw.iterations ?? 0),
54
+ history: Array.isArray(raw.history) ? raw.history : [],
55
+ truncated: Number(raw.truncated ?? 0),
56
+ summaries: Array.isArray(raw.summaries) ? raw.summaries : []
57
+ };
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ //#endregion
64
+ export { createInitialState, deserializeState, estimateTokens, serializeState, truncateHistory };
65
+ //# sourceMappingURL=orchestrator-state.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-state.mjs","names":["dumpYAML","parseYAML"],"sources":["../../src/agent-runners/orchestrator-state.ts"],"sourcesContent":["import { dump as dumpYAML, load as parseYAML } from \"js-yaml\";\n\nexport interface TaskResult {\n iteration: number;\n description: string;\n result: unknown;\n error?: string;\n ts: string;\n}\n\nexport interface OrchestratorState {\n objective: string;\n iterations: number;\n history: TaskResult[];\n truncated: number;\n summaries: string[];\n}\n\nexport function createInitialState(objective: string): OrchestratorState {\n return { objective, iterations: 0, history: [], truncated: 0, summaries: [] };\n}\n\nexport function estimateTokens(value: unknown): number {\n const text = typeof value === \"string\" ? value : JSON.stringify(value ?? \"\");\n return Math.max(1, Math.ceil(text.length / 4));\n}\n\nexport function truncateHistory(\n state: OrchestratorState,\n maxTokens: number,\n keepRecent: number,\n): OrchestratorState {\n if (state.history.length <= keepRecent) return state;\n if (estimateTokens(state.history) <= maxTokens) return state;\n\n const history = [...state.history];\n const summaries = [...state.summaries];\n let { truncated } = state;\n\n while (history.length > keepRecent && estimateTokens(history) > maxTokens) {\n const removed = history.shift()!;\n truncated++;\n summaries.push(`[iter ${removed.iteration}] ${removed.description}: ${removed.error ?? \"ok\"}`);\n }\n\n return { ...state, history, truncated, summaries };\n}\n\nexport function serializeState(state: OrchestratorState, keepRecent?: number): string {\n const output: Record<string, unknown> = {\n objective: state.objective,\n iterations: state.iterations,\n history: state.history,\n truncated: state.truncated,\n };\n if (keepRecent !== undefined) output.keep_recent = keepRecent;\n if (state.summaries.length > 0) output.summaries = state.summaries;\n return dumpYAML(output);\n}\n\nexport function deserializeState(yaml: string): OrchestratorState | null {\n if (!yaml.trim()) return null;\n try {\n const raw = parseYAML(yaml) as Record<string, unknown>;\n if (!raw || typeof raw !== \"object\") return null;\n return {\n objective: String(raw.objective ?? \"\"),\n iterations: Number(raw.iterations ?? 0),\n history: Array.isArray(raw.history) ? raw.history : [],\n truncated: Number(raw.truncated ?? 0),\n summaries: Array.isArray(raw.summaries) ? raw.summaries : [],\n };\n } catch {\n return null;\n }\n}\n"],"mappings":";;;AAkBA,SAAgB,mBAAmB,WAAsC;AACvE,QAAO;EAAE;EAAW,YAAY;EAAG,SAAS,EAAE;EAAE,WAAW;EAAG,WAAW,EAAE;EAAE;;AAG/E,SAAgB,eAAe,OAAwB;CACrD,MAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,SAAS,GAAG;AAC5E,QAAO,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,SAAS,EAAE,CAAC;;AAGhD,SAAgB,gBACd,OACA,WACA,YACmB;AACnB,KAAI,MAAM,QAAQ,UAAU,WAAY,QAAO;AAC/C,KAAI,eAAe,MAAM,QAAQ,IAAI,UAAW,QAAO;CAEvD,MAAM,UAAU,CAAC,GAAG,MAAM,QAAQ;CAClC,MAAM,YAAY,CAAC,GAAG,MAAM,UAAU;CACtC,IAAI,EAAE,cAAc;AAEpB,QAAO,QAAQ,SAAS,cAAc,eAAe,QAAQ,GAAG,WAAW;EACzE,MAAM,UAAU,QAAQ,OAAO;AAC/B;AACA,YAAU,KAAK,SAAS,QAAQ,UAAU,IAAI,QAAQ,YAAY,IAAI,QAAQ,SAAS,OAAO;;AAGhG,QAAO;EAAE,GAAG;EAAO;EAAS;EAAW;EAAW;;AAGpD,SAAgB,eAAe,OAA0B,YAA6B;CACpF,MAAM,SAAkC;EACtC,WAAW,MAAM;EACjB,YAAY,MAAM;EAClB,SAAS,MAAM;EACf,WAAW,MAAM;EAClB;AACD,KAAI,eAAe,OAAW,QAAO,cAAc;AACnD,KAAI,MAAM,UAAU,SAAS,EAAG,QAAO,YAAY,MAAM;AACzD,QAAOA,KAAS,OAAO;;AAGzB,SAAgB,iBAAiB,MAAwC;AACvE,KAAI,CAAC,KAAK,MAAM,CAAE,QAAO;AACzB,KAAI;EACF,MAAM,MAAMC,KAAU,KAAK;AAC3B,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,SAAO;GACL,WAAW,OAAO,IAAI,aAAa,GAAG;GACtC,YAAY,OAAO,IAAI,cAAc,EAAE;GACvC,SAAS,MAAM,QAAQ,IAAI,QAAQ,GAAG,IAAI,UAAU,EAAE;GACtD,WAAW,OAAO,IAAI,aAAa,EAAE;GACrC,WAAW,MAAM,QAAQ,IAAI,UAAU,GAAG,IAAI,YAAY,EAAE;GAC7D;SACK;AACN,SAAO"}
@@ -0,0 +1,30 @@
1
+
2
+ //#region src/agent-runners/retry.ts
3
+ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4
+ async function withRetry(fn, config, shouldRetry, opts = {}) {
5
+ const maxAttempts = Math.max(0, config?.retries ?? 0) + 1;
6
+ const minTimeoutMs = config?.minTimeoutMs ?? 0;
7
+ const factor = config?.factor ?? 2;
8
+ const sleep = opts.sleep ?? defaultSleep;
9
+ let lastError;
10
+ let lastResult;
11
+ let hasResult = false;
12
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
13
+ try {
14
+ const result = await fn();
15
+ if (shouldRetry?.(result) && attempt < maxAttempts - 1) {
16
+ lastResult = result;
17
+ hasResult = true;
18
+ } else return result;
19
+ } catch (err) {
20
+ lastError = err;
21
+ if (attempt === maxAttempts - 1) throw err;
22
+ }
23
+ if (minTimeoutMs > 0 && attempt < maxAttempts - 1) await sleep(minTimeoutMs * factor ** attempt);
24
+ }
25
+ if (hasResult) return lastResult;
26
+ throw lastError;
27
+ }
28
+
29
+ //#endregion
30
+ exports.withRetry = withRetry;
@@ -0,0 +1,13 @@
1
+ //#region src/agent-runners/retry.d.ts
2
+ interface RetryConfig {
3
+ retries: number;
4
+ minTimeoutMs?: number;
5
+ factor?: number;
6
+ }
7
+ interface WithRetryOptions {
8
+ sleep?: (ms: number) => Promise<void>;
9
+ }
10
+ declare function withRetry<T>(fn: () => Promise<T>, config: RetryConfig | undefined, shouldRetry?: (result: T) => boolean, opts?: WithRetryOptions): Promise<T>;
11
+ //#endregion
12
+ export { RetryConfig, WithRetryOptions, withRetry };
13
+ //# sourceMappingURL=retry.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.cts","names":[],"sources":["../../src/agent-runners/retry.ts"],"mappings":";UAAiB,WAAA;EACf,OAAA;EACA,YAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA,IAAS,EAAA,aAAe,OAAA;AAAA;AAAA,iBAMJ,SAAA,GAAA,CACpB,EAAA,QAAU,OAAA,CAAQ,CAAA,GAClB,MAAA,EAAQ,WAAA,cACR,WAAA,IAAe,MAAA,EAAQ,CAAA,cACvB,IAAA,GAAM,gBAAA,GACL,OAAA,CAAQ,CAAA"}
@@ -0,0 +1,13 @@
1
+ //#region src/agent-runners/retry.d.ts
2
+ interface RetryConfig {
3
+ retries: number;
4
+ minTimeoutMs?: number;
5
+ factor?: number;
6
+ }
7
+ interface WithRetryOptions {
8
+ sleep?: (ms: number) => Promise<void>;
9
+ }
10
+ declare function withRetry<T>(fn: () => Promise<T>, config: RetryConfig | undefined, shouldRetry?: (result: T) => boolean, opts?: WithRetryOptions): Promise<T>;
11
+ //#endregion
12
+ export { RetryConfig, WithRetryOptions, withRetry };
13
+ //# sourceMappingURL=retry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.mts","names":[],"sources":["../../src/agent-runners/retry.ts"],"mappings":";UAAiB,WAAA;EACf,OAAA;EACA,YAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA,IAAS,EAAA,aAAe,OAAA;AAAA;AAAA,iBAMJ,SAAA,GAAA,CACpB,EAAA,QAAU,OAAA,CAAQ,CAAA,GAClB,MAAA,EAAQ,WAAA,cACR,WAAA,IAAe,MAAA,EAAQ,CAAA,cACvB,IAAA,GAAM,gBAAA,GACL,OAAA,CAAQ,CAAA"}
@@ -0,0 +1,30 @@
1
+ //#region src/agent-runners/retry.ts
2
+ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3
+ async function withRetry(fn, config, shouldRetry, opts = {}) {
4
+ const maxAttempts = Math.max(0, config?.retries ?? 0) + 1;
5
+ const minTimeoutMs = config?.minTimeoutMs ?? 0;
6
+ const factor = config?.factor ?? 2;
7
+ const sleep = opts.sleep ?? defaultSleep;
8
+ let lastError;
9
+ let lastResult;
10
+ let hasResult = false;
11
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
12
+ try {
13
+ const result = await fn();
14
+ if (shouldRetry?.(result) && attempt < maxAttempts - 1) {
15
+ lastResult = result;
16
+ hasResult = true;
17
+ } else return result;
18
+ } catch (err) {
19
+ lastError = err;
20
+ if (attempt === maxAttempts - 1) throw err;
21
+ }
22
+ if (minTimeoutMs > 0 && attempt < maxAttempts - 1) await sleep(minTimeoutMs * factor ** attempt);
23
+ }
24
+ if (hasResult) return lastResult;
25
+ throw lastError;
26
+ }
27
+
28
+ //#endregion
29
+ export { withRetry };
30
+ //# sourceMappingURL=retry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.mjs","names":[],"sources":["../../src/agent-runners/retry.ts"],"sourcesContent":["export interface RetryConfig {\n retries: number;\n minTimeoutMs?: number;\n factor?: number;\n}\n\nexport interface WithRetryOptions {\n sleep?: (ms: number) => Promise<void>;\n}\n\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n config: RetryConfig | undefined,\n shouldRetry?: (result: T) => boolean,\n opts: WithRetryOptions = {},\n): Promise<T> {\n const retries = Math.max(0, config?.retries ?? 0);\n const maxAttempts = retries + 1;\n const minTimeoutMs = config?.minTimeoutMs ?? 0;\n const factor = config?.factor ?? 2;\n const sleep = opts.sleep ?? defaultSleep;\n\n let lastError: unknown;\n let lastResult: T | undefined;\n let hasResult = false;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n const result = await fn();\n if (shouldRetry?.(result) && attempt < maxAttempts - 1) {\n lastResult = result;\n hasResult = true;\n } else {\n return result;\n }\n } catch (err) {\n lastError = err;\n if (attempt === maxAttempts - 1) throw err;\n }\n\n if (minTimeoutMs > 0 && attempt < maxAttempts - 1) {\n const delay = minTimeoutMs * factor ** attempt;\n await sleep(delay);\n }\n }\n\n if (hasResult) return lastResult as T;\n throw lastError;\n}\n"],"mappings":";AAUA,MAAM,gBAAgB,OACpB,IAAI,SAAS,YAAY,WAAW,SAAS,GAAG,CAAC;AAEnD,eAAsB,UACpB,IACA,QACA,aACA,OAAyB,EAAE,EACf;CAEZ,MAAM,cADU,KAAK,IAAI,GAAG,QAAQ,WAAW,EAAE,GACnB;CAC9B,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,QAAQ,KAAK,SAAS;CAE5B,IAAI;CACJ,IAAI;CACJ,IAAI,YAAY;AAEhB,MAAK,IAAI,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,MAAI;GACF,MAAM,SAAS,MAAM,IAAI;AACzB,OAAI,cAAc,OAAO,IAAI,UAAU,cAAc,GAAG;AACtD,iBAAa;AACb,gBAAY;SAEZ,QAAO;WAEF,KAAK;AACZ,eAAY;AACZ,OAAI,YAAY,cAAc,EAAG,OAAM;;AAGzC,MAAI,eAAe,KAAK,UAAU,cAAc,EAE9C,OAAM,MADQ,eAAe,UAAU,QACrB;;AAItB,KAAI,UAAW,QAAO;AACtB,OAAM"}
@@ -0,0 +1,276 @@
1
+ let ufo = require("ufo");
2
+
3
+ //#region src/agent-runners/scratchpad-afs.ts
4
+ /**
5
+ * @deprecated Phase 2 migrates scratch to the scope-local `/scratch/` mount.
6
+ * Kept only for the legacy read-path (old sessions) and removed in Phase 6.
7
+ */
8
+ const MEMORY_SCRATCH_ROOT = "/modules/memory";
9
+ /** Root path of the scope-local scratch mount created by `projectForChild`. */
10
+ const SCRATCH_SCOPE_ROOT = "/scratch";
11
+ function validatePathComponent(value, label) {
12
+ if (typeof value !== "string" || value.length === 0) throw new TypeError(`SCRATCH_INVALID_INPUT: ${label} must be a non-empty string`);
13
+ if (value.includes("..")) throw new Error(`SCRATCH_INVALID_INPUT: path traversal disallowed in ${label}`);
14
+ if (value.includes("\0")) throw new Error(`SCRATCH_INVALID_INPUT: null byte disallowed in ${label}`);
15
+ if (value.includes("/") || value.includes("\\")) throw new Error(`SCRATCH_INVALID_INPUT: path separator disallowed in ${label}`);
16
+ return value;
17
+ }
18
+ /**
19
+ * Reject scratch-local paths that try to escape the `/scratch/` root or
20
+ * smuggle control characters. Runs on every read/write/list/stat/delete
21
+ * against the scope-local mount.
22
+ */
23
+ function assertScratchPath(path) {
24
+ if (typeof path !== "string" || path.length === 0) throw new Error(`SCRATCH_INVALID_PATH: path must be a non-empty string`);
25
+ if (path.includes("\0")) throw new Error(`SCRATCH_INVALID_PATH: null byte disallowed`);
26
+ if (path.split("/").some((s) => s === "..")) throw new Error(`SCRATCH_INVALID_PATH: path traversal disallowed (".." segment)`);
27
+ }
28
+ /**
29
+ * @deprecated Use `createScratchProvider` + the scope-local `/scratch/` mount.
30
+ * Retained for the legacy read-path and removed in Phase 6.
31
+ */
32
+ function computeScratchLayout(session, runId) {
33
+ const basePath = (0, ufo.joinURL)(MEMORY_SCRATCH_ROOT, "runs", validatePathComponent(session, "session"), "subruns", validatePathComponent(runId, "runId"));
34
+ return {
35
+ basePath,
36
+ stateYml: (0, ufo.joinURL)(basePath, "state.yml"),
37
+ messagesJsonl: (0, ufo.joinURL)(basePath, "messages.jsonl"),
38
+ eventsJsonl: (0, ufo.joinURL)(basePath, "events.jsonl"),
39
+ historyJsonl: (0, ufo.joinURL)(basePath, "history.jsonl")
40
+ };
41
+ }
42
+ /**
43
+ * @deprecated Use the scope-local `/scratch/` mount (`createScratchProvider`).
44
+ * Kept for backwards compatibility with pre-Phase-2 callers; removed in P6.
45
+ */
46
+ async function provisionScratchViaAFS(afs, session, runId) {
47
+ if (!afs.write) throw new Error("SCRATCH_NO_WRITE: host AFS does not expose a write method");
48
+ const layout = computeScratchLayout(session, runId);
49
+ await afs.write(layout.stateYml, { content: "" });
50
+ await afs.write(layout.messagesJsonl, { content: "" });
51
+ await afs.write(layout.eventsJsonl, { content: "" });
52
+ await afs.write(layout.historyJsonl, { content: "" });
53
+ return layout;
54
+ }
55
+ /**
56
+ * @deprecated Scope teardown will manage scratch lifetime once P5 lands.
57
+ * Phase 2 keeps this helper for callers still operating on legacy sessions.
58
+ */
59
+ async function teardownScratchViaAFS(afs, session, retention = "session") {
60
+ if (retention === "forever" || retention === "run") return;
61
+ const s = validatePathComponent(session, "session");
62
+ const anyAfs = afs;
63
+ if (typeof anyAfs.delete !== "function") return;
64
+ const sessionPath = (0, ufo.joinURL)(MEMORY_SCRATCH_ROOT, "runs", s);
65
+ try {
66
+ await anyAfs.delete(sessionPath, { recursive: true });
67
+ } catch {}
68
+ }
69
+ function normalizeScratchPath(path) {
70
+ assertScratchPath(path);
71
+ if (path === SCRATCH_SCOPE_ROOT) return SCRATCH_SCOPE_ROOT;
72
+ if (path.startsWith(`${SCRATCH_SCOPE_ROOT}/`)) {
73
+ const trimmed = path.replace(/\/+$/, "");
74
+ return trimmed.length < 8 ? SCRATCH_SCOPE_ROOT : trimmed;
75
+ }
76
+ throw new Error(`SCRATCH_PATH_OUT_OF_SCOPE: ${path} is not inside ${SCRATCH_SCOPE_ROOT}/`);
77
+ }
78
+ function isScratchPath(path) {
79
+ return path === SCRATCH_SCOPE_ROOT || path.startsWith(`${SCRATCH_SCOPE_ROOT}/`);
80
+ }
81
+ function createScratchProvider(opts) {
82
+ validatePathComponent(opts.session, "session");
83
+ if (opts.runId !== void 0) validatePathComponent(opts.runId, "runId");
84
+ const retention = opts.retention ?? "session";
85
+ const store = /* @__PURE__ */ new Map();
86
+ return {
87
+ session: opts.session,
88
+ runId: opts.runId,
89
+ retention,
90
+ async read(path) {
91
+ const norm = normalizeScratchPath(path);
92
+ if (!store.has(norm)) return null;
93
+ return {
94
+ data: {
95
+ content: store.get(norm),
96
+ path: norm
97
+ },
98
+ path: norm
99
+ };
100
+ },
101
+ async write(path, payload) {
102
+ const norm = normalizeScratchPath(path);
103
+ if (norm === SCRATCH_SCOPE_ROOT) throw new Error(`SCRATCH_INVALID_PATH: cannot write to scratch root`);
104
+ const content = typeof payload?.content === "string" ? payload.content : "";
105
+ store.set(norm, content);
106
+ },
107
+ async list(path) {
108
+ const norm = normalizeScratchPath(path);
109
+ const prefix = norm === SCRATCH_SCOPE_ROOT ? `${SCRATCH_SCOPE_ROOT}/` : `${norm}/`;
110
+ const files = [];
111
+ const dirs = /* @__PURE__ */ new Set();
112
+ for (const stored of store.keys()) {
113
+ if (!stored.startsWith(prefix)) continue;
114
+ const rest = stored.slice(prefix.length);
115
+ const slash = rest.indexOf("/");
116
+ if (slash === -1) {
117
+ const content = store.get(stored) ?? "";
118
+ files.push({
119
+ name: rest,
120
+ path: stored,
121
+ type: "file",
122
+ size: Buffer.byteLength(content, "utf8")
123
+ });
124
+ } else {
125
+ const dir = rest.slice(0, slash);
126
+ dirs.add(dir);
127
+ }
128
+ }
129
+ const list = [];
130
+ for (const d of dirs) list.push({
131
+ name: d,
132
+ path: `${prefix}${d}`,
133
+ type: "dir",
134
+ size: 0
135
+ });
136
+ list.push(...files);
137
+ return {
138
+ data: list,
139
+ list
140
+ };
141
+ },
142
+ async stat(path) {
143
+ const norm = normalizeScratchPath(path);
144
+ if (norm === SCRATCH_SCOPE_ROOT) return { data: {
145
+ path: norm,
146
+ size: 0,
147
+ type: "dir"
148
+ } };
149
+ if (store.has(norm)) {
150
+ const content = store.get(norm);
151
+ return { data: {
152
+ path: norm,
153
+ size: Buffer.byteLength(content, "utf8"),
154
+ type: "file"
155
+ } };
156
+ }
157
+ const prefix = `${norm}/`;
158
+ for (const k of store.keys()) if (k.startsWith(prefix)) return { data: {
159
+ path: norm,
160
+ size: 0,
161
+ type: "dir"
162
+ } };
163
+ return null;
164
+ },
165
+ async delete(path, options) {
166
+ const norm = normalizeScratchPath(path);
167
+ if (norm === SCRATCH_SCOPE_ROOT) {
168
+ if (options?.recursive) {
169
+ store.clear();
170
+ return;
171
+ }
172
+ throw new Error(`SCRATCH_INVALID_PATH: cannot delete scratch root non-recursively`);
173
+ }
174
+ if (store.has(norm)) {
175
+ store.delete(norm);
176
+ return;
177
+ }
178
+ if (options?.recursive) {
179
+ const prefix = `${norm}/`;
180
+ for (const k of Array.from(store.keys())) if (k.startsWith(prefix)) store.delete(k);
181
+ }
182
+ },
183
+ clear() {
184
+ store.clear();
185
+ }
186
+ };
187
+ }
188
+ /**
189
+ * Overlay `/scratch/*` reads/writes/lists/stats/deletes onto the given AFS
190
+ * by routing them to the scratch provider. All other paths fall through to
191
+ * the underlying AFS via the prototype chain (Object.create).
192
+ *
193
+ * The overlay is stateless besides its reference to the provider — two
194
+ * scopes with different providers never see each other's scratch.
195
+ */
196
+ function attachScratchMount(afs, provider) {
197
+ const child = Object.create(afs);
198
+ Object.defineProperty(child, "read", {
199
+ value: async (path, options) => {
200
+ if (isScratchPath(path)) {
201
+ const result = await provider.read(path);
202
+ if (result) return result;
203
+ const err = /* @__PURE__ */ new Error(`SCRATCH_NOT_FOUND: ${path}`);
204
+ err.code = "NOT_FOUND";
205
+ throw err;
206
+ }
207
+ return afs.read.call(afs, path, options);
208
+ },
209
+ enumerable: false,
210
+ writable: false,
211
+ configurable: false
212
+ });
213
+ Object.defineProperty(child, "write", {
214
+ value: async (path, payload, options) => {
215
+ if (isScratchPath(path)) {
216
+ await provider.write(path, payload);
217
+ return {
218
+ success: true,
219
+ data: { path }
220
+ };
221
+ }
222
+ if (typeof afs.write !== "function") throw new Error(`SCRATCH_NO_UNDERLYING_WRITE: afs.write not available for ${path}`);
223
+ return afs.write.call(afs, path, payload, options);
224
+ },
225
+ enumerable: false,
226
+ writable: false,
227
+ configurable: false
228
+ });
229
+ Object.defineProperty(child, "list", {
230
+ value: async (path, options) => {
231
+ if (isScratchPath(path)) return provider.list(path);
232
+ return afs.list.call(afs, path, options);
233
+ },
234
+ enumerable: false,
235
+ writable: false,
236
+ configurable: false
237
+ });
238
+ Object.defineProperty(child, "stat", {
239
+ value: async (path, options) => {
240
+ if (isScratchPath(path)) {
241
+ const result = await provider.stat(path);
242
+ if (result) return result;
243
+ const err = /* @__PURE__ */ new Error(`SCRATCH_NOT_FOUND: ${path}`);
244
+ err.code = "NOT_FOUND";
245
+ throw err;
246
+ }
247
+ return afs.stat.call(afs, path, options);
248
+ },
249
+ enumerable: false,
250
+ writable: false,
251
+ configurable: false
252
+ });
253
+ Object.defineProperty(child, "delete", {
254
+ value: async (path, options) => {
255
+ if (isScratchPath(path)) {
256
+ await provider.delete(path, options);
257
+ return { success: true };
258
+ }
259
+ if (typeof afs.delete !== "function") return { success: false };
260
+ return afs.delete.call(afs, path, options);
261
+ },
262
+ enumerable: false,
263
+ writable: false,
264
+ configurable: false
265
+ });
266
+ return child;
267
+ }
268
+
269
+ //#endregion
270
+ exports.MEMORY_SCRATCH_ROOT = MEMORY_SCRATCH_ROOT;
271
+ exports.SCRATCH_SCOPE_ROOT = SCRATCH_SCOPE_ROOT;
272
+ exports.attachScratchMount = attachScratchMount;
273
+ exports.computeScratchLayout = computeScratchLayout;
274
+ exports.createScratchProvider = createScratchProvider;
275
+ exports.provisionScratchViaAFS = provisionScratchViaAFS;
276
+ exports.teardownScratchViaAFS = teardownScratchViaAFS;