@mono-agent/agent-app 0.19.1 → 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.
- package/README.md +304 -32
- package/dist/acp-bridge.d.ts.map +1 -1
- package/dist/acp-bridge.js +113 -54
- package/dist/acp-bridge.js.map +1 -1
- package/dist/acp-session-store.d.ts +12 -0
- package/dist/acp-session-store.d.ts.map +1 -0
- package/dist/acp-session-store.js +74 -0
- package/dist/acp-session-store.js.map +1 -0
- package/dist/agent-artifact-paths.d.ts +8 -0
- package/dist/agent-artifact-paths.d.ts.map +1 -0
- package/dist/agent-artifact-paths.js +11 -0
- package/dist/agent-artifact-paths.js.map +1 -0
- package/dist/agent-root-coordinator.d.ts +101 -0
- package/dist/agent-root-coordinator.d.ts.map +1 -0
- package/dist/agent-root-coordinator.js +470 -0
- package/dist/agent-root-coordinator.js.map +1 -0
- package/dist/app-controller-channels.d.ts +11 -1
- package/dist/app-controller-channels.d.ts.map +1 -1
- package/dist/app-controller-channels.js +145 -20
- package/dist/app-controller-channels.js.map +1 -1
- package/dist/app-controller-continuation.d.ts +2 -0
- package/dist/app-controller-continuation.d.ts.map +1 -1
- package/dist/app-controller-continuation.js.map +1 -1
- package/dist/app-controller-lifecycle.d.ts +5 -0
- package/dist/app-controller-lifecycle.d.ts.map +1 -1
- package/dist/app-controller-lifecycle.js +24 -5
- package/dist/app-controller-lifecycle.js.map +1 -1
- package/dist/app-controller-maintenance.d.ts +2 -0
- package/dist/app-controller-maintenance.d.ts.map +1 -1
- package/dist/app-controller-maintenance.js +32 -2
- package/dist/app-controller-maintenance.js.map +1 -1
- package/dist/app-controller-process-jobs.d.ts +46 -0
- package/dist/app-controller-process-jobs.d.ts.map +1 -0
- package/dist/app-controller-process-jobs.js +281 -0
- package/dist/app-controller-process-jobs.js.map +1 -0
- package/dist/app-controller-responder.d.ts +15 -0
- package/dist/app-controller-responder.d.ts.map +1 -1
- package/dist/app-controller-responder.js +146 -12
- package/dist/app-controller-responder.js.map +1 -1
- package/dist/app-controller-traceability.d.ts +6 -0
- package/dist/app-controller-traceability.d.ts.map +1 -1
- package/dist/app-controller-traceability.js +10 -0
- package/dist/app-controller-traceability.js.map +1 -1
- package/dist/app-controller-utils.d.ts +8 -0
- package/dist/app-controller-utils.d.ts.map +1 -1
- package/dist/app-controller-utils.js +24 -1
- package/dist/app-controller-utils.js.map +1 -1
- package/dist/app-controller.d.ts +40 -1
- package/dist/app-controller.d.ts.map +1 -1
- package/dist/app-controller.js +124 -39
- package/dist/app-controller.js.map +1 -1
- package/dist/background-log-maintenance.d.ts +85 -2
- package/dist/background-log-maintenance.d.ts.map +1 -1
- package/dist/background-log-maintenance.js +407 -136
- package/dist/background-log-maintenance.js.map +1 -1
- package/dist/background-runtime.d.ts.map +1 -1
- package/dist/background-runtime.js +22 -41
- package/dist/background-runtime.js.map +1 -1
- package/dist/background.d.ts +18 -26
- package/dist/background.d.ts.map +1 -1
- package/dist/background.js +83 -138
- package/dist/background.js.map +1 -1
- package/dist/channel-drivers/cron.d.ts +12 -1
- package/dist/channel-drivers/cron.d.ts.map +1 -1
- package/dist/channel-drivers/cron.js +121 -18
- package/dist/channel-drivers/cron.js.map +1 -1
- package/dist/channel-drivers/native-notify.d.ts +3 -0
- package/dist/channel-drivers/native-notify.d.ts.map +1 -1
- package/dist/channel-drivers/native-notify.js +2 -1
- package/dist/channel-drivers/native-notify.js.map +1 -1
- package/dist/channel-drivers/slack.d.ts.map +1 -1
- package/dist/channel-drivers/slack.js +41 -4
- package/dist/channel-drivers/slack.js.map +1 -1
- package/dist/channel-drivers/telegram.d.ts.map +1 -1
- package/dist/channel-drivers/telegram.js +46 -3
- package/dist/channel-drivers/telegram.js.map +1 -1
- package/dist/channel-drivers/tui.d.ts +13 -2
- package/dist/channel-drivers/tui.d.ts.map +1 -1
- package/dist/channel-drivers/tui.js +112 -3
- package/dist/channel-drivers/tui.js.map +1 -1
- package/dist/channels.d.ts +1 -1
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +4 -2
- package/dist/channels.js.map +1 -1
- package/dist/cli-args.d.ts +15 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +82 -12
- package/dist/cli-args.js.map +1 -1
- package/dist/cli-background-command.d.ts +9 -2
- package/dist/cli-background-command.d.ts.map +1 -1
- package/dist/cli-background-command.js +174 -66
- package/dist/cli-background-command.js.map +1 -1
- package/dist/cli-commands.d.ts.map +1 -1
- package/dist/cli-commands.js +50 -12
- package/dist/cli-commands.js.map +1 -1
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +21 -1
- package/dist/cli-help.js.map +1 -1
- package/dist/config-reference.d.ts.map +1 -1
- package/dist/config-reference.js +99 -2
- package/dist/config-reference.js.map +1 -1
- package/dist/configured-agent.d.ts +44 -3
- package/dist/configured-agent.d.ts.map +1 -1
- package/dist/configured-agent.js +805 -156
- package/dist/configured-agent.js.map +1 -1
- package/dist/conversation-state-roots.d.ts +59 -0
- package/dist/conversation-state-roots.d.ts.map +1 -0
- package/dist/conversation-state-roots.js +248 -0
- package/dist/conversation-state-roots.js.map +1 -0
- package/dist/cron-control-store.d.ts +91 -0
- package/dist/cron-control-store.d.ts.map +1 -0
- package/dist/cron-control-store.js +1251 -0
- package/dist/cron-control-store.js.map +1 -0
- package/dist/cron-operator-service.d.ts +54 -0
- package/dist/cron-operator-service.d.ts.map +1 -0
- package/dist/cron-operator-service.js +352 -0
- package/dist/cron-operator-service.js.map +1 -0
- package/dist/doctor-session-history.d.ts +9 -0
- package/dist/doctor-session-history.d.ts.map +1 -0
- package/dist/doctor-session-history.js +313 -0
- package/dist/doctor-session-history.js.map +1 -0
- package/dist/doctor.d.ts +2 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +320 -9
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interaction-bridge.d.ts +1 -0
- package/dist/interaction-bridge.d.ts.map +1 -1
- package/dist/interaction-bridge.js +54 -6
- package/dist/interaction-bridge.js.map +1 -1
- package/dist/jobs-command.d.ts +17 -0
- package/dist/jobs-command.d.ts.map +1 -0
- package/dist/jobs-command.js +207 -0
- package/dist/jobs-command.js.map +1 -0
- package/dist/launchd-lifecycle-lock.d.ts +36 -0
- package/dist/launchd-lifecycle-lock.d.ts.map +1 -0
- package/dist/launchd-lifecycle-lock.js +124 -0
- package/dist/launchd-lifecycle-lock.js.map +1 -0
- package/dist/launchd-log-monitor-status.d.ts +7 -0
- package/dist/launchd-log-monitor-status.d.ts.map +1 -0
- package/dist/launchd-log-monitor-status.js +224 -0
- package/dist/launchd-log-monitor-status.js.map +1 -0
- package/dist/launchd-logs.d.ts +9 -1
- package/dist/launchd-logs.d.ts.map +1 -1
- package/dist/launchd-logs.js +69 -16
- package/dist/launchd-logs.js.map +1 -1
- package/dist/launchd-maintenance-command.d.ts +10 -0
- package/dist/launchd-maintenance-command.d.ts.map +1 -0
- package/dist/launchd-maintenance-command.js +2 -0
- package/dist/launchd-maintenance-command.js.map +1 -0
- package/dist/launchd-maintenance-entry.d.ts +30 -0
- package/dist/launchd-maintenance-entry.d.ts.map +1 -0
- package/dist/launchd-maintenance-entry.js +206 -0
- package/dist/launchd-maintenance-entry.js.map +1 -0
- package/dist/launchd-maintenance-gate.d.ts +28 -0
- package/dist/launchd-maintenance-gate.d.ts.map +1 -0
- package/dist/launchd-maintenance-gate.js +80 -0
- package/dist/launchd-maintenance-gate.js.map +1 -0
- package/dist/launchd-private-files.d.ts +3 -0
- package/dist/launchd-private-files.d.ts.map +1 -0
- package/dist/launchd-private-files.js +58 -0
- package/dist/launchd-private-files.js.map +1 -0
- package/dist/launchd.d.ts +56 -2
- package/dist/launchd.d.ts.map +1 -1
- package/dist/launchd.js +210 -5
- package/dist/launchd.js.map +1 -1
- package/dist/local-configuration.d.ts.map +1 -1
- package/dist/local-configuration.js +33 -7
- package/dist/local-configuration.js.map +1 -1
- package/dist/managed-launchd-maintenance-environment.d.ts +3 -0
- package/dist/managed-launchd-maintenance-environment.d.ts.map +1 -0
- package/dist/managed-launchd-maintenance-environment.js +12 -0
- package/dist/managed-launchd-maintenance-environment.js.map +1 -0
- package/dist/managed-runtime-launch-proof.d.ts +11 -0
- package/dist/managed-runtime-launch-proof.d.ts.map +1 -0
- package/dist/managed-runtime-launch-proof.js +59 -0
- package/dist/managed-runtime-launch-proof.js.map +1 -0
- package/dist/managed-runtime-maintenance-entry.d.ts +10 -0
- package/dist/managed-runtime-maintenance-entry.d.ts.map +1 -0
- package/dist/managed-runtime-maintenance-entry.js +244 -0
- package/dist/managed-runtime-maintenance-entry.js.map +1 -0
- package/dist/managed-web-logs.d.ts +29 -11
- package/dist/managed-web-logs.d.ts.map +1 -1
- package/dist/managed-web-logs.js +244 -121
- package/dist/managed-web-logs.js.map +1 -1
- package/dist/managed-web-maintenance-environment.d.ts +6 -0
- package/dist/managed-web-maintenance-environment.d.ts.map +1 -0
- package/dist/managed-web-maintenance-environment.js +19 -0
- package/dist/managed-web-maintenance-environment.js.map +1 -0
- package/dist/mcp-apps.d.ts +37 -0
- package/dist/mcp-apps.d.ts.map +1 -0
- package/dist/mcp-apps.js +1753 -0
- package/dist/mcp-apps.js.map +1 -0
- package/dist/memory-command.d.ts +12 -0
- package/dist/memory-command.d.ts.map +1 -1
- package/dist/memory-command.js +510 -1
- package/dist/memory-command.js.map +1 -1
- package/dist/modules/known-tools.d.ts +1 -1
- package/dist/modules/known-tools.d.ts.map +1 -1
- package/dist/modules/known-tools.js +2 -0
- package/dist/modules/known-tools.js.map +1 -1
- package/dist/posted-reply-history.d.ts.map +1 -1
- package/dist/posted-reply-history.js +12 -0
- package/dist/posted-reply-history.js.map +1 -1
- package/dist/proactive-notify.d.ts +4 -1
- package/dist/proactive-notify.d.ts.map +1 -1
- package/dist/proactive-notify.js +43 -5
- package/dist/proactive-notify.js.map +1 -1
- package/dist/process-jobs-config.d.ts +82 -0
- package/dist/process-jobs-config.d.ts.map +1 -0
- package/dist/process-jobs-config.js +423 -0
- package/dist/process-jobs-config.js.map +1 -0
- package/dist/process-jobs-context.d.ts +24 -0
- package/dist/process-jobs-context.d.ts.map +1 -0
- package/dist/process-jobs-context.js +135 -0
- package/dist/process-jobs-context.js.map +1 -0
- package/dist/process-jobs-root-registry.d.ts +115 -0
- package/dist/process-jobs-root-registry.d.ts.map +1 -0
- package/dist/process-jobs-root-registry.js +978 -0
- package/dist/process-jobs-root-registry.js.map +1 -0
- package/dist/process-jobs-runtime.d.ts +35 -0
- package/dist/process-jobs-runtime.d.ts.map +1 -0
- package/dist/process-jobs-runtime.js +177 -0
- package/dist/process-jobs-runtime.js.map +1 -0
- package/dist/process-jobs-service.d.ts +70 -0
- package/dist/process-jobs-service.d.ts.map +1 -0
- package/dist/process-jobs-service.js +1989 -0
- package/dist/process-jobs-service.js.map +1 -0
- package/dist/process-jobs-store.d.ts +151 -0
- package/dist/process-jobs-store.d.ts.map +1 -0
- package/dist/process-jobs-store.js +1290 -0
- package/dist/process-jobs-store.js.map +1 -0
- package/dist/reply-artifacts.d.ts +65 -0
- package/dist/reply-artifacts.d.ts.map +1 -0
- package/dist/reply-artifacts.js +1147 -0
- package/dist/reply-artifacts.js.map +1 -0
- package/dist/reply-part-budget.d.ts +16 -0
- package/dist/reply-part-budget.d.ts.map +1 -0
- package/dist/reply-part-budget.js +57 -0
- package/dist/reply-part-budget.js.map +1 -0
- package/dist/request-model-override.d.ts +19 -0
- package/dist/request-model-override.d.ts.map +1 -1
- package/dist/request-model-override.js +54 -1
- package/dist/request-model-override.js.map +1 -1
- package/dist/request-scoped-mcp.d.ts +31 -0
- package/dist/request-scoped-mcp.d.ts.map +1 -0
- package/dist/request-scoped-mcp.js +197 -0
- package/dist/request-scoped-mcp.js.map +1 -0
- package/dist/run-history.d.ts.map +1 -1
- package/dist/run-history.js +50 -254
- package/dist/run-history.js.map +1 -1
- package/dist/runtime-option-extensions.d.ts +21 -0
- package/dist/runtime-option-extensions.d.ts.map +1 -1
- package/dist/runtime-option-extensions.js +53 -0
- package/dist/runtime-option-extensions.js.map +1 -1
- package/dist/secure-file-replace.d.ts +3 -0
- package/dist/secure-file-replace.d.ts.map +1 -1
- package/dist/secure-file-replace.js +31 -7
- package/dist/secure-file-replace.js.map +1 -1
- package/dist/session-history.d.ts +146 -0
- package/dist/session-history.d.ts.map +1 -0
- package/dist/session-history.js +347 -0
- package/dist/session-history.js.map +1 -0
- package/dist/sessions.d.ts +45 -2
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +849 -30
- package/dist/sessions.js.map +1 -1
- package/dist/web-command.d.ts +12 -11
- package/dist/web-command.d.ts.map +1 -1
- package/dist/web-command.js +554 -80
- package/dist/web-command.js.map +1 -1
- package/dist/web-log-maintenance-command.d.ts +7 -0
- package/dist/web-log-maintenance-command.d.ts.map +1 -0
- package/dist/web-log-maintenance-command.js +21 -0
- package/dist/web-log-maintenance-command.js.map +1 -0
- package/dist/web-log-maintenance-status.d.ts +26 -0
- package/dist/web-log-maintenance-status.d.ts.map +1 -0
- package/dist/web-log-maintenance-status.js +171 -0
- package/dist/web-log-maintenance-status.js.map +1 -0
- package/dist/web-log-maintenance.d.ts +32 -0
- package/dist/web-log-maintenance.d.ts.map +1 -0
- package/dist/web-log-maintenance.js +163 -0
- package/dist/web-log-maintenance.js.map +1 -0
- package/dist/web-maintenance-paths.d.ts +12 -0
- package/dist/web-maintenance-paths.d.ts.map +1 -0
- package/dist/web-maintenance-paths.js +24 -0
- package/dist/web-maintenance-paths.js.map +1 -0
- package/dist/wizard/prompts.d.ts.map +1 -1
- package/dist/wizard/prompts.js +1 -0
- package/dist/wizard/prompts.js.map +1 -1
- package/dist/wizard/run.js +1 -1
- package/dist/wizard/run.js.map +1 -1
- package/package.json +15 -15
- package/schema/mono-agent.config.schema.json +102 -1
- package/skills/mono-agent-composer/references/config-blueprint.md +26 -2
- package/skills/mono-agent-composer/references/discovery-questions.md +2 -2
- package/skills/mono-agent-composer/references/feature-coverage.md +6 -4
- package/skills/mono-agent-composer/references/package-map.md +19 -3
- package/skills/mono-agent-composer/references/playbooks.md +3 -3
- package/skills/mono-agent-composer/references/validation.md +4 -2
package/dist/configured-agent.js
CHANGED
|
@@ -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
|
-
...(
|
|
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
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
-
: {
|
|
722
|
+
: {
|
|
723
|
+
retireProviderSession: async (providerSessionId) => {
|
|
724
|
+
await retireDurableSession(providerSessionId, piSessionsRoot);
|
|
725
|
+
},
|
|
726
|
+
}),
|
|
488
727
|
});
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
//
|
|
494
|
-
//
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
},
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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
|
-
: {
|
|
566
|
-
...(
|
|
841
|
+
: { offerLiveInput: harness.offerLiveInput.bind(harness) }),
|
|
842
|
+
...(harness.cancel === undefined ? {} : { cancel: harness.cancel.bind(harness) }),
|
|
843
|
+
...(harness.resetConversation === undefined
|
|
567
844
|
? {}
|
|
568
|
-
: {
|
|
569
|
-
|
|
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
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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.",
|