@mono-agent/agent-app 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/README.md +304 -32
  2. package/dist/acp-bridge.d.ts.map +1 -1
  3. package/dist/acp-bridge.js +113 -54
  4. package/dist/acp-bridge.js.map +1 -1
  5. package/dist/acp-session-store.d.ts +12 -0
  6. package/dist/acp-session-store.d.ts.map +1 -0
  7. package/dist/acp-session-store.js +74 -0
  8. package/dist/acp-session-store.js.map +1 -0
  9. package/dist/agent-artifact-paths.d.ts +8 -0
  10. package/dist/agent-artifact-paths.d.ts.map +1 -0
  11. package/dist/agent-artifact-paths.js +11 -0
  12. package/dist/agent-artifact-paths.js.map +1 -0
  13. package/dist/agent-root-coordinator.d.ts +101 -0
  14. package/dist/agent-root-coordinator.d.ts.map +1 -0
  15. package/dist/agent-root-coordinator.js +470 -0
  16. package/dist/agent-root-coordinator.js.map +1 -0
  17. package/dist/app-controller-channels.d.ts +11 -1
  18. package/dist/app-controller-channels.d.ts.map +1 -1
  19. package/dist/app-controller-channels.js +145 -20
  20. package/dist/app-controller-channels.js.map +1 -1
  21. package/dist/app-controller-continuation.d.ts +2 -0
  22. package/dist/app-controller-continuation.d.ts.map +1 -1
  23. package/dist/app-controller-continuation.js.map +1 -1
  24. package/dist/app-controller-lifecycle.d.ts +5 -0
  25. package/dist/app-controller-lifecycle.d.ts.map +1 -1
  26. package/dist/app-controller-lifecycle.js +24 -5
  27. package/dist/app-controller-lifecycle.js.map +1 -1
  28. package/dist/app-controller-maintenance.d.ts +2 -0
  29. package/dist/app-controller-maintenance.d.ts.map +1 -1
  30. package/dist/app-controller-maintenance.js +32 -2
  31. package/dist/app-controller-maintenance.js.map +1 -1
  32. package/dist/app-controller-process-jobs.d.ts +46 -0
  33. package/dist/app-controller-process-jobs.d.ts.map +1 -0
  34. package/dist/app-controller-process-jobs.js +281 -0
  35. package/dist/app-controller-process-jobs.js.map +1 -0
  36. package/dist/app-controller-responder.d.ts +15 -0
  37. package/dist/app-controller-responder.d.ts.map +1 -1
  38. package/dist/app-controller-responder.js +146 -12
  39. package/dist/app-controller-responder.js.map +1 -1
  40. package/dist/app-controller-traceability.d.ts +6 -0
  41. package/dist/app-controller-traceability.d.ts.map +1 -1
  42. package/dist/app-controller-traceability.js +10 -0
  43. package/dist/app-controller-traceability.js.map +1 -1
  44. package/dist/app-controller-utils.d.ts +8 -0
  45. package/dist/app-controller-utils.d.ts.map +1 -1
  46. package/dist/app-controller-utils.js +24 -1
  47. package/dist/app-controller-utils.js.map +1 -1
  48. package/dist/app-controller.d.ts +40 -1
  49. package/dist/app-controller.d.ts.map +1 -1
  50. package/dist/app-controller.js +124 -39
  51. package/dist/app-controller.js.map +1 -1
  52. package/dist/background-log-maintenance.d.ts +85 -2
  53. package/dist/background-log-maintenance.d.ts.map +1 -1
  54. package/dist/background-log-maintenance.js +407 -136
  55. package/dist/background-log-maintenance.js.map +1 -1
  56. package/dist/background-runtime.d.ts.map +1 -1
  57. package/dist/background-runtime.js +22 -41
  58. package/dist/background-runtime.js.map +1 -1
  59. package/dist/background.d.ts +18 -26
  60. package/dist/background.d.ts.map +1 -1
  61. package/dist/background.js +83 -138
  62. package/dist/background.js.map +1 -1
  63. package/dist/channel-drivers/cron.d.ts +12 -1
  64. package/dist/channel-drivers/cron.d.ts.map +1 -1
  65. package/dist/channel-drivers/cron.js +121 -18
  66. package/dist/channel-drivers/cron.js.map +1 -1
  67. package/dist/channel-drivers/native-notify.d.ts +3 -0
  68. package/dist/channel-drivers/native-notify.d.ts.map +1 -1
  69. package/dist/channel-drivers/native-notify.js +2 -1
  70. package/dist/channel-drivers/native-notify.js.map +1 -1
  71. package/dist/channel-drivers/slack.d.ts.map +1 -1
  72. package/dist/channel-drivers/slack.js +41 -4
  73. package/dist/channel-drivers/slack.js.map +1 -1
  74. package/dist/channel-drivers/telegram.d.ts.map +1 -1
  75. package/dist/channel-drivers/telegram.js +46 -3
  76. package/dist/channel-drivers/telegram.js.map +1 -1
  77. package/dist/channel-drivers/tui.d.ts +13 -2
  78. package/dist/channel-drivers/tui.d.ts.map +1 -1
  79. package/dist/channel-drivers/tui.js +112 -3
  80. package/dist/channel-drivers/tui.js.map +1 -1
  81. package/dist/channels.d.ts +1 -1
  82. package/dist/channels.d.ts.map +1 -1
  83. package/dist/channels.js +4 -2
  84. package/dist/channels.js.map +1 -1
  85. package/dist/cli-args.d.ts +15 -1
  86. package/dist/cli-args.d.ts.map +1 -1
  87. package/dist/cli-args.js +82 -12
  88. package/dist/cli-args.js.map +1 -1
  89. package/dist/cli-background-command.d.ts +9 -2
  90. package/dist/cli-background-command.d.ts.map +1 -1
  91. package/dist/cli-background-command.js +174 -66
  92. package/dist/cli-background-command.js.map +1 -1
  93. package/dist/cli-commands.d.ts.map +1 -1
  94. package/dist/cli-commands.js +50 -12
  95. package/dist/cli-commands.js.map +1 -1
  96. package/dist/cli-help.d.ts.map +1 -1
  97. package/dist/cli-help.js +21 -1
  98. package/dist/cli-help.js.map +1 -1
  99. package/dist/config-reference.d.ts.map +1 -1
  100. package/dist/config-reference.js +99 -2
  101. package/dist/config-reference.js.map +1 -1
  102. package/dist/configured-agent.d.ts +44 -3
  103. package/dist/configured-agent.d.ts.map +1 -1
  104. package/dist/configured-agent.js +805 -156
  105. package/dist/configured-agent.js.map +1 -1
  106. package/dist/conversation-state-roots.d.ts +59 -0
  107. package/dist/conversation-state-roots.d.ts.map +1 -0
  108. package/dist/conversation-state-roots.js +248 -0
  109. package/dist/conversation-state-roots.js.map +1 -0
  110. package/dist/cron-control-store.d.ts +91 -0
  111. package/dist/cron-control-store.d.ts.map +1 -0
  112. package/dist/cron-control-store.js +1251 -0
  113. package/dist/cron-control-store.js.map +1 -0
  114. package/dist/cron-operator-service.d.ts +54 -0
  115. package/dist/cron-operator-service.d.ts.map +1 -0
  116. package/dist/cron-operator-service.js +352 -0
  117. package/dist/cron-operator-service.js.map +1 -0
  118. package/dist/doctor-session-history.d.ts +9 -0
  119. package/dist/doctor-session-history.d.ts.map +1 -0
  120. package/dist/doctor-session-history.js +313 -0
  121. package/dist/doctor-session-history.js.map +1 -0
  122. package/dist/doctor.d.ts +2 -1
  123. package/dist/doctor.d.ts.map +1 -1
  124. package/dist/doctor.js +320 -9
  125. package/dist/doctor.js.map +1 -1
  126. package/dist/index.d.ts +4 -0
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +2 -0
  129. package/dist/index.js.map +1 -1
  130. package/dist/interaction-bridge.d.ts +1 -0
  131. package/dist/interaction-bridge.d.ts.map +1 -1
  132. package/dist/interaction-bridge.js +54 -6
  133. package/dist/interaction-bridge.js.map +1 -1
  134. package/dist/jobs-command.d.ts +17 -0
  135. package/dist/jobs-command.d.ts.map +1 -0
  136. package/dist/jobs-command.js +207 -0
  137. package/dist/jobs-command.js.map +1 -0
  138. package/dist/launchd-lifecycle-lock.d.ts +36 -0
  139. package/dist/launchd-lifecycle-lock.d.ts.map +1 -0
  140. package/dist/launchd-lifecycle-lock.js +124 -0
  141. package/dist/launchd-lifecycle-lock.js.map +1 -0
  142. package/dist/launchd-log-monitor-status.d.ts +7 -0
  143. package/dist/launchd-log-monitor-status.d.ts.map +1 -0
  144. package/dist/launchd-log-monitor-status.js +224 -0
  145. package/dist/launchd-log-monitor-status.js.map +1 -0
  146. package/dist/launchd-logs.d.ts +9 -1
  147. package/dist/launchd-logs.d.ts.map +1 -1
  148. package/dist/launchd-logs.js +69 -16
  149. package/dist/launchd-logs.js.map +1 -1
  150. package/dist/launchd-maintenance-command.d.ts +10 -0
  151. package/dist/launchd-maintenance-command.d.ts.map +1 -0
  152. package/dist/launchd-maintenance-command.js +2 -0
  153. package/dist/launchd-maintenance-command.js.map +1 -0
  154. package/dist/launchd-maintenance-entry.d.ts +30 -0
  155. package/dist/launchd-maintenance-entry.d.ts.map +1 -0
  156. package/dist/launchd-maintenance-entry.js +206 -0
  157. package/dist/launchd-maintenance-entry.js.map +1 -0
  158. package/dist/launchd-maintenance-gate.d.ts +28 -0
  159. package/dist/launchd-maintenance-gate.d.ts.map +1 -0
  160. package/dist/launchd-maintenance-gate.js +80 -0
  161. package/dist/launchd-maintenance-gate.js.map +1 -0
  162. package/dist/launchd-private-files.d.ts +3 -0
  163. package/dist/launchd-private-files.d.ts.map +1 -0
  164. package/dist/launchd-private-files.js +58 -0
  165. package/dist/launchd-private-files.js.map +1 -0
  166. package/dist/launchd.d.ts +56 -2
  167. package/dist/launchd.d.ts.map +1 -1
  168. package/dist/launchd.js +210 -5
  169. package/dist/launchd.js.map +1 -1
  170. package/dist/local-configuration.d.ts.map +1 -1
  171. package/dist/local-configuration.js +33 -7
  172. package/dist/local-configuration.js.map +1 -1
  173. package/dist/managed-launchd-maintenance-environment.d.ts +3 -0
  174. package/dist/managed-launchd-maintenance-environment.d.ts.map +1 -0
  175. package/dist/managed-launchd-maintenance-environment.js +12 -0
  176. package/dist/managed-launchd-maintenance-environment.js.map +1 -0
  177. package/dist/managed-runtime-launch-proof.d.ts +11 -0
  178. package/dist/managed-runtime-launch-proof.d.ts.map +1 -0
  179. package/dist/managed-runtime-launch-proof.js +59 -0
  180. package/dist/managed-runtime-launch-proof.js.map +1 -0
  181. package/dist/managed-runtime-maintenance-entry.d.ts +10 -0
  182. package/dist/managed-runtime-maintenance-entry.d.ts.map +1 -0
  183. package/dist/managed-runtime-maintenance-entry.js +244 -0
  184. package/dist/managed-runtime-maintenance-entry.js.map +1 -0
  185. package/dist/managed-web-logs.d.ts +29 -11
  186. package/dist/managed-web-logs.d.ts.map +1 -1
  187. package/dist/managed-web-logs.js +244 -121
  188. package/dist/managed-web-logs.js.map +1 -1
  189. package/dist/managed-web-maintenance-environment.d.ts +6 -0
  190. package/dist/managed-web-maintenance-environment.d.ts.map +1 -0
  191. package/dist/managed-web-maintenance-environment.js +19 -0
  192. package/dist/managed-web-maintenance-environment.js.map +1 -0
  193. package/dist/mcp-apps.d.ts +37 -0
  194. package/dist/mcp-apps.d.ts.map +1 -0
  195. package/dist/mcp-apps.js +1753 -0
  196. package/dist/mcp-apps.js.map +1 -0
  197. package/dist/memory-command.d.ts +12 -0
  198. package/dist/memory-command.d.ts.map +1 -1
  199. package/dist/memory-command.js +510 -1
  200. package/dist/memory-command.js.map +1 -1
  201. package/dist/modules/known-tools.d.ts +1 -1
  202. package/dist/modules/known-tools.d.ts.map +1 -1
  203. package/dist/modules/known-tools.js +2 -0
  204. package/dist/modules/known-tools.js.map +1 -1
  205. package/dist/posted-reply-history.d.ts.map +1 -1
  206. package/dist/posted-reply-history.js +12 -0
  207. package/dist/posted-reply-history.js.map +1 -1
  208. package/dist/proactive-notify.d.ts +4 -1
  209. package/dist/proactive-notify.d.ts.map +1 -1
  210. package/dist/proactive-notify.js +43 -5
  211. package/dist/proactive-notify.js.map +1 -1
  212. package/dist/process-jobs-config.d.ts +82 -0
  213. package/dist/process-jobs-config.d.ts.map +1 -0
  214. package/dist/process-jobs-config.js +423 -0
  215. package/dist/process-jobs-config.js.map +1 -0
  216. package/dist/process-jobs-context.d.ts +24 -0
  217. package/dist/process-jobs-context.d.ts.map +1 -0
  218. package/dist/process-jobs-context.js +135 -0
  219. package/dist/process-jobs-context.js.map +1 -0
  220. package/dist/process-jobs-root-registry.d.ts +115 -0
  221. package/dist/process-jobs-root-registry.d.ts.map +1 -0
  222. package/dist/process-jobs-root-registry.js +978 -0
  223. package/dist/process-jobs-root-registry.js.map +1 -0
  224. package/dist/process-jobs-runtime.d.ts +35 -0
  225. package/dist/process-jobs-runtime.d.ts.map +1 -0
  226. package/dist/process-jobs-runtime.js +177 -0
  227. package/dist/process-jobs-runtime.js.map +1 -0
  228. package/dist/process-jobs-service.d.ts +70 -0
  229. package/dist/process-jobs-service.d.ts.map +1 -0
  230. package/dist/process-jobs-service.js +1989 -0
  231. package/dist/process-jobs-service.js.map +1 -0
  232. package/dist/process-jobs-store.d.ts +151 -0
  233. package/dist/process-jobs-store.d.ts.map +1 -0
  234. package/dist/process-jobs-store.js +1290 -0
  235. package/dist/process-jobs-store.js.map +1 -0
  236. package/dist/reply-artifacts.d.ts +65 -0
  237. package/dist/reply-artifacts.d.ts.map +1 -0
  238. package/dist/reply-artifacts.js +1147 -0
  239. package/dist/reply-artifacts.js.map +1 -0
  240. package/dist/reply-part-budget.d.ts +16 -0
  241. package/dist/reply-part-budget.d.ts.map +1 -0
  242. package/dist/reply-part-budget.js +57 -0
  243. package/dist/reply-part-budget.js.map +1 -0
  244. package/dist/request-model-override.d.ts +19 -0
  245. package/dist/request-model-override.d.ts.map +1 -1
  246. package/dist/request-model-override.js +54 -1
  247. package/dist/request-model-override.js.map +1 -1
  248. package/dist/request-scoped-mcp.d.ts +31 -0
  249. package/dist/request-scoped-mcp.d.ts.map +1 -0
  250. package/dist/request-scoped-mcp.js +197 -0
  251. package/dist/request-scoped-mcp.js.map +1 -0
  252. package/dist/run-history.d.ts.map +1 -1
  253. package/dist/run-history.js +50 -254
  254. package/dist/run-history.js.map +1 -1
  255. package/dist/runtime-option-extensions.d.ts +21 -0
  256. package/dist/runtime-option-extensions.d.ts.map +1 -1
  257. package/dist/runtime-option-extensions.js +53 -0
  258. package/dist/runtime-option-extensions.js.map +1 -1
  259. package/dist/secure-file-replace.d.ts +3 -0
  260. package/dist/secure-file-replace.d.ts.map +1 -1
  261. package/dist/secure-file-replace.js +31 -7
  262. package/dist/secure-file-replace.js.map +1 -1
  263. package/dist/session-history.d.ts +146 -0
  264. package/dist/session-history.d.ts.map +1 -0
  265. package/dist/session-history.js +347 -0
  266. package/dist/session-history.js.map +1 -0
  267. package/dist/sessions.d.ts +45 -2
  268. package/dist/sessions.d.ts.map +1 -1
  269. package/dist/sessions.js +849 -30
  270. package/dist/sessions.js.map +1 -1
  271. package/dist/web-command.d.ts +12 -11
  272. package/dist/web-command.d.ts.map +1 -1
  273. package/dist/web-command.js +554 -80
  274. package/dist/web-command.js.map +1 -1
  275. package/dist/web-log-maintenance-command.d.ts +7 -0
  276. package/dist/web-log-maintenance-command.d.ts.map +1 -0
  277. package/dist/web-log-maintenance-command.js +21 -0
  278. package/dist/web-log-maintenance-command.js.map +1 -0
  279. package/dist/web-log-maintenance-status.d.ts +26 -0
  280. package/dist/web-log-maintenance-status.d.ts.map +1 -0
  281. package/dist/web-log-maintenance-status.js +171 -0
  282. package/dist/web-log-maintenance-status.js.map +1 -0
  283. package/dist/web-log-maintenance.d.ts +32 -0
  284. package/dist/web-log-maintenance.d.ts.map +1 -0
  285. package/dist/web-log-maintenance.js +163 -0
  286. package/dist/web-log-maintenance.js.map +1 -0
  287. package/dist/web-maintenance-paths.d.ts +12 -0
  288. package/dist/web-maintenance-paths.d.ts.map +1 -0
  289. package/dist/web-maintenance-paths.js +24 -0
  290. package/dist/web-maintenance-paths.js.map +1 -0
  291. package/dist/wizard/prompts.d.ts.map +1 -1
  292. package/dist/wizard/prompts.js +1 -0
  293. package/dist/wizard/prompts.js.map +1 -1
  294. package/dist/wizard/run.js +1 -1
  295. package/dist/wizard/run.js.map +1 -1
  296. package/package.json +15 -15
  297. package/schema/mono-agent.config.schema.json +102 -1
  298. package/skills/mono-agent-composer/references/config-blueprint.md +26 -2
  299. package/skills/mono-agent-composer/references/discovery-questions.md +2 -2
  300. package/skills/mono-agent-composer/references/feature-coverage.md +6 -4
  301. package/skills/mono-agent-composer/references/package-map.md +19 -3
  302. package/skills/mono-agent-composer/references/playbooks.md +3 -3
  303. package/skills/mono-agent-composer/references/validation.md +4 -2
@@ -1,4 +1,4 @@
1
- import { createAgentHarness, createAgentResponder, createDurableHistoryStore, createToolPolicy, loadToolPolicyFromJsonFileSync, renderSkillIndexSection, } from "@mono-agent/agent-harness";
1
+ import { createAgentHarness, createAgentResponder, acquireToolHistoryWriter, createDurableHistoryStore, createToolPolicy, loadToolPolicyFromJsonFileSync, renderSkillIndexSection, ToolHistoryReader, toolHistoryLogicalConversationId, } from "@mono-agent/agent-harness";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { resolve as resolvePath } from "node:path";
@@ -6,11 +6,16 @@ import { setToolActivityPathRoots } from "@mono-agent/agent-contracts";
6
6
  import { resolveSupermemoryContainer } from "@mono-agent/config";
7
7
  import { createCompositeRunRecorder, createJsonlRunRecorder } from "@mono-agent/observability";
8
8
  import { createPhoenixRunExporter } from "@mono-agent/observability/otel";
9
- import { assertExecutionModeCompatible, createMonoRuntime, createPiOAuthApiKeyResolver, defaultExecutionModeForModel, describeMonoRuntimeSupport, modelReferenceKey, monoRuntimeSupportsSessionResume, parseMonoRuntimeModelReference, runtimeOptionsForLocalProvider, } from "@mono-agent/runtime-adapter";
9
+ import { assertExecutionModeCompatible, createMonoRuntime, createPiOAuthApiKeyResolver, createSrtSandboxEngine, defaultExecutionModeForModel, describeMonoRuntimeSupport, modelReferenceKey, monoRuntimeSupportsSessionResume, parseMonoRuntimeModelReference, runtimeOptionsForLocalProvider, mergeSandboxPolicies, } from "@mono-agent/runtime-adapter";
10
+ import { agentArtifactDerivedRoots } from "./agent-artifact-paths.js";
11
+ import { acquireAgentRootOwnership, assertAgentRootLeaseOutsideWorkspace, releaseAgentRootOwnershipWhenIdle, } from "./agent-root-coordinator.js";
10
12
  import { resolveMemoryRecallSettings } from "./memory-recall.js";
11
13
  import { BUILTIN_TOOL_NAMES, canonicalToolName, isAllowAllTools } from "./modules/known-tools.js";
12
14
  import { createSharedMemoryRecallRuntimeExtension, isSharedRecallStore, MemoryRetrievalService, } from "./memory-retrieval.js";
13
- import { composeRuntimeOptionExtensions } from "./runtime-option-extensions.js";
15
+ import { clearSessionsSandboxPolicy, composeRuntimeOptionExtensions, createClearSessionsRuntimeExtension, } from "./runtime-option-extensions.js";
16
+ import { configuredRuntimeFallbackModels, runtimeUsesFallbackRouter, } from "./runtime-routes.js";
17
+ import { createProcessJobsRuntimeExtension, processJobsSandboxPolicy, PROCESS_JOBS_PI_NATIVE_REQUIRED_ERROR, PROCESS_JOBS_PROTECTION_UNAVAILABLE_ERROR, } from "./process-jobs-runtime.js";
18
+ import { attestProcessJobsRootRegistrySnapshot, loadProcessJobsRootRegistryProtection, processJobsProtectionPolicyRoots, registerProcessJobsRoot, } from "./process-jobs-root-registry.js";
14
19
  import { isReadSkillDenied } from "./skill-registry.js";
15
20
  import { loadSupermemoryPlugin } from "./supermemory-plugin.js";
16
21
  /**
@@ -148,10 +153,20 @@ function recorderCompositionDeps(config, options, internalHooks = {}) {
148
153
  export function createConfiguredAgentRuntime(input) {
149
154
  const config = isRuntimeOptions(input) ? input.config : input;
150
155
  const options = isRuntimeOptions(input) ? input : undefined;
156
+ return wrapOwnedConfiguredRuntime(createConfiguredAgentRuntimeBase(config, options), config, options?.cwd, options?.sandboxEngine);
157
+ }
158
+ /** @internal App/harness seam; callers are already inside the shared root/request choke point. */
159
+ export function createConfiguredAgentRuntimeForApp(input) {
160
+ const config = isRuntimeOptions(input) ? input.config : input;
161
+ const options = isRuntimeOptions(input) ? input : undefined;
162
+ return createConfiguredAgentRuntimeBase(config, options);
163
+ }
164
+ function createConfiguredAgentRuntimeBase(config, options) {
151
165
  const fallback = fallbackChainForConfig(config, options);
166
+ const sandboxEngine = configuredSandboxEngine(config, options?.model ?? config.runtime.model, options?.sandboxEngine);
152
167
  const runtimeOptions = {
153
168
  ...runtimeHostOptionsForConfig(config),
154
- ...(options?.sandboxEngine === undefined ? {} : { sandboxEngine: options.sandboxEngine }),
169
+ ...(sandboxEngine === undefined ? {} : { sandboxEngine }),
155
170
  ...fallback,
156
171
  ...(fallback.fallbackChain === undefined
157
172
  ? {}
@@ -175,6 +190,107 @@ export function createConfiguredAgentRuntime(input) {
175
190
  };
176
191
  return createMonoRuntime(runtimeOptions);
177
192
  }
193
+ function configuredSandboxEngine(config, primaryModel, explicit) {
194
+ if (explicit !== undefined)
195
+ return explicit;
196
+ return [primaryModel, ...configuredRuntimeFallbackModels(config.runtime)]
197
+ .some((model) => model.sdk === "pi")
198
+ ? createSrtSandboxEngine()
199
+ : undefined;
200
+ }
201
+ function wrapOwnedConfiguredRuntime(runtime, config, agentRoot, configuredSandboxEngine) {
202
+ let security;
203
+ let disposed = false;
204
+ const loadSecurity = async () => {
205
+ const ownership = await acquireAgentRootOwnership(agentRoot);
206
+ try {
207
+ assertAgentRootLeaseOutsideWorkspace(ownership, config.runtime.workspace);
208
+ return { ownership };
209
+ }
210
+ catch (error) {
211
+ await releaseAgentRootOwnershipWhenIdle(ownership).catch(() => undefined);
212
+ throw error;
213
+ }
214
+ };
215
+ const secured = () => (security ??= loadSecurity());
216
+ const releaseOwnership = async () => {
217
+ const current = security;
218
+ security = undefined;
219
+ if (current === undefined)
220
+ return;
221
+ const { ownership } = await current.catch(() => ({ ownership: undefined }));
222
+ if (ownership !== undefined) {
223
+ await releaseAgentRootOwnershipWhenIdle(ownership);
224
+ }
225
+ };
226
+ return {
227
+ async run(systemPrompt, runOptions) {
228
+ if (disposed)
229
+ throw new Error("Configured runtime has been disposed.");
230
+ const { ownership } = await secured();
231
+ const registry = await loadProcessJobsRootRegistryProtection(ownership.agentRoot, config.runtime.workspace);
232
+ ownership.coordinator.synchronizeGeneration(registry.generation);
233
+ const boundary = await attestProcessJobsRootRegistrySnapshot(registry, config.runtime.workspace);
234
+ if (disposed)
235
+ throw new Error("Configured runtime has been disposed.");
236
+ const lease = ownership.coordinator.acquireRequestLease(boundary.generation);
237
+ try {
238
+ const attested = await attestProcessJobsRootRegistrySnapshot(boundary, config.runtime.workspace);
239
+ const protectedRoots = processJobsProtectionPolicyRoots(attested);
240
+ let effectiveOptions = runOptions;
241
+ if (protectedRoots.length > 0) {
242
+ if (!configuredRoutesOnlyPiNative(config, runOptions.model)) {
243
+ throw new Error(PROCESS_JOBS_PI_NATIVE_REQUIRED_ERROR);
244
+ }
245
+ if (runOptions.model.sdk !== "pi")
246
+ throw new Error(PROCESS_JOBS_PI_NATIVE_REQUIRED_ERROR);
247
+ const sandboxEngine = runOptions.sandboxEngine
248
+ ?? configuredSandboxEngine
249
+ ?? createSrtSandboxEngine();
250
+ if (!await sandboxEngine.isAvailable().catch(() => false)) {
251
+ throw new Error(PROCESS_JOBS_PROTECTION_UNAVAILABLE_ERROR);
252
+ }
253
+ const sandboxPolicy = mergeSandboxPolicies(runOptions.sandboxPolicy, processJobsSandboxPolicy({ coreConfig: config, protectedRoots }));
254
+ if (sandboxPolicy === undefined) {
255
+ throw new Error(PROCESS_JOBS_PROTECTION_UNAVAILABLE_ERROR);
256
+ }
257
+ effectiveOptions = {
258
+ ...runOptions,
259
+ sandboxPolicy,
260
+ sandboxEngine,
261
+ };
262
+ }
263
+ return await runtime.run(systemPrompt, effectiveOptions);
264
+ }
265
+ finally {
266
+ lease.releaseAfterSettlement();
267
+ }
268
+ },
269
+ ...(runtime.configureTools === undefined
270
+ ? {}
271
+ : { configureTools: runtime.configureTools.bind(runtime) }),
272
+ ...(runtime.syncSession === undefined ? {} : { syncSession: runtime.syncSession.bind(runtime) }),
273
+ ...(runtime.refreshSession === undefined ? {} : { refreshSession: runtime.refreshSession.bind(runtime) }),
274
+ ...(runtime.retireDurableSession === undefined
275
+ ? {}
276
+ : { retireDurableSession: runtime.retireDurableSession.bind(runtime) }),
277
+ ...(runtime.disposeSession === undefined ? {} : { disposeSession: runtime.disposeSession.bind(runtime) }),
278
+ ...(runtime.invalidateSession === undefined
279
+ ? {}
280
+ : { invalidateSession: runtime.invalidateSession.bind(runtime) }),
281
+ async disposeAllSessions() {
282
+ if (disposed)
283
+ return;
284
+ disposed = true;
285
+ try {
286
+ await runtime.disposeAllSessions?.();
287
+ }
288
+ finally {
289
+ await releaseOwnership();
290
+ }
291
+ },
292
+ };
293
+ }
178
294
  /**
179
295
  * Narrow the loaded MCP servers to the ones a profile names.
180
296
  *
@@ -327,6 +443,9 @@ function subagentsRuntimeOptions(config, deps) {
327
443
  const childSystemPrompt = childSkills === undefined
328
444
  ? request.systemPrompt
329
445
  : `${request.systemPrompt}\n\n${renderSkillIndexSection(childSkills)}`;
446
+ if (childModel.sdk !== "pi" && sandboxPolicyCarriesProtectedRoots(request.sandboxPolicy)) {
447
+ throw new Error(PROCESS_JOBS_PI_NATIVE_REQUIRED_ERROR);
448
+ }
330
449
  return await runtime.run(childSystemPrompt, {
331
450
  model: childModel,
332
451
  executionMode: childExecutionMode,
@@ -446,6 +565,27 @@ function fallbackChainForConfig(config, options) {
446
565
  ],
447
566
  };
448
567
  }
568
+ function configuredRoutesOnlyPiNative(config, primary) {
569
+ try {
570
+ const fallback = fallbackChainForConfig(config, { config, model: primary });
571
+ const routes = fallback.fallbackChain?.map((entry) => entry.model) ?? [primary];
572
+ return routes.length > 0 && routes.every((model) => model.sdk === "pi");
573
+ }
574
+ catch {
575
+ return false;
576
+ }
577
+ }
578
+ function sandboxPolicyCarriesProtectedRoots(policy) {
579
+ if (policy === undefined || policy === null || typeof policy !== "object")
580
+ return false;
581
+ try {
582
+ const roots = policy.protectedRoots;
583
+ return roots !== undefined && (!Array.isArray(roots) || roots.length > 0);
584
+ }
585
+ catch {
586
+ return true;
587
+ }
588
+ }
449
589
  let memoryBujoModule;
450
590
  let memorySearchModule;
451
591
  const loadMemoryBujoModule = async () => (memoryBujoModule ??= await import("@mono-agent/memory/bujo"));
@@ -455,156 +595,562 @@ export async function createConfiguredAgentHarness(options) {
455
595
  }
456
596
  async function createConfiguredAgentHarnessInternal(options, internalHooks = {}) {
457
597
  const config = options.config;
458
- // Chat activity lines are formatted deep in the streaming layer, which has no
459
- // per-message workspace to hand down. Without this the root falls back to
460
- // `process.cwd()` for a service-managed agent, whatever directory the
461
- // supervisor started it in — and tool previews expose the full machine layout.
462
- setToolActivityPathRoots({ workspaceRoot: config.runtime.workspace, homeDir: homedir() });
463
- const model = options.model ?? config.runtime.model;
464
- const executionMode = options.executionMode ?? config.runtime.executionMode;
465
- const runtime = options.runtime ?? createConfiguredAgentRuntime({
466
- config,
467
- model,
468
- executionMode,
469
- ...(options.sandboxEngine === undefined ? {} : { sandboxEngine: options.sandboxEngine }),
470
- });
471
- // The memory LLM must NOT ride the channel `runtime`: that runtime carries the
472
- // channel fallback chain whose primary is `config.runtime.model`, and the
473
- // fallback router overrides each run's per-call `model` — so reusing it would
474
- // execute memory capture on `config.runtime.model` instead of
475
- // `config.memory.llm.model`. createConfiguredMemory builds the memory LLM its own
476
- // fallback-free runtime when no `memoryRuntime` is injected.
477
- const configuredMemory = options.memory ?? (await createConfiguredMemory(config, {
478
- ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
479
- }));
480
- const memory = configuredMemoryForHarness(config, configuredMemory);
481
- const memoryRecall = resolveMemoryRecallSettings(config) === undefined
482
- || !(memory instanceof MemoryRetrievalService)
483
- ? undefined
484
- : createSharedMemoryRecallRuntimeExtension(memory, {
485
- ...(options.onMemoryRecallUnavailable === undefined
598
+ const ownership = await acquireAgentRootOwnership(options.cwd ?? process.cwd());
599
+ const agentRoot = ownership.agentRoot;
600
+ let ownershipTransferred = false;
601
+ try {
602
+ assertAgentRootLeaseOutsideWorkspace(ownership, config.runtime.workspace);
603
+ const processJobsRegistry = internalHooks.processJobs?.registry
604
+ ?? (internalHooks.bootstrapProcessJobsStateDir === undefined
605
+ ? await loadProcessJobsRootRegistryProtection(ownership.agentRoot, config.runtime.workspace)
606
+ : (await registerProcessJobsRoot({
607
+ agentRoot: ownership.agentRoot,
608
+ workspace: config.runtime.workspace,
609
+ stateDir: internalHooks.bootstrapProcessJobsStateDir,
610
+ coordinator: ownership.coordinator,
611
+ })).snapshot);
612
+ ownership.coordinator.synchronizeGeneration(processJobsRegistry.generation);
613
+ const processJobsProtectedRoots = processJobsProtectionPolicyRoots(processJobsRegistry);
614
+ const artifactDerivedRoots = agentArtifactDerivedRoots(config.artifacts.dir);
615
+ // Chat activity lines are formatted deep in the streaming layer, which has no
616
+ // per-message workspace to hand down. Without this the root falls back to
617
+ // `process.cwd()` for a service-managed agent, whatever directory the
618
+ // supervisor started it in and tool previews expose the full machine layout.
619
+ setToolActivityPathRoots({ workspaceRoot: config.runtime.workspace, homeDir: homedir() });
620
+ const model = options.model ?? config.runtime.model;
621
+ const executionMode = options.executionMode ?? config.runtime.executionMode;
622
+ const fallbackModels = configuredRuntimeFallbackModels(config.runtime);
623
+ const sandboxEngine = configuredSandboxEngine(config, model, options.sandboxEngine);
624
+ const harnessSandboxPolicy = processJobsProtectedRoots.length === 0
625
+ ? config.sandbox
626
+ : processJobsSandboxPolicy({ coreConfig: config, protectedRoots: processJobsProtectedRoots });
627
+ const runtime = options.runtime ?? createConfiguredAgentRuntimeForApp({
628
+ config,
629
+ cwd: agentRoot,
630
+ model,
631
+ executionMode,
632
+ ...(sandboxEngine === undefined ? {} : { sandboxEngine }),
633
+ });
634
+ const clearSessionsBoundaryOptions = {
635
+ cwd: agentRoot,
636
+ workspace: config.runtime.workspace,
637
+ baseModel: model,
638
+ fallbackModels,
639
+ ...(harnessSandboxPolicy === undefined ? {} : { sandboxPolicy: harnessSandboxPolicy }),
640
+ };
641
+ const routedClearSessionsPolicy = runtimeUsesFallbackRouter(config.runtime)
642
+ ? clearSessionsSandboxPolicy(clearSessionsBoundaryOptions)
643
+ : undefined;
644
+ // Request policy is still attested and applied per turn below. Configure the
645
+ // same stable engine/policy into the routed ToolContext so Pi filesystem
646
+ // builtins resolve their native boundary there; per-route-native projection
647
+ // clears both fields from every non-Pi attempt.
648
+ runtime.configureTools?.({
649
+ workspace: config.runtime.workspace,
650
+ ...(sandboxEngine === undefined ? {} : { sandboxEngine }),
651
+ ...(routedClearSessionsPolicy === undefined ? {} : { sandboxPolicy: routedClearSessionsPolicy }),
652
+ });
653
+ // The memory LLM must NOT ride the channel `runtime`: that runtime carries the
654
+ // channel fallback chain whose primary is `config.runtime.model`, and the
655
+ // fallback router overrides each run's per-call `model` — so reusing it would
656
+ // execute memory capture on `config.runtime.model` instead of
657
+ // `config.memory.llm.model`. createConfiguredMemory builds the memory LLM its own
658
+ // fallback-free runtime when no `memoryRuntime` is injected.
659
+ const configuredMemory = options.memory ?? (await createConfiguredMemory(config, {
660
+ cwd: agentRoot,
661
+ }));
662
+ const memory = configuredMemoryForHarness(config, configuredMemory);
663
+ const memoryRecall = resolveMemoryRecallSettings(config) === undefined
664
+ || !(memory instanceof MemoryRetrievalService)
665
+ ? undefined
666
+ : createSharedMemoryRecallRuntimeExtension(memory, {
667
+ ...(options.onMemoryRecallUnavailable === undefined
668
+ ? {}
669
+ : { onUnavailable: options.onMemoryRecallUnavailable }),
670
+ });
671
+ const composedRuntimeOptionsForRequest = composeRuntimeOptionExtensions([
672
+ memoryRecall,
673
+ options.runtimeOptionsForRequest,
674
+ ], {
675
+ // The app-owned, read-only MemoryRecall endpoint is part of every configured
676
+ // memory tier. Preserve only this exact extension under an authenticated
677
+ // request override; arbitrary caller/action MCP extensions remain excluded.
678
+ preserveMcpServersUnderOverride: memoryRecall === undefined ? [] : [memoryRecall],
679
+ });
680
+ const clearSessionsRuntimeOptionsForRequest = createClearSessionsRuntimeExtension(composedRuntimeOptionsForRequest, clearSessionsBoundaryOptions);
681
+ const runtimeOptionsForRequest = createProcessJobsRuntimeExtension({
682
+ next: clearSessionsRuntimeOptionsForRequest,
683
+ ownership,
684
+ registry: processJobsRegistry,
685
+ service: internalHooks.processJobs?.service,
686
+ coreConfig: config,
687
+ baseModel: model,
688
+ channelId: internalHooks.processJobs?.channelId,
689
+ sandboxEngine,
690
+ routesOnlyPiNative: internalHooks.processJobs?.routesOnlyPiNative
691
+ ?? (() => configuredRoutesOnlyPiNative(config, model)),
692
+ });
693
+ const subagents = subagentsRuntimeOptions(config, {
694
+ runtime,
695
+ baseModel: model,
696
+ baseExecutionMode: executionMode,
697
+ ...(options.runtimeForModel === undefined ? {} : { runtimeForModel: options.runtimeForModel }),
698
+ });
699
+ const runtimeOptions = mergeStaticRuntimeOptions(runtimeOptionsForLocalProvider(model, config.providers?.local), configRuntimeFlags(config), sandboxEngine === undefined ? undefined : { sandboxEngine }, subagents, options.runtimeOptions);
700
+ const sessionOptions = {
701
+ mode: config.runtime.session.mode,
702
+ idleTimeoutMs: config.runtime.session.idleTimeoutMs,
703
+ // Any fallback makes the logical run stateless. A provider-owned session
704
+ // cannot safely cross the route boundary, even when both bridges happen to
705
+ // expose resume support. History replay remains available to every attempt.
706
+ supportsResume: hasConfiguredFallback(config)
707
+ ? false
708
+ : supportsSessionResume(model, executionMode),
709
+ ...(config.runtime.session.isolateProactive === undefined
710
+ ? {}
711
+ : { isolateProactive: config.runtime.session.isolateProactive }),
712
+ ...(options.onSessionEvent === undefined ? {} : { onSessionEvent: options.onSessionEvent }),
713
+ };
714
+ const piSessionsRoot = config.providers?.piNative?.piSessionsRoot;
715
+ const retireDurableSession = runtime.retireDurableSession?.bind(runtime);
716
+ const historyRoot = artifactDerivedRoots.history;
717
+ const baseHistoryStore = options.historyStore ?? createDurableHistoryStore({
718
+ root: historyRoot,
719
+ maxMessages: DEFAULT_HISTORY_MAX_MESSAGES,
720
+ ...(piSessionsRoot === undefined || retireDurableSession === undefined
486
721
  ? {}
487
- : { onUnavailable: options.onMemoryRecallUnavailable }),
722
+ : {
723
+ retireProviderSession: async (providerSessionId) => {
724
+ await retireDurableSession(providerSessionId, piSessionsRoot);
725
+ },
726
+ }),
488
727
  });
489
- const runtimeOptionsForRequest = composeRuntimeOptionExtensions([
490
- memoryRecall,
491
- options.runtimeOptionsForRequest,
492
- ], {
493
- // The app-owned, read-only MemoryRecall endpoint is part of every configured
494
- // memory tier. Preserve only this exact extension under an authenticated
495
- // request override; arbitrary caller/action MCP extensions remain excluded.
496
- preserveMcpServersUnderOverride: memoryRecall === undefined ? [] : [memoryRecall],
497
- });
498
- const subagents = subagentsRuntimeOptions(config, {
499
- runtime,
500
- baseModel: model,
501
- baseExecutionMode: executionMode,
502
- ...(options.runtimeForModel === undefined ? {} : { runtimeForModel: options.runtimeForModel }),
503
- });
504
- const runtimeOptions = mergeStaticRuntimeOptions(runtimeOptionsForLocalProvider(model, config.providers?.local), configRuntimeFlags(config), options.sandboxEngine === undefined ? undefined : { sandboxEngine: options.sandboxEngine }, subagents, options.runtimeOptions);
505
- const sessionOptions = {
506
- mode: config.runtime.session.mode,
507
- idleTimeoutMs: config.runtime.session.idleTimeoutMs,
508
- // Any fallback makes the logical run stateless. A provider-owned session
509
- // cannot safely cross the route boundary, even when both bridges happen to
510
- // expose resume support. History replay remains available to every attempt.
511
- supportsResume: hasConfiguredFallback(config)
512
- ? false
513
- : supportsSessionResume(model, executionMode),
514
- ...(config.runtime.session.isolateProactive === undefined
515
- ? {}
516
- : { isolateProactive: config.runtime.session.isolateProactive }),
517
- ...(options.onSessionEvent === undefined ? {} : { onSessionEvent: options.onSessionEvent }),
518
- };
519
- const piSessionsRoot = config.providers?.piNative?.piSessionsRoot;
520
- const retireDurableSession = runtime.retireDurableSession?.bind(runtime);
521
- const baseHistoryStore = options.historyStore ?? createDurableHistoryStore({
522
- root: resolvePath(config.artifacts.dir, "..", "history"),
523
- maxMessages: DEFAULT_HISTORY_MAX_MESSAGES,
524
- ...(piSessionsRoot === undefined || retireDurableSession === undefined
525
- ? {}
526
- : {
527
- retireProviderSession: async (providerSessionId) => {
528
- await retireDurableSession(providerSessionId, piSessionsRoot);
529
- },
530
- }),
531
- });
532
- const historyStore = internalHooks.wrapHistoryStore?.(baseHistoryStore) ?? baseHistoryStore;
533
- return createAgentHarness({
534
- identityPath: config.context.identityPath,
535
- ...(config.context.soulPath === undefined ? {} : { soulPath: config.context.soulPath }),
536
- ...(config.context.skillsRoot === undefined ? {} : { skillsRoot: config.context.skillsRoot }),
537
- ...(config.context.skillMaxBytes === undefined ? {} : { skillMaxBytes: config.context.skillMaxBytes }),
538
- ...(config.context.skillDisclosure === undefined ? {} : { skillDisclosure: config.context.skillDisclosure }),
539
- selectedSkills: config.context.selectedSkills,
540
- runtime,
541
- model,
542
- executionMode,
543
- cwd: config.runtime.workspace,
544
- ...(config.runtime.effort === undefined ? {} : { effort: config.runtime.effort }),
545
- ...(config.runtime.maxTurns === undefined ? {} : { maxTurns: config.runtime.maxTurns }),
546
- ...(config.providers?.piNative?.piSessionsRoot === undefined
547
- ? {}
548
- : { piSessionsRoot: config.providers.piNative.piSessionsRoot }),
549
- session: sessionOptions,
550
- ...(config.concurrency?.maxConcurrentRuns === undefined && config.concurrency?.maxPendingRuns === undefined
551
- ? {}
552
- : {
553
- concurrency: {
554
- ...(config.concurrency?.maxConcurrentRuns === undefined
555
- ? {}
556
- : { maxConcurrentRuns: config.concurrency.maxConcurrentRuns }),
557
- ...(config.concurrency?.maxPendingRuns === undefined
558
- ? {}
559
- : { maxPendingRuns: config.concurrency.maxPendingRuns }),
560
- },
561
- }),
562
- runtimeOptions,
563
- ...(runtimeOptionsForRequest === undefined
728
+ const historyStore = internalHooks.wrapHistoryStore?.(baseHistoryStore) ?? baseHistoryStore;
729
+ const rollover = internalHooks.sessionRollover ?? config.runtime.session.rollover;
730
+ // Conversation history and managed-tool history are distinct contracts. A
731
+ // caller-supplied message store remains the sole message-history owner, while
732
+ // the configured app keeps its independent lifecycle sidecar and
733
+ // SessionHistory capability. Acquisition stays lazy so tool-free runs do not
734
+ // create either the sidecar or its owner database.
735
+ const toolHistory = lazyConfiguredToolHistory({
736
+ root: historyRoot,
737
+ artifactRoot: resolvePath(config.artifacts.dir, "tool-output"),
738
+ rollover,
739
+ ...(options.onToolHistoryWarning === undefined
740
+ ? {}
741
+ : { onWarning: options.onToolHistoryWarning }),
742
+ });
743
+ try {
744
+ const harness = createAgentHarness({
745
+ identityPath: config.context.identityPath,
746
+ ...(config.context.soulPath === undefined ? {} : { soulPath: config.context.soulPath }),
747
+ ...(config.context.skillsRoot === undefined ? {} : { skillsRoot: config.context.skillsRoot }),
748
+ ...(config.context.skillMaxBytes === undefined ? {} : { skillMaxBytes: config.context.skillMaxBytes }),
749
+ ...(config.context.skillDisclosure === undefined ? {} : { skillDisclosure: config.context.skillDisclosure }),
750
+ selectedSkills: config.context.selectedSkills,
751
+ runtime,
752
+ model,
753
+ executionMode,
754
+ cwd: config.runtime.workspace,
755
+ ...(config.runtime.effort === undefined ? {} : { effort: config.runtime.effort }),
756
+ ...(config.runtime.maxTurns === undefined ? {} : { maxTurns: config.runtime.maxTurns }),
757
+ ...(config.providers?.piNative?.piSessionsRoot === undefined
758
+ ? {}
759
+ : { piSessionsRoot: config.providers.piNative.piSessionsRoot }),
760
+ session: sessionOptions,
761
+ ...(config.concurrency?.maxConcurrentRuns === undefined && config.concurrency?.maxPendingRuns === undefined
762
+ ? {}
763
+ : {
764
+ concurrency: {
765
+ ...(config.concurrency?.maxConcurrentRuns === undefined
766
+ ? {}
767
+ : { maxConcurrentRuns: config.concurrency.maxConcurrentRuns }),
768
+ ...(config.concurrency?.maxPendingRuns === undefined
769
+ ? {}
770
+ : { maxPendingRuns: config.concurrency.maxPendingRuns }),
771
+ },
772
+ }),
773
+ runtimeOptions,
774
+ ...(runtimeOptionsForRequest === undefined
775
+ ? {}
776
+ : { runtimeOptionsForRequest }),
777
+ ...(config.tools.mcpRequestContextServers === undefined
778
+ ? {}
779
+ : {
780
+ mcpRequestContext: {
781
+ serverNames: config.tools.mcpRequestContextServers,
782
+ runOutputRoot: artifactDerivedRoots.outbound,
783
+ ...(options.progressCapabilityIssuer === undefined
784
+ ? {}
785
+ : { progressCapabilityIssuer: options.progressCapabilityIssuer }),
786
+ },
787
+ }),
788
+ ...(config.tools.continuationServers === undefined || options.continuationCapabilityIssuer === undefined
789
+ ? {}
790
+ : {
791
+ continuationContext: {
792
+ serverNames: config.tools.continuationServers,
793
+ capabilityIssuer: options.continuationCapabilityIssuer,
794
+ },
795
+ }),
796
+ ...(options.runtimeForModel === undefined ? {} : { runtimeForModel: options.runtimeForModel }),
797
+ ...(memory === undefined ? {} : { memory }),
798
+ memoryWriteMode: config.memory?.writeMode ?? "disabled",
799
+ ...(options.onMemoryWarning === undefined ? {} : { onMemoryWarning: options.onMemoryWarning }),
800
+ historyStore,
801
+ toolHistory,
802
+ ...(options.turnHistoryEnricher === undefined ? {} : { turnHistoryEnricher: options.turnHistoryEnricher }),
803
+ // Inbound channel attachments are saved here (under the artifacts dir, which
804
+ // sits inside a sandbox-readable root) so the agent can open them by path.
805
+ attachmentsDir: artifactDerivedRoots.attachments,
806
+ toolPolicy: createToolPolicy(toolPolicyInput(config)),
807
+ ...(harnessSandboxPolicy === undefined ? {} : { sandboxPolicy: harnessSandboxPolicy }),
808
+ recorderFactory: ({ runId, conversationId, userInput, source, sourceDetail, isolated }) => composeRunRecorder(recorderCompositionDeps(config, options, internalHooks), {
809
+ runId,
810
+ conversationId,
811
+ runKind: "channel",
812
+ ...(isolated === undefined ? {} : { isolated }),
813
+ ...(userInput === undefined ? {} : { userInput }),
814
+ ...(source === undefined ? {} : { source }),
815
+ ...(sourceDetail === undefined ? {} : { sourceDetail }),
816
+ }),
817
+ ...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
818
+ ...(options.now === undefined ? {} : { now: options.now }),
819
+ });
820
+ ownershipTransferred = true;
821
+ return harnessWithAgentRootOwnership(harness, ownership);
822
+ }
823
+ catch (error) {
824
+ await toolHistory?.release?.().catch(() => undefined);
825
+ throw error;
826
+ }
827
+ }
828
+ finally {
829
+ if (!ownershipTransferred) {
830
+ await releaseAgentRootOwnershipWhenIdle(ownership).catch(() => undefined);
831
+ }
832
+ }
833
+ }
834
+ function harnessWithAgentRootOwnership(harness, ownership) {
835
+ let disposePromise;
836
+ return {
837
+ run: harness.run.bind(harness),
838
+ ...(harness.submit === undefined ? {} : { submit: harness.submit.bind(harness) }),
839
+ ...(harness.offerLiveInput === undefined
564
840
  ? {}
565
- : { runtimeOptionsForRequest }),
566
- ...(config.tools.mcpRequestContextServers === undefined
841
+ : { offerLiveInput: harness.offerLiveInput.bind(harness) }),
842
+ ...(harness.cancel === undefined ? {} : { cancel: harness.cancel.bind(harness) }),
843
+ ...(harness.resetConversation === undefined
567
844
  ? {}
568
- : {
569
- mcpRequestContext: {
570
- serverNames: config.tools.mcpRequestContextServers,
571
- runOutputRoot: resolvePath(config.artifacts.dir, "outbound"),
572
- ...(options.progressCapabilityIssuer === undefined
573
- ? {}
574
- : { progressCapabilityIssuer: options.progressCapabilityIssuer }),
575
- },
576
- }),
577
- ...(config.tools.continuationServers === undefined || options.continuationCapabilityIssuer === undefined
845
+ : { resetConversation: harness.resetConversation.bind(harness) }),
846
+ ...(harness.appendVerbatimTurn === undefined
578
847
  ? {}
579
- : {
580
- continuationContext: {
581
- serverNames: config.tools.continuationServers,
582
- capabilityIssuer: options.continuationCapabilityIssuer,
583
- },
584
- }),
585
- ...(options.runtimeForModel === undefined ? {} : { runtimeForModel: options.runtimeForModel }),
586
- ...(memory === undefined ? {} : { memory }),
587
- memoryWriteMode: config.memory?.writeMode ?? "disabled",
588
- ...(options.onMemoryWarning === undefined ? {} : { onMemoryWarning: options.onMemoryWarning }),
589
- historyStore,
590
- ...(options.turnHistoryEnricher === undefined ? {} : { turnHistoryEnricher: options.turnHistoryEnricher }),
591
- // Inbound channel attachments are saved here (under the artifacts dir, which
592
- // sits inside a sandbox-readable root) so the agent can open them by path.
593
- attachmentsDir: resolvePath(config.artifacts.dir, "attachments"),
594
- toolPolicy: createToolPolicy(toolPolicyInput(config)),
595
- ...(config.sandbox === undefined ? {} : { sandboxPolicy: config.sandbox }),
596
- recorderFactory: ({ runId, conversationId, userInput, source, sourceDetail, isolated }) => composeRunRecorder(recorderCompositionDeps(config, options, internalHooks), {
597
- runId,
598
- conversationId,
599
- runKind: "channel",
600
- ...(isolated === undefined ? {} : { isolated }),
601
- ...(userInput === undefined ? {} : { userInput }),
602
- ...(source === undefined ? {} : { source }),
603
- ...(sourceDetail === undefined ? {} : { sourceDetail }),
604
- }),
605
- ...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
606
- ...(options.now === undefined ? {} : { now: options.now }),
607
- });
848
+ : { appendVerbatimTurn: harness.appendVerbatimTurn.bind(harness) }),
849
+ dispose: () => {
850
+ disposePromise ??= Promise.resolve()
851
+ .then(async () => await harness.dispose?.())
852
+ .finally(async () => {
853
+ await releaseAgentRootOwnershipWhenIdle(ownership);
854
+ });
855
+ return disposePromise;
856
+ },
857
+ };
858
+ }
859
+ const TOOL_HISTORY_ACQUISITION_FAILURE_BACKOFF_MS = 30_000;
860
+ const TOOL_HISTORY_ACQUISITION_FAILURE_BACKOFF_MAX_MS = 5 * 60_000;
861
+ export function lazyConfiguredToolHistory(options) {
862
+ const failureBackoffMs = options.acquisitionFailureBackoffMs
863
+ ?? TOOL_HISTORY_ACQUISITION_FAILURE_BACKOFF_MS;
864
+ if (!Number.isSafeInteger(failureBackoffMs) || failureBackoffMs < 1) {
865
+ throw new TypeError("tool history acquisition failure backoff must be a positive integer.");
866
+ }
867
+ const failureBackoffMaxMs = options.acquisitionFailureBackoffMaxMs
868
+ ?? Math.max(TOOL_HISTORY_ACQUISITION_FAILURE_BACKOFF_MAX_MS, failureBackoffMs);
869
+ if (!Number.isSafeInteger(failureBackoffMaxMs)
870
+ || failureBackoffMaxMs < failureBackoffMs) {
871
+ throw new TypeError("tool history acquisition failure backoff maximum must be an integer at least as large as the initial backoff.");
872
+ }
873
+ const now = options.now ?? Date.now;
874
+ let sharedAttempt;
875
+ let latestTurnGeneration = 0;
876
+ const turnStates = new Map();
877
+ let resetTail = Promise.resolve();
878
+ let retirementTail = Promise.resolve();
879
+ let acquisitionOutage = false;
880
+ let consecutiveAcquisitionFailures = 0;
881
+ const reader = new ToolHistoryReader(options.root);
882
+ const warn = (message) => {
883
+ try {
884
+ options.onWarning?.(message);
885
+ }
886
+ catch { /* diagnostics are best-effort */ }
887
+ };
888
+ const turnKey = (conversationId, runId) => JSON.stringify([conversationId, runId]);
889
+ const stateFor = (conversationId, runId) => {
890
+ const key = turnKey(conversationId, runId);
891
+ const existing = turnStates.get(key);
892
+ if (existing !== undefined)
893
+ return existing;
894
+ const state = { generation: ++latestTurnGeneration };
895
+ if (sharedAttempt?.failed === true
896
+ && sharedAttempt.retryAtMs !== undefined
897
+ && now() < sharedAttempt.retryAtMs) {
898
+ state.attempt = sharedAttempt;
899
+ }
900
+ turnStates.set(key, state);
901
+ return state;
902
+ };
903
+ const failedPromise = (code) => {
904
+ const error = Object.assign(new Error("Tool history writer became unavailable; a fresh boundary must reacquire it."), { code });
905
+ const failure = Promise.reject(error);
906
+ void failure.catch(() => undefined);
907
+ return failure;
908
+ };
909
+ const nextFailureBackoffMs = () => {
910
+ let backoffMs = failureBackoffMs;
911
+ for (let index = 0; index < consecutiveAcquisitionFailures && backoffMs < failureBackoffMaxMs; index += 1) {
912
+ backoffMs = backoffMs > Math.floor(failureBackoffMaxMs / 2)
913
+ ? failureBackoffMaxMs
914
+ : Math.min(failureBackoffMaxMs, backoffMs * 2);
915
+ }
916
+ consecutiveAcquisitionFailures += 1;
917
+ return backoffMs;
918
+ };
919
+ const retire = (attempt) => {
920
+ if (attempt.retired || attempt.handle === undefined)
921
+ return;
922
+ attempt.retired = true;
923
+ retirementTail = retirementTail.then(async () => {
924
+ try {
925
+ await attempt.handle?.release();
926
+ }
927
+ catch { /* replacement acquisition must remain armed */ }
928
+ });
929
+ };
930
+ const latchExistingTurns = (attempt, failure) => {
931
+ const failedThrough = latestTurnGeneration;
932
+ for (const state of turnStates.values()) {
933
+ if (state.generation > failedThrough)
934
+ continue;
935
+ if (state.attempt === undefined || state.attempt === attempt)
936
+ state.failure = failure;
937
+ }
938
+ };
939
+ const invalidate = (attempt, code) => {
940
+ if (attempt.failed)
941
+ return attempt.failurePromise ?? attempt.promise;
942
+ const failure = failedPromise(code);
943
+ attempt.failed = true;
944
+ attempt.failurePromise = failure;
945
+ attempt.retryAtMs = now() + nextFailureBackoffMs();
946
+ latchExistingTurns(attempt, failure);
947
+ retire(attempt);
948
+ if (sharedAttempt === attempt) {
949
+ sharedAttempt = {
950
+ promise: failure,
951
+ failurePromise: failure,
952
+ failed: true,
953
+ retryAtMs: attempt.retryAtMs,
954
+ retired: true,
955
+ };
956
+ }
957
+ acquisitionOutage = true;
958
+ return failure;
959
+ };
960
+ const startAttempt = () => {
961
+ const acquisition = retirementTail.then(async () => await (options.acquireWriter ?? acquireToolHistoryWriter)({
962
+ root: options.root,
963
+ artifactRoot: options.artifactRoot,
964
+ ...(options.onWarning === undefined ? {} : { onWarning: options.onWarning }),
965
+ }));
966
+ const attempt = {
967
+ promise: acquisition,
968
+ failed: false,
969
+ retired: false,
970
+ };
971
+ attempt.promise = acquisition.then((handle) => {
972
+ attempt.handle = handle;
973
+ consecutiveAcquisitionFailures = 0;
974
+ if (acquisitionOutage) {
975
+ warn("Tool history writer acquisition recovered; lifecycle persistence resumed.");
976
+ }
977
+ acquisitionOutage = false;
978
+ return handle;
979
+ }).catch((error) => {
980
+ attempt.failed = true;
981
+ attempt.failurePromise = attempt.promise;
982
+ const retryBackoffMs = nextFailureBackoffMs();
983
+ attempt.retryAtMs = now() + retryBackoffMs;
984
+ latchExistingTurns(attempt, attempt.promise);
985
+ if (!acquisitionOutage) {
986
+ acquisitionOutage = true;
987
+ warn(`Tool history writer acquisition failed (${toolHistoryAcquisitionErrorCode(error)}); new turns fail fast for ${String(retryBackoffMs)} ms and repeated failures back off to ${String(failureBackoffMaxMs)} ms, while explicit reset may retry immediately.`);
988
+ }
989
+ throw error;
990
+ });
991
+ void attempt.promise.catch(() => undefined);
992
+ sharedAttempt = attempt;
993
+ return attempt;
994
+ };
995
+ const selectAttempt = (bypassFailureBackoff) => {
996
+ if (sharedAttempt !== undefined) {
997
+ if (sharedAttempt.handle?.writer.isClosed === true) {
998
+ invalidate(sharedAttempt, "history_writer_closed");
999
+ }
1000
+ const withinFailureBackoff = sharedAttempt.retryAtMs !== undefined
1001
+ && now() < sharedAttempt.retryAtMs;
1002
+ if (!sharedAttempt.failed
1003
+ || (!bypassFailureBackoff && withinFailureBackoff)) {
1004
+ return sharedAttempt;
1005
+ }
1006
+ sharedAttempt = undefined;
1007
+ }
1008
+ return startAttempt();
1009
+ };
1010
+ const acquireForTurn = async (state) => {
1011
+ if (state.failure !== undefined)
1012
+ return await state.failure;
1013
+ state.attempt ??= selectAttempt(false);
1014
+ const handle = await state.attempt.promise;
1015
+ if (handle.writer.isClosed) {
1016
+ state.failure = invalidate(state.attempt, "history_writer_closed");
1017
+ return await state.failure;
1018
+ }
1019
+ return handle;
1020
+ };
1021
+ const writer = {
1022
+ createSink(binding) {
1023
+ const state = stateFor(binding.conversationId, binding.runId);
1024
+ return async (event) => {
1025
+ const handle = await acquireForTurn(state);
1026
+ try {
1027
+ const result = await handle.writer.persist(binding, event);
1028
+ const terminalCode = terminalToolHistoryWriterFailureCode(result, handle);
1029
+ if (terminalCode !== undefined && state.attempt !== undefined) {
1030
+ state.failure = invalidate(state.attempt, terminalCode);
1031
+ }
1032
+ return result;
1033
+ }
1034
+ catch (error) {
1035
+ const terminalCode = terminalToolHistoryWriterFailureCode(error, handle);
1036
+ if (terminalCode !== undefined && state.attempt !== undefined) {
1037
+ state.failure = invalidate(state.attempt, terminalCode);
1038
+ }
1039
+ throw error;
1040
+ }
1041
+ };
1042
+ },
1043
+ async finishRun(binding, status, failureKind) {
1044
+ const key = turnKey(binding.conversationId, binding.runId);
1045
+ const state = turnStates.get(key);
1046
+ try {
1047
+ if (state?.attempt === undefined || state.failure !== undefined)
1048
+ return;
1049
+ const handle = await state.attempt.promise.catch(() => undefined);
1050
+ try {
1051
+ await handle?.writer.finishRun(binding, status, failureKind);
1052
+ }
1053
+ catch (error) {
1054
+ if (handle === undefined)
1055
+ return;
1056
+ const terminalCode = terminalToolHistoryWriterFailureCode(error, handle);
1057
+ if (terminalCode === undefined)
1058
+ throw error;
1059
+ invalidate(state.attempt, terminalCode);
1060
+ return;
1061
+ }
1062
+ const terminalCode = handle === undefined
1063
+ ? undefined
1064
+ : terminalToolHistoryWriterFailureCode(undefined, handle);
1065
+ if (terminalCode !== undefined)
1066
+ invalidate(state.attempt, terminalCode);
1067
+ }
1068
+ finally {
1069
+ turnStates.delete(key);
1070
+ }
1071
+ },
1072
+ async resetConversation(logicalConversationId) {
1073
+ const reset = resetTail.then(async () => {
1074
+ if (!await reader.exists())
1075
+ return;
1076
+ // Reset is serialized and host-explicit, so it may bypass only the
1077
+ // progressive post-failure cooldown. It still reuses a healthy/pending handle
1078
+ // and every fresh acquisition keeps the full restart-handoff ceiling.
1079
+ const observedAttempt = sharedAttempt;
1080
+ if (observedAttempt !== undefined && !observedAttempt.failed) {
1081
+ await observedAttempt.promise.catch(() => undefined);
1082
+ }
1083
+ let recoveryRetriesRemaining = 1;
1084
+ for (;;) {
1085
+ const attempt = selectAttempt(true);
1086
+ const handle = await attempt.promise;
1087
+ try {
1088
+ await handle.writer.resetConversation(logicalConversationId);
1089
+ }
1090
+ catch (error) {
1091
+ const terminalCode = reportedToolHistoryWriterFailureCode(error);
1092
+ if (terminalCode === undefined) {
1093
+ if (handle.writer.isClosed)
1094
+ invalidate(attempt, "history_writer_closed");
1095
+ throw error;
1096
+ }
1097
+ invalidate(attempt, terminalCode);
1098
+ if (recoveryRetriesRemaining === 0)
1099
+ throw error;
1100
+ recoveryRetriesRemaining -= 1;
1101
+ continue;
1102
+ }
1103
+ const terminalCode = terminalToolHistoryWriterFailureCode(undefined, handle);
1104
+ if (terminalCode !== undefined)
1105
+ invalidate(attempt, terminalCode);
1106
+ // A resolved reset was acknowledged only after its transaction
1107
+ // committed. Retire a concurrently closed handle, but never open a
1108
+ // second destructive reset window for an operation that succeeded.
1109
+ return;
1110
+ }
1111
+ });
1112
+ resetTail = reset.then(() => undefined, () => undefined);
1113
+ await reset;
1114
+ },
1115
+ };
1116
+ return {
1117
+ writer,
1118
+ reader,
1119
+ logicalConversationId: (conversationId) => toolHistoryLogicalConversationId(conversationId, options.rollover),
1120
+ async release() {
1121
+ const attempt = sharedAttempt;
1122
+ sharedAttempt = undefined;
1123
+ if (attempt !== undefined) {
1124
+ await attempt.promise.catch(() => undefined);
1125
+ retire(attempt);
1126
+ }
1127
+ await retirementTail;
1128
+ },
1129
+ };
1130
+ }
1131
+ function terminalToolHistoryWriterFailureCode(value, handle) {
1132
+ return reportedToolHistoryWriterFailureCode(value)
1133
+ ?? (handle.writer.isClosed ? "history_writer_closed" : undefined);
1134
+ }
1135
+ function reportedToolHistoryWriterFailureCode(value) {
1136
+ const candidate = typeof value === "object" && value !== null
1137
+ ? "errorCode" in value
1138
+ ? value.errorCode
1139
+ : "code" in value
1140
+ ? value.code
1141
+ : undefined
1142
+ : undefined;
1143
+ if (candidate === "history_writer_closed")
1144
+ return candidate;
1145
+ return undefined;
1146
+ }
1147
+ function toolHistoryAcquisitionErrorCode(error) {
1148
+ const candidate = typeof error === "object" && error !== null && "code" in error
1149
+ ? error.code
1150
+ : undefined;
1151
+ return typeof candidate === "string" && /^history_[a-z0-9_]+$/u.test(candidate)
1152
+ ? candidate
1153
+ : "history_writer_unavailable";
608
1154
  }
609
1155
  function configuredMemoryForHarness(config, memory) {
610
1156
  if (memory instanceof MemoryRetrievalService || config.memory === undefined || !isSharedRecallStore(memory)) {
@@ -705,7 +1251,7 @@ export async function createConfiguredMemory(config, deps = {}) {
705
1251
  throw new Error(`memory.embeddings.apiKeyEnv ${embeddingsConfig.apiKeyEnv} is declared but has no resolved value; ` +
706
1252
  `set ${embeddingsConfig.apiKeyEnv} before starting managed memory.`);
707
1253
  }
708
- const embeddings = search.createCircuitBreakerEmbeddingProvider(search.createEmbeddingProvider({
1254
+ const embeddings = wrapOwnedDirectEmbeddingProvider(search.createCircuitBreakerEmbeddingProvider(search.createEmbeddingProvider({
709
1255
  provider: embeddingsConfig?.provider ?? "ollama",
710
1256
  model: embeddingsConfig?.model ?? "nomic-embed-text:v1.5",
711
1257
  ...(embeddingsConfig?.endpoint !== undefined && { endpoint: embeddingsConfig.endpoint }),
@@ -718,7 +1264,7 @@ export async function createConfiguredMemory(config, deps = {}) {
718
1264
  ...(embeddingsConfig?.circuitBreaker?.cooldownMs !== undefined && {
719
1265
  cooldownMs: embeddingsConfig.circuitBreaker.cooldownMs,
720
1266
  }),
721
- });
1267
+ }), config, deps.cwd ?? process.cwd());
722
1268
  const dim = embeddingsConfig?.dim ?? 768;
723
1269
  if (mode === "journal") {
724
1270
  if (embeddingsConfig === undefined) {
@@ -746,7 +1292,7 @@ export async function createConfiguredMemory(config, deps = {}) {
746
1292
  const recording = deps.observability === undefined
747
1293
  ? undefined
748
1294
  : recorderCompositionDeps(config, deps.observability);
749
- const llm = configuredMemoryLlm(bujo, config, llmConfig, deps.memoryRuntime, recording);
1295
+ const llm = configuredMemoryLlm(bujo, config, llmConfig, deps.memoryRuntime, recording, deps.cwd ?? process.cwd());
750
1296
  if (llm === undefined) {
751
1297
  throw new Error("memory.mode 'bujo' could not construct the required memory.llm.");
752
1298
  }
@@ -773,16 +1319,16 @@ function configuredMemoryLlm(bujo, config, llmConfig,
773
1319
  // Explicit memory-LLM runtime (tests). MUST be fallback-chain-free — see the
774
1320
  // `memoryRuntime` doc on createConfiguredMemory. When undefined the memory LLM
775
1321
  // builds its own fallback-free runtime so the per-call memory model is primary.
776
- memoryRuntimeOverride, recording) {
1322
+ memoryRuntimeOverride, recording, agentRoot) {
777
1323
  if (llmConfig === undefined) {
778
1324
  return undefined;
779
1325
  }
780
1326
  if (llmConfig.provider === "ollama") {
781
1327
  // The ollama memory LLM does not ride `runtime.run`, so it is not recorded.
782
- return bujo.createOllamaLlm({
1328
+ return wrapOwnedDirectMemoryLlm(bujo.createOllamaLlm({
783
1329
  model: llmConfig.model,
784
1330
  ...(llmConfig.endpoint !== undefined && { endpoint: llmConfig.endpoint }),
785
- });
1331
+ }), config, agentRoot);
786
1332
  }
787
1333
  const model = parseMonoRuntimeModelReference(llmConfig.model);
788
1334
  const executionMode = llmConfig.executionMode ?? defaultExecutionModeForModel(model);
@@ -795,7 +1341,7 @@ memoryRuntimeOverride, recording) {
795
1341
  // channel runtime (which carries the fallback chain whose primary is
796
1342
  // `config.runtime.model`) is intentionally NOT reused — see the `memoryRuntime`
797
1343
  // doc on createConfiguredMemory.
798
- const runtime = memoryRuntimeOverride ?? createMonoRuntime(runtimeHostOptionsForConfig(config));
1344
+ const runtime = wrapPerRunOwnedConfiguredRuntime(memoryRuntimeOverride ?? createMonoRuntime(runtimeHostOptionsForConfig(config)), config, agentRoot);
799
1345
  return createAgentHostMemoryLlm({
800
1346
  runtime,
801
1347
  model,
@@ -812,6 +1358,109 @@ memoryRuntimeOverride, recording) {
812
1358
  : {}),
813
1359
  });
814
1360
  }
1361
+ /**
1362
+ * Memory completion is a model-running surface even when no channel harness is
1363
+ * present. Acquire the canonical-root owner and protection generation for the
1364
+ * exact duration of the provider call; release follows actual runtime
1365
+ * settlement, never its abort signal.
1366
+ */
1367
+ function wrapPerRunOwnedConfiguredRuntime(runtime, config, agentRoot) {
1368
+ return {
1369
+ ...runtime,
1370
+ async run(systemPrompt, runOptions) {
1371
+ const ownership = await acquireAgentRootOwnership(agentRoot);
1372
+ let requestLease;
1373
+ try {
1374
+ assertAgentRootLeaseOutsideWorkspace(ownership, config.runtime.workspace);
1375
+ const loaded = await loadProcessJobsRootRegistryProtection(ownership.agentRoot, config.runtime.workspace);
1376
+ ownership.coordinator.synchronizeGeneration(loaded.generation);
1377
+ const boundary = await attestProcessJobsRootRegistrySnapshot(loaded, config.runtime.workspace);
1378
+ requestLease = ownership.coordinator.acquireRequestLease(boundary.generation);
1379
+ const attested = await attestProcessJobsRootRegistrySnapshot(boundary, config.runtime.workspace);
1380
+ const protectedRoots = processJobsProtectionPolicyRoots(attested);
1381
+ let effectiveOptions = runOptions;
1382
+ if (protectedRoots.length > 0) {
1383
+ if (runOptions.model.sdk !== "pi")
1384
+ throw new Error(PROCESS_JOBS_PI_NATIVE_REQUIRED_ERROR);
1385
+ const sandboxEngine = runOptions.sandboxEngine ?? createSrtSandboxEngine();
1386
+ if (!await sandboxEngine.isAvailable().catch(() => false)) {
1387
+ throw new Error(PROCESS_JOBS_PROTECTION_UNAVAILABLE_ERROR);
1388
+ }
1389
+ const sandboxPolicy = mergeSandboxPolicies(runOptions.sandboxPolicy, processJobsSandboxPolicy({ coreConfig: config, protectedRoots }));
1390
+ if (sandboxPolicy === undefined) {
1391
+ throw new Error(PROCESS_JOBS_PROTECTION_UNAVAILABLE_ERROR);
1392
+ }
1393
+ effectiveOptions = {
1394
+ ...runOptions,
1395
+ sandboxPolicy,
1396
+ sandboxEngine,
1397
+ };
1398
+ }
1399
+ return await runtime.run(systemPrompt, effectiveOptions);
1400
+ }
1401
+ finally {
1402
+ requestLease?.releaseAfterSettlement();
1403
+ await releaseAgentRootOwnershipWhenIdle(ownership);
1404
+ }
1405
+ },
1406
+ };
1407
+ }
1408
+ function wrapOwnedDirectMemoryLlm(llm, config, agentRoot) {
1409
+ return {
1410
+ ...llm,
1411
+ async complete(prompt, options) {
1412
+ const ownership = await acquireAgentRootOwnership(agentRoot);
1413
+ let requestLease;
1414
+ try {
1415
+ assertAgentRootLeaseOutsideWorkspace(ownership, config.runtime.workspace);
1416
+ const loaded = await loadProcessJobsRootRegistryProtection(ownership.agentRoot, config.runtime.workspace);
1417
+ ownership.coordinator.synchronizeGeneration(loaded.generation);
1418
+ const boundary = await attestProcessJobsRootRegistrySnapshot(loaded, config.runtime.workspace);
1419
+ requestLease = ownership.coordinator.acquireRequestLease(boundary.generation);
1420
+ const attested = await attestProcessJobsRootRegistrySnapshot(boundary, config.runtime.workspace);
1421
+ if (processJobsProtectionPolicyRoots(attested).length > 0) {
1422
+ throw new Error(PROCESS_JOBS_PI_NATIVE_REQUIRED_ERROR);
1423
+ }
1424
+ return await llm.complete(prompt, options);
1425
+ }
1426
+ finally {
1427
+ requestLease?.releaseAfterSettlement();
1428
+ await releaseAgentRootOwnershipWhenIdle(ownership);
1429
+ }
1430
+ },
1431
+ };
1432
+ }
1433
+ /**
1434
+ * Configured embedding providers execute outside the channel harness. Hold the
1435
+ * same canonical-root owner and generation lease through the true embed()
1436
+ * settlement, and reject the non-Pi provider before invocation whenever a
1437
+ * retained process-job root makes native SRT confinement mandatory.
1438
+ */
1439
+ function wrapOwnedDirectEmbeddingProvider(provider, config, agentRoot) {
1440
+ return {
1441
+ ...provider,
1442
+ async embed(texts) {
1443
+ const ownership = await acquireAgentRootOwnership(agentRoot);
1444
+ let requestLease;
1445
+ try {
1446
+ assertAgentRootLeaseOutsideWorkspace(ownership, config.runtime.workspace);
1447
+ const loaded = await loadProcessJobsRootRegistryProtection(ownership.agentRoot, config.runtime.workspace);
1448
+ ownership.coordinator.synchronizeGeneration(loaded.generation);
1449
+ const boundary = await attestProcessJobsRootRegistrySnapshot(loaded, config.runtime.workspace);
1450
+ requestLease = ownership.coordinator.acquireRequestLease(boundary.generation);
1451
+ const attested = await attestProcessJobsRootRegistrySnapshot(boundary, config.runtime.workspace);
1452
+ if (processJobsProtectionPolicyRoots(attested).length > 0) {
1453
+ throw new Error(PROCESS_JOBS_PI_NATIVE_REQUIRED_ERROR);
1454
+ }
1455
+ return await provider.embed(texts);
1456
+ }
1457
+ finally {
1458
+ requestLease?.releaseAfterSettlement();
1459
+ await releaseAgentRootOwnershipWhenIdle(ownership);
1460
+ }
1461
+ },
1462
+ };
1463
+ }
815
1464
  const MEMORY_LLM_SYSTEM_PROMPT = [
816
1465
  "You are the private memory maintenance LLM for mono-agent.",
817
1466
  "Return only the requested JSON or plain text.",