@nowcrew/daemon 0.6.101-beta.3 → 0.6.101-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloud-report-upload.js +1 -10
- package/dist/execution-journal-lock.js +51 -2
- package/dist/execution-journal.js +3 -1
- package/dist/execution-protocol.js +1 -1
- package/dist/execution-runner.js +4 -1
- package/dist/host-execution-coordinator.js +10 -0
- package/dist/local-execution-prompt.js +8 -3
- package/dist/local-executor.js +78 -55
- package/dist/local-memory/commit-telemetry.js +30 -0
- package/dist/local-memory/execution-workspace.js +117 -0
- package/dist/local-memory/full-index-search.js +47 -0
- package/dist/local-memory/index-budget.js +9 -3
- package/dist/local-memory/initialization-identity.js +36 -0
- package/dist/local-memory/inventory-cli.js +52 -8
- package/dist/local-memory/inventory-source.js +15 -8
- package/dist/local-memory/inventory-v2.js +362 -0
- package/dist/local-memory/legacy-adapter.js +233 -0
- package/dist/local-memory/migration-access.js +242 -0
- package/dist/local-memory/migration-cli.js +54 -0
- package/dist/local-memory/migration-io.js +199 -0
- package/dist/local-memory/migration-pending.js +9 -0
- package/dist/local-memory/migration-plan.js +432 -0
- package/dist/local-memory/migration-schema.js +58 -0
- package/dist/local-memory/migration-state-invariants.js +65 -0
- package/dist/local-memory/migration-store.js +414 -0
- package/dist/local-memory/migration-tool-entry.js +21 -0
- package/dist/local-memory/pending-query.js +5 -2
- package/dist/local-memory/pending-schema.js +1 -1
- package/dist/local-memory/pending.js +16 -2
- package/dist/local-memory/prompt.js +21 -5
- package/dist/local-memory/read-cli.js +98 -76
- package/dist/local-memory/release-artifact-guard.js +55 -0
- package/dist/local-memory/rollout.js +79 -11
- package/dist/local-memory/runtime.js +191 -17
- package/dist/local-memory/source-path.js +13 -0
- package/dist/local-memory/storage-format.js +249 -0
- package/dist/local-memory/write.js +190 -21
- package/dist/local-memory/writer-mode.js +13 -0
- package/dist/local-memory-diagnostics.js +96 -15
- package/dist/local-memory-telemetry.js +31 -3
- package/dist/machine-info.js +6 -1
- package/dist/machine-runtime-environment.js +1 -0
- package/dist/marketplace-protocol.js +1 -1
- package/dist/marketplace-remote.js +1 -1
- package/dist/marketplace-runner.js +1 -1
- package/dist/memory-migration-controller.js +89 -0
- package/dist/memory-migration-inspect.js +116 -0
- package/dist/memory-migration-journal.js +14 -0
- package/dist/memory-migration-protocol.js +14 -0
- package/dist/memory-migration-runtime.js +367 -0
- package/dist/memory-prune-diagnostics.js +74 -4
- package/dist/message-file-preview.js +11 -1
- package/dist/prompt.js +9 -17
- package/dist/runner.js +1 -1
- package/dist/runtime-tool-update-bridge.js +126 -0
- package/dist/runtime-tool-update-controller.js +151 -0
- package/dist/runtime-tool-update-protocol.js +24 -0
- package/dist/runtime-tool-update-serve.js +54 -0
- package/dist/runtimes/claude-thread-runner.js +25 -4
- package/dist/serve.js +47 -3
- package/dist/token.js +1 -0
- package/dist/workspace-control-handler.js +16 -3
- package/dist/workspace.js +23 -4
- package/package.json +1 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { homedir, hostname, platform } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
const ALIYUN_MARKER = /alibaba|aliyun|alicloud/iu;
|
|
5
4
|
function readMarker(path) {
|
|
6
5
|
try {
|
|
@@ -29,15 +28,7 @@ export function detectCloudProvider(env = process.env, platformName = platform()
|
|
|
29
28
|
}
|
|
30
29
|
export function findOssUploadScript(env = process.env, exists = existsSync) {
|
|
31
30
|
const explicit = env.CREW_OSS_UPLOAD_SCRIPT?.trim();
|
|
32
|
-
|
|
33
|
-
return exists(explicit) ? explicit : undefined;
|
|
34
|
-
const home = env.HOME?.trim() || homedir();
|
|
35
|
-
const candidates = [
|
|
36
|
-
join(home, ".claude", "skills", "oss-upload", "scripts", "oss_upload.py"),
|
|
37
|
-
join(home, ".codex", "skills", "oss-upload", "scripts", "oss_upload.py"),
|
|
38
|
-
join(home, ".agents", "skills", "oss-upload", "scripts", "oss_upload.py"),
|
|
39
|
-
];
|
|
40
|
-
return candidates.find(exists);
|
|
31
|
+
return explicit && exists(explicit) ? explicit : undefined;
|
|
41
32
|
}
|
|
42
33
|
export function cloudReportUploadFacts(env = process.env, platformName = platform(), hostName = hostname(), readMarkerValue, exists) {
|
|
43
34
|
const provider = detectCloudProvider(env, platformName, hostName, readMarkerValue);
|
|
@@ -3,10 +3,25 @@ import { renameSync } from "node:fs";
|
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
+
const ProtectedGroupSchema = z.object({ pid: z.number().int().positive(), processIdentity: z.string().min(1) }).strict();
|
|
7
|
+
export async function inspectProtectedProcessGroup(pid) {
|
|
8
|
+
try {
|
|
9
|
+
process.kill(-pid, 0);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error.code === "ESRCH")
|
|
14
|
+
return false;
|
|
15
|
+
if (error.code === "EPERM")
|
|
16
|
+
return true;
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
6
20
|
const OwnerSchema = z.object({
|
|
7
21
|
pid: z.number().int().positive(),
|
|
8
22
|
processIdentity: z.string().min(1),
|
|
9
23
|
token: z.string().uuid(),
|
|
24
|
+
protectedGroup: ProtectedGroupSchema.optional(),
|
|
10
25
|
}).strict();
|
|
11
26
|
export class JournalLockedError extends Error {
|
|
12
27
|
journalPath;
|
|
@@ -144,7 +159,8 @@ export async function inspectJournalLock(options) {
|
|
|
144
159
|
let inspection;
|
|
145
160
|
try {
|
|
146
161
|
const identity = await options.inspectIdentity(owner.pid);
|
|
147
|
-
|
|
162
|
+
const protectedAlive = owner.protectedGroup !== undefined && await (options.inspectProcessGroup ?? inspectProtectedProcessGroup)(owner.protectedGroup.pid);
|
|
163
|
+
inspection = identity === owner.processIdentity || protectedAlive
|
|
148
164
|
? {
|
|
149
165
|
status: "owned",
|
|
150
166
|
ownerPid: owner.pid,
|
|
@@ -333,7 +349,9 @@ export function createJournalLease(options) {
|
|
|
333
349
|
if (observed === null)
|
|
334
350
|
continue;
|
|
335
351
|
const identity = await options.inspectIdentity(observed.owner.pid);
|
|
336
|
-
|
|
352
|
+
const protectedAlive = observed.owner.protectedGroup !== undefined
|
|
353
|
+
&& await (options.inspectProcessGroup ?? inspectProtectedProcessGroup)(observed.owner.protectedGroup.pid);
|
|
354
|
+
if (identity === observed.owner.processIdentity || protectedAlive) {
|
|
337
355
|
throw new JournalLockedError(`Execution journal is locked by process ${observed.owner.pid}`, { journalPath, ownerPid: observed.owner.pid });
|
|
338
356
|
}
|
|
339
357
|
await options.hooks?.beforeRemoveObservedOwner?.(observed.owner);
|
|
@@ -408,6 +426,9 @@ export function createJournalLease(options) {
|
|
|
408
426
|
status = "closed";
|
|
409
427
|
return;
|
|
410
428
|
}
|
|
429
|
+
if (lease.owner.protectedGroup && await (options.inspectProcessGroup ?? inspectProtectedProcessGroup)(lease.owner.protectedGroup.pid)) {
|
|
430
|
+
throw new JournalLockedError("Protected maintenance process group is still alive", { journalPath, ownerPid: lease.owner.protectedGroup.pid });
|
|
431
|
+
}
|
|
411
432
|
status = "closing";
|
|
412
433
|
lease.releasing = true;
|
|
413
434
|
await awaitAbortable((async () => {
|
|
@@ -426,8 +447,36 @@ export function createJournalLease(options) {
|
|
|
426
447
|
status = "closed";
|
|
427
448
|
void cleanupReleasedDirectory(releasedDirectory);
|
|
428
449
|
};
|
|
450
|
+
const protectProcessGroup = async (raw) => {
|
|
451
|
+
const group = ProtectedGroupSchema.parse(raw);
|
|
452
|
+
const lease = registry.get(options.directory);
|
|
453
|
+
if (!attached || status !== "open" || !lease || lease.releasing || lease.refs !== 1)
|
|
454
|
+
throw new JournalLockedError("Lease cannot protect a worker", { journalPath });
|
|
455
|
+
await validateInstalledOwner(lease);
|
|
456
|
+
if (await options.inspectIdentity(group.pid) !== group.processIdentity
|
|
457
|
+
|| !await (options.inspectProcessGroup ?? inspectProtectedProcessGroup)(group.pid))
|
|
458
|
+
throw new JournalLockedError("Worker identity is absent", { journalPath });
|
|
459
|
+
if (lease.owner.protectedGroup) {
|
|
460
|
+
if (JSON.stringify(lease.owner.protectedGroup) === JSON.stringify(group))
|
|
461
|
+
return;
|
|
462
|
+
throw new JournalLockedError("Lease already protects a worker", { journalPath });
|
|
463
|
+
}
|
|
464
|
+
const owner = { ...lease.owner, protectedGroup: group };
|
|
465
|
+
const temp = join(options.directory, `.journal-owner.${lease.owner.token}.${randomUUID()}.tmp`);
|
|
466
|
+
try {
|
|
467
|
+
await fileSystem.writeDurableFile(temp, `${JSON.stringify(owner)}\n`);
|
|
468
|
+
await fileSystem.rename(temp, join(lockDirectory, lease.ownerFile));
|
|
469
|
+
lease.owner = owner;
|
|
470
|
+
await options.syncDirectory(lockDirectory);
|
|
471
|
+
await options.syncDirectory(options.directory);
|
|
472
|
+
}
|
|
473
|
+
finally {
|
|
474
|
+
await fileSystem.rm(temp, { force: true }).catch(() => undefined);
|
|
475
|
+
}
|
|
476
|
+
};
|
|
429
477
|
return {
|
|
430
478
|
acquire,
|
|
479
|
+
protectProcessGroup,
|
|
431
480
|
assertUsable: () => {
|
|
432
481
|
if (status !== "open") {
|
|
433
482
|
throw new JournalLockedError(`Execution journal lease is ${status}`, { journalPath });
|
|
@@ -8,7 +8,7 @@ import { provePosixProcessGroupStopped } from "./execution-posix-stop-proof.js";
|
|
|
8
8
|
export { JournalLockedError, JournalLockCorruptionError } from "./execution-journal-lock.js";
|
|
9
9
|
const ExecutionIdSchema = z.string().uuid();
|
|
10
10
|
const TimestampSchema = z.string().datetime({ offset: true });
|
|
11
|
-
const RuntimeSchema = z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness", "pi"]);
|
|
11
|
+
const RuntimeSchema = z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness", "memory_migration", "pi"]);
|
|
12
12
|
const RUNTIME_READY_SUFFIX = ".runtime-ready";
|
|
13
13
|
const RawJournalEntrySchema = z.object({
|
|
14
14
|
executionId: ExecutionIdSchema,
|
|
@@ -523,6 +523,8 @@ export function createExecutionJournal(agentsRoot, options = {}) {
|
|
|
523
523
|
}
|
|
524
524
|
};
|
|
525
525
|
const pruneInternal = async () => {
|
|
526
|
+
if (options.retainCompleted)
|
|
527
|
+
return;
|
|
526
528
|
const protectedExecutionIds = new Set(options.protectedExecutionIds?.() ?? []);
|
|
527
529
|
const entries = await readAll();
|
|
528
530
|
const acknowledged = entries
|
|
@@ -319,7 +319,7 @@ const RawExecutionCompletedSchema = z.object({
|
|
|
319
319
|
providerErrorCategory: ProviderErrorCategorySchema.optional(),
|
|
320
320
|
providerHttpStatus: ProviderHttpStatusSchema.optional(),
|
|
321
321
|
providerErrorCode: ProviderErrorCodeSchema.optional(),
|
|
322
|
-
runtime: RuntimeSchema,
|
|
322
|
+
runtime: z.union([RuntimeSchema, z.literal("memory_migration")]),
|
|
323
323
|
model: z.string().optional(),
|
|
324
324
|
resumed: z.boolean(),
|
|
325
325
|
finalText: z.string().optional(),
|
package/dist/execution-runner.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { isLocalMemoryV2Enabled, localMemoryV2Environment, resolveReposRoot } from "./config.js";
|
|
4
|
+
import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
|
|
4
5
|
import { DaemonToServerExecutionFrameSchema, ExecutionCompletedSchema, ExecutionRejectedSchema, ExecutionStartSchema, } from "./execution-protocol.js";
|
|
5
6
|
import { JournalConflictError } from "./execution-journal.js";
|
|
6
7
|
import { boundExecutionFrame } from "./execution-event-limit.js";
|
|
@@ -846,8 +847,9 @@ export async function runExecution(config, input, dependencies) {
|
|
|
846
847
|
const localMemoryGuardInBase = localMemoryV2Environment(config.serverUrl) === "custom";
|
|
847
848
|
const boundedSystemPrompt = (context) => {
|
|
848
849
|
const enabled = context.workspace.localMemoryV2Enabled ?? localMemoryV2Enabled;
|
|
849
|
-
const systemPromptWithLocalFacts = withLocalExecutionFacts(`${spec.instructions.systemPrompt}${enabled && localMemoryGuardInBase ? renderLocalMemoryV2WriteGuard() : ""}`, baseSystemPromptBudget, {
|
|
850
|
+
const systemPromptWithLocalFacts = withLocalExecutionFacts(`${spec.instructions.systemPrompt}${enabled && localMemoryGuardInBase && detectLocalMemoryStorageVersion(context.workspace.memory) !== 2 ? renderLocalMemoryV2WriteGuard() : ""}`, baseSystemPromptBudget, {
|
|
850
851
|
...(selfTraining ? { isolateLocalMemory: true } : {}),
|
|
852
|
+
memoryQuery: spec.instructions.wakePrompt,
|
|
851
853
|
collaborationTools: config.codexCollaborationTools && spec.runtime.name === "codex",
|
|
852
854
|
});
|
|
853
855
|
const base = typeof systemPromptWithLocalFacts === "string"
|
|
@@ -887,6 +889,7 @@ export async function runExecution(config, input, dependencies) {
|
|
|
887
889
|
serverUrl: config.serverUrl,
|
|
888
890
|
token: credential.token,
|
|
889
891
|
agentId: credential.agentId,
|
|
892
|
+
...(dependencies.controlIdentity === undefined ? {} : dependencies.controlIdentity),
|
|
890
893
|
agentsRoot: config.agentsRoot,
|
|
891
894
|
reposRoot: resolveReposRoot(config.agentsRoot, config.reposRoot),
|
|
892
895
|
...(config.qaReportRoot === undefined ? {} : { qaReportRoot: config.qaReportRoot }),
|
|
@@ -302,6 +302,16 @@ export function createHostExecutionCoordinator(options = {}) {
|
|
|
302
302
|
}
|
|
303
303
|
let releasePromise = null;
|
|
304
304
|
return {
|
|
305
|
+
protectProcessGroup: async (pid) => {
|
|
306
|
+
const processIdentity = await defaultProcessController.inspectIdentity(pid);
|
|
307
|
+
if (processIdentity === null)
|
|
308
|
+
throw new Error("maintenance worker identity is absent");
|
|
309
|
+
for (const lease of leases) {
|
|
310
|
+
if (!lease.protectProcessGroup)
|
|
311
|
+
throw new Error("lease process-group protection is unavailable");
|
|
312
|
+
await lease.protectProcessGroup({ pid, processIdentity });
|
|
313
|
+
}
|
|
314
|
+
},
|
|
305
315
|
release: () => {
|
|
306
316
|
if (releasePromise !== null)
|
|
307
317
|
return releasePromise;
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* 本机执行提示词的合成与预算裁剪。
|
|
3
3
|
*
|
|
4
4
|
* server 提示词是权威部分,绝不裁剪;项目工作区提示词是绑定执行的强制部分,放不下就直接失败;
|
|
5
|
-
*
|
|
5
|
+
* 本机事实与旧格式预览可按预算省略;schema2身份和置顶规则必须保留,放不下则拒绝执行。
|
|
6
6
|
*/
|
|
7
|
+
import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
|
|
7
8
|
import { buildCollaborationToolsPrompt, buildRuntimeWorkspacePrompt, capMemoryForInject, capWorkLogForInject, } from "./prompt.js";
|
|
8
9
|
const trainingProjectJson = (project) => JSON.stringify({
|
|
9
10
|
repositoryKey: project.repositoryKey,
|
|
@@ -57,10 +58,14 @@ export function withLocalExecutionFacts(serverPrompt, maxBytes, options = {}) {
|
|
|
57
58
|
}
|
|
58
59
|
const remaining = maxBytes - requiredBytes - Math.max(0, reservedPromptBytes);
|
|
59
60
|
const factsBytes = Buffer.byteLength(localFacts, "utf8");
|
|
60
|
-
if (factsBytes > remaining)
|
|
61
|
+
if (factsBytes > remaining) {
|
|
62
|
+
if (!options.isolateLocalMemory && detectLocalMemoryStorageVersion(workspace.memory) === 2) {
|
|
63
|
+
throw new Error("local_memory_identity_budget_exceeded");
|
|
64
|
+
}
|
|
61
65
|
return `${serverPrompt}${collaborationPrompt}${mandatoryWorkspacePrompt}`;
|
|
66
|
+
}
|
|
62
67
|
const memoryHeading = "\n\n## Injected MEMORY.md (bounded local context)\n";
|
|
63
|
-
const memory = options.isolateLocalMemory ? "" : capMemoryForInject(workspace.memory, undefined, remaining - factsBytes - Buffer.byteLength(memoryHeading, "utf8"));
|
|
68
|
+
const memory = options.isolateLocalMemory ? "" : capMemoryForInject(workspace.memory, undefined, remaining - factsBytes - Buffer.byteLength(memoryHeading, "utf8"), options.memoryQuery);
|
|
64
69
|
const memorySection = memory === "" ? "" : memoryHeading + memory;
|
|
65
70
|
const workLogSection = workLog === "" ? "" : `\n\n## Injected work-log (bounded local context)\n${workLog}`;
|
|
66
71
|
const workLogBudget = remaining - factsBytes - Buffer.byteLength(memorySection, "utf8");
|
package/dist/local-executor.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createInterface } from "node:readline";
|
|
|
6
6
|
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { cleanupSelfTrainingRunDir } from "./self-training-workspace.js";
|
|
9
|
-
import {
|
|
9
|
+
import { rotateAgentSession, safeKey, } from "./workspace.js";
|
|
10
10
|
import { CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV, isClaudeAdditionalDirectoryInstructionsSupported, probeClaudeVersion, spawnClaude, } from "./runtimes/claude.js";
|
|
11
11
|
import { spawnCodex } from "./runtimes/codex.js";
|
|
12
12
|
import { DEEPSEEK_CODEX_MODEL, DEEPSEEK_CODEX_REASONING_LEVELS, materializeDeepSeekCodexHome, } from "./runtimes/codex-deepseek-config.js";
|
|
@@ -38,14 +38,22 @@ import { formatProjectSkillRuntimeWarning } from "./project-skills/runtime-warni
|
|
|
38
38
|
import { projectSkillRuntimeDirectories, } from "./project-skills/runtime-launch.js";
|
|
39
39
|
import { logIdentityRosterRuntimePrepared } from "./identity-roster-telemetry.js";
|
|
40
40
|
import { diffMemoryPruneNotes, evaluateMemoryPrunePostcondition, inspectMemoryPruneFilesWithinDeadline, logMemoryPruneDiagnosticsFailure, memoryPruneSnapshotFields, parseMemoryPruneTraceId, } from "./memory-prune-diagnostics.js";
|
|
41
|
+
import { checkReleaseArtifactGuardBeforeCommit, throwReleaseArtifactGuardFailure } from "./local-memory/release-artifact-guard.js";
|
|
41
42
|
import { createLocalMemoryTelemetry, logLocalMemoryContextPrepareFailure, logLocalMemoryDiagnosticsFailure, } from "./local-memory-telemetry.js";
|
|
43
|
+
import { LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS } from "./local-memory-diagnostics.js";
|
|
42
44
|
import { CodexStartupStageParser } from "./codex-startup-stage.js";
|
|
43
45
|
import { formatRuntimeStartupError } from "./runtime-startup-error.js";
|
|
44
46
|
import { logRuntimeEnvironmentContract } from "./runtime-environment-telemetry.js";
|
|
45
|
-
import { commitLocalMemoryResultAfterExit,
|
|
47
|
+
import { commitLocalMemoryResultAfterExit, isLocalMemoryV2Eligible, localMemoryResultPath as makeLocalMemoryResultPath, } from "./local-memory/runtime.js";
|
|
46
48
|
import { prepareLocalMemoryPrompt } from "./local-memory/prompt.js";
|
|
47
|
-
import { reportLocalMemoryV2Deferred
|
|
49
|
+
import { reportLocalMemoryV2Deferred } from "./local-memory/rollout.js";
|
|
50
|
+
import { prepareExecutionMemoryWorkspace } from "./local-memory/execution-workspace.js";
|
|
48
51
|
import { localMemoryV2Environment } from "./config.js";
|
|
52
|
+
import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
|
|
53
|
+
import { MEMORY_STATE_GUARD_CAPABILITY, MEMORY_STORAGE_V2_CAPABILITY } from "./memory-migration-protocol.js";
|
|
54
|
+
import { resolveLocalMemoryWriterMode } from "./local-memory/writer-mode.js";
|
|
55
|
+
import { logLocalMemoryCommitApplied } from "./local-memory/commit-telemetry.js";
|
|
56
|
+
import { shouldUseMigrationDeferredPending } from "./local-memory/migration-pending.js";
|
|
49
57
|
export class RuntimeRunningCallbackTimeoutError extends Error {
|
|
50
58
|
constructor(runtime, timeoutMs) {
|
|
51
59
|
super(`${runtime} runtime-running callback timed out after ${timeoutMs}ms`);
|
|
@@ -59,7 +67,6 @@ const STDERR_TAIL_CAP = 2_000;
|
|
|
59
67
|
// the old failure mode where a callback could hold execution slots forever.
|
|
60
68
|
const RUNTIME_RUNNING_CALLBACK_TIMEOUT_MS = 30_000;
|
|
61
69
|
const MEMORY_PRUNE_DIAGNOSTICS_TIMEOUT_MS = 2_000;
|
|
62
|
-
const LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS = 250;
|
|
63
70
|
const CLAUDE_INSTRUCTION_WARNING = "claude_additional_directory_instructions_unverified";
|
|
64
71
|
const CODEX_COLLABORATION_EXEC_WARNING = "codex_collaboration_disabled_on_exec";
|
|
65
72
|
function withoutClaudeInstructionFlag(env) {
|
|
@@ -211,37 +218,12 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
211
218
|
: "high"
|
|
212
219
|
: runtime.reasoning;
|
|
213
220
|
const providerFp = providerFingerprint(runtime.name, providerConfig);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
agentsRoot: input.launch.agentsRoot,
|
|
218
|
-
handle: input.handle,
|
|
219
|
-
cliPath: input.launch.cliPath,
|
|
220
|
-
executionId: input.executionId,
|
|
221
|
-
...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
|
|
222
|
-
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
223
|
-
...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
|
|
224
|
-
...(input.sessionContextFingerprint === undefined
|
|
225
|
-
? {}
|
|
226
|
-
: { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
227
|
-
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
228
|
-
...(isolatedMaintenance ? { skipLocalMemory: true } : {}),
|
|
229
|
-
}), dependencies.cancellation);
|
|
230
|
-
}
|
|
231
|
-
catch (error) {
|
|
232
|
-
logLocalMemoryContextPrepareFailure({
|
|
233
|
-
executionId: input.executionId,
|
|
234
|
-
agentHandle: input.handle,
|
|
235
|
-
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
236
|
-
}, "workspace_prepare", error);
|
|
237
|
-
throw error;
|
|
238
|
-
}
|
|
239
|
-
const memoryRollout = await resolveLocalMemoryV2Rollout({ workspace, handle: input.handle,
|
|
240
|
-
serverUrl: input.launch.serverUrl, requested: input.localMemoryV2Enabled === true,
|
|
241
|
-
selfTraining: isolatedMaintenance, ...(input.launch.description ? { description: input.launch.description } : {}) });
|
|
242
|
-
workspace = { ...workspace, localMemoryV2Enabled: memoryRollout.enabled };
|
|
221
|
+
const preparedMemory = await prepareExecutionMemoryWorkspace(input, isolatedMaintenance, dependencies.cancellation);
|
|
222
|
+
let workspace = preparedMemory.workspace;
|
|
223
|
+
const memoryRollout = preparedMemory.mode;
|
|
243
224
|
input = { ...input, localMemoryV2Enabled: memoryRollout.enabled };
|
|
244
|
-
const localMemoryV2Initialized =
|
|
225
|
+
const localMemoryV2Initialized = preparedMemory.initialized;
|
|
226
|
+
let localMemoryWriterMode = resolveLocalMemoryWriterMode(workspace, memoryRollout);
|
|
245
227
|
let materialized = null;
|
|
246
228
|
let knownAttachmentDirectory = null;
|
|
247
229
|
const startupReservationState = { current: null };
|
|
@@ -252,6 +234,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
252
234
|
let memoryPruneBeforeSnapshot = null;
|
|
253
235
|
let memoryPruneSharedWriteKey = null;
|
|
254
236
|
let localMemoryResultPath = null;
|
|
237
|
+
let migrationDeferredPending = false;
|
|
255
238
|
let environmentSnapshot;
|
|
256
239
|
let executionWorkspace = workspace;
|
|
257
240
|
let localMemoryTelemetry = null;
|
|
@@ -390,29 +373,41 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
390
373
|
const attachmentPlan = routeRuntimeAttachments(runtime.name, materialized?.attachments ?? []);
|
|
391
374
|
let baseWakePrompt = `${resolvePrompt(input.wakePrompt, promptContext)}${attachmentPlan.promptSuffix}`;
|
|
392
375
|
memoryPruneTraceId = isolatedMaintenance ? null : parseMemoryPruneTraceId(baseWakePrompt);
|
|
393
|
-
|
|
394
|
-
|
|
376
|
+
localMemoryWriterMode = resolveLocalMemoryWriterMode(executionWorkspace, memoryRollout);
|
|
377
|
+
migrationDeferredPending = shouldUseMigrationDeferredPending({ pruneTraceId: memoryPruneTraceId,
|
|
378
|
+
writerMode: localMemoryWriterMode, rolloutEnabled: memoryRollout.enabled,
|
|
379
|
+
legacyFallback: memoryRollout.legacyFallback,
|
|
380
|
+
failure: memoryRollout.failure, memory: executionWorkspace.memory });
|
|
381
|
+
if (memoryRollout.deferred || migrationDeferredPending)
|
|
382
|
+
reportLocalMemoryV2Deferred(input.executionId, input.handle, memoryPruneTraceId !== null || input.maintenancePurpose === "memory_prune", memoryRollout.legacyFallback, memoryRollout.failure, migrationDeferredPending);
|
|
383
|
+
if (memoryPruneTraceId !== null && localMemoryWriterMode === "blocked" && !migrationDeferredPending) {
|
|
384
|
+
throw new Error(memoryRollout.failure === "inspection_failed" ? "local_memory_inspection_failed" : "local_memory_v2_requires_migration");
|
|
385
|
+
}
|
|
395
386
|
if (memoryPruneTraceId !== null) {
|
|
396
387
|
executionWorkspace = await resolveMemoryPruneWorkLog(executionWorkspace, input);
|
|
397
388
|
promptContext = { ...promptContext, workspace: executionWorkspace };
|
|
398
389
|
baseWakePrompt = `${resolvePrompt(input.wakePrompt, promptContext)}${attachmentPlan.promptSuffix}`;
|
|
399
390
|
}
|
|
400
|
-
if (
|
|
391
|
+
if ((localMemoryWriterMode === "v2" && memoryPruneTraceId !== null
|
|
401
392
|
&& isLocalMemoryV2Eligible({
|
|
402
393
|
enabledForHandle: true,
|
|
403
394
|
agentHomePreexisted: workspace.agentHomePreexisted === true,
|
|
404
395
|
memorySeedCreated: executionWorkspace.memorySeedCreated === true && (localMemoryV2Initialized || workspace.localMemoryV2Initialized !== false),
|
|
405
396
|
localMemoryV2Initialized,
|
|
406
397
|
memoryPrune: true,
|
|
407
|
-
})) {
|
|
398
|
+
})) || migrationDeferredPending) {
|
|
408
399
|
localMemoryResultPath = makeLocalMemoryResultPath(executionWorkspace.runDir, input.executionId);
|
|
409
400
|
}
|
|
410
401
|
const memoryPrompt = await prepareLocalMemoryPrompt({
|
|
411
402
|
agentDir: executionWorkspace.dir, executionId: input.executionId, agentHandle: input.handle,
|
|
412
403
|
enabled: input.localMemoryV2Enabled === true, query: baseWakePrompt,
|
|
413
404
|
resultPath: localMemoryResultPath, maxBytes: input.maxSystemPromptBytes,
|
|
414
|
-
|
|
405
|
+
storageVersion: detectLocalMemoryStorageVersion(executionWorkspace.memory),
|
|
406
|
+
strictRollout: !isolatedMaintenance && !memoryRollout.legacyFallback && (localMemoryV2Environment(input.launch.serverUrl) === "dev"
|
|
407
|
+
|| detectLocalMemoryStorageVersion(executionWorkspace.memory) === 2),
|
|
415
408
|
deferred: memoryRollout.deferred,
|
|
409
|
+
...(memoryRollout.legacyFallback ? { legacyFallback: true } : {}),
|
|
410
|
+
...(migrationDeferredPending ? { migrationDeferred: true } : {}),
|
|
416
411
|
renderBase: (reservedPromptBytes) => resolvePrompt(input.systemPrompt, { ...promptContext, reservedPromptBytes }),
|
|
417
412
|
});
|
|
418
413
|
localMemoryResultPath = memoryPrompt.resultPath;
|
|
@@ -528,6 +523,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
528
523
|
localMemoryTelemetry?.contextPrepared({
|
|
529
524
|
systemPrompt: effectiveSystemPrompt,
|
|
530
525
|
memory: executionWorkspace.memory,
|
|
526
|
+
memoryQuery: baseWakePrompt,
|
|
531
527
|
resumed: resuming,
|
|
532
528
|
...(executionWorkspace.memorySeedCreated === undefined
|
|
533
529
|
? {}
|
|
@@ -901,15 +897,21 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
901
897
|
if (localMemoryResultPath !== null) {
|
|
902
898
|
memoryPruneFailurePhase = "memory_commit";
|
|
903
899
|
const resultPath = localMemoryResultPath;
|
|
904
|
-
const commit = () =>
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
900
|
+
const commit = async () => {
|
|
901
|
+
if (exitCode === 0) {
|
|
902
|
+
const releaseGuard = await checkReleaseArtifactGuardBeforeCommit({ runDir: executionWorkspace.runDir, scopeKey: memoryPruneTraceId, before: memoryPruneBeforeSnapshot, inspectAfter: () => inspectMemoryPruneFilesWithinDeadline(executionWorkspace.dir, executionWorkspace.runDir, executionWorkspace.workLogPath, dependencies.memoryPruneDiagnosticsTimeoutMs ?? MEMORY_PRUNE_DIAGNOSTICS_TIMEOUT_MS) });
|
|
903
|
+
if (releaseGuard.blocked) {
|
|
904
|
+
memoryPruneFailurePhase = "memory_artifact_guard";
|
|
905
|
+
throwReleaseArtifactGuardFailure({ result: releaseGuard, executionId: input.executionId,
|
|
906
|
+
agentHandle: input.handle, taskKey: input.taskKey, pruneTraceId: memoryPruneTraceId });
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return commitLocalMemoryResultAfterExit({ resultPath, agentDir: executionWorkspace.dir, executionId: input.executionId,
|
|
910
|
+
pruneTraceId: memoryPruneTraceId, exitCode, workLogPath: executionWorkspace.workLogPath,
|
|
911
|
+
expectedWorkLogSha256: workLogSha256(executionWorkspace.workLog),
|
|
912
|
+
...(localMemoryWriterMode === "v2" ? { writerCapabilities: [MEMORY_STORAGE_V2_CAPABILITY, MEMORY_STATE_GUARD_CAPABILITY], requiredStorageVersion: 2 } : {}),
|
|
913
|
+
...(migrationDeferredPending ? { migrationDeferredPending: true } : {}) });
|
|
914
|
+
};
|
|
913
915
|
const committed = exitCode !== 0 ? await commit() : await withWorkLogCommit(workLogExecutionKey(input.launch.agentsRoot, input.handle, input.taskKey), commit, dependencies.cancellation);
|
|
914
916
|
if (committed.status === "failed" || committed.status === "missing") {
|
|
915
917
|
const reason = committed.error ?? "local_memory_result_missing";
|
|
@@ -922,6 +924,14 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
922
924
|
});
|
|
923
925
|
throw new Error(`local_memory_commit_failed: ${reason}`);
|
|
924
926
|
}
|
|
927
|
+
if (committed.status === "applied") {
|
|
928
|
+
if (localMemoryWriterMode === "v2" && (committed.storageVersionBefore !== 2 || committed.storageVersionAfter !== 2
|
|
929
|
+
|| committed.committedState !== true)) {
|
|
930
|
+
throw new Error("local_memory_commit_failed: local_memory_v2_commit_state_invalid");
|
|
931
|
+
}
|
|
932
|
+
logLocalMemoryCommitApplied({ executionId: input.executionId, agentHandle: input.handle,
|
|
933
|
+
pruneTraceId: memoryPruneTraceId, committed });
|
|
934
|
+
}
|
|
925
935
|
memoryPruneFailurePhase = "runtime_finalize";
|
|
926
936
|
}
|
|
927
937
|
const errorTail = [
|
|
@@ -962,13 +972,9 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
962
972
|
await writeFile(legacyCwdMarker, "1", "utf8");
|
|
963
973
|
}
|
|
964
974
|
}
|
|
965
|
-
const externalAnswer = runtime.name === "pi"
|
|
966
|
-
?
|
|
967
|
-
|
|
968
|
-
?? (finalText === null ? null : extractExternalAnswer(finalText));
|
|
969
|
-
const reportFinalText = runtime.name === "pi" && externalAnswer === null
|
|
970
|
-
? null
|
|
971
|
-
: finalText;
|
|
975
|
+
const externalAnswer = runtime.name === "pi" ? externalOutput.lastClosedBlock : externalOutput.lastClosedBlock
|
|
976
|
+
?? (finalText === null ? null : extractExternalAnswer(finalText));
|
|
977
|
+
const reportFinalText = runtime.name === "pi" && externalAnswer === null ? null : finalText;
|
|
972
978
|
const cloudReportResult = exitCode === 0
|
|
973
979
|
? await deliverCloudReports({
|
|
974
980
|
facts: cloudReportUpload, ...reportRoots, before: reportSnapshot, finalText: reportFinalText,
|
|
@@ -1052,6 +1058,23 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
1052
1058
|
after_incomplete_file_count: noteDiff.after_manifest.incomplete_file_count,
|
|
1053
1059
|
changes: serializedChanges.json,
|
|
1054
1060
|
});
|
|
1061
|
+
const pendingDiff = diffMemoryPruneNotes(memoryPruneBeforeSnapshot.pending_manifest
|
|
1062
|
+
?? { files: [], total_count: 0, omitted_count: 0, truncated: false }, snapshot.pending_manifest
|
|
1063
|
+
?? { files: [], total_count: 0, omitted_count: 0, truncated: false });
|
|
1064
|
+
const serializedPendingChanges = boundedDiagnosticJsonArray(pendingDiff.changes);
|
|
1065
|
+
const pendingChangesTruncated = pendingDiff.truncated || serializedPendingChanges.truncated;
|
|
1066
|
+
dslog("memory_prune.pending_changed", "长期记忆 pending 候选变化已评估", {
|
|
1067
|
+
execution_id: input.executionId,
|
|
1068
|
+
agent_handle: input.handle,
|
|
1069
|
+
task_key: input.taskKey,
|
|
1070
|
+
prune_trace_id: memoryPruneTraceId,
|
|
1071
|
+
change_count: pendingDiff.change_count,
|
|
1072
|
+
changes_truncated: pendingChangesTruncated,
|
|
1073
|
+
evidence_complete: pendingDiff.evidence_complete && !pendingChangesTruncated,
|
|
1074
|
+
before_total_count: pendingDiff.before_manifest.total_count,
|
|
1075
|
+
after_total_count: pendingDiff.after_manifest.total_count,
|
|
1076
|
+
changes: serializedPendingChanges.json,
|
|
1077
|
+
});
|
|
1055
1078
|
const postcondition = evaluateMemoryPrunePostcondition(memoryPruneBeforeSnapshot, snapshot, {
|
|
1056
1079
|
executorCompleted: memoryPruneExecutorCompleted,
|
|
1057
1080
|
...(memoryPruneRuntimeExitCode === undefined
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { dslog } from "../slog.js";
|
|
2
|
+
function boundedIds(ids) {
|
|
3
|
+
return {
|
|
4
|
+
value: (ids ?? []).slice(0, 100).join(","),
|
|
5
|
+
count: ids?.length ?? 0,
|
|
6
|
+
truncated: (ids?.length ?? 0) > 100,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function logLocalMemoryCommitApplied(input) {
|
|
10
|
+
const { committed } = input;
|
|
11
|
+
const created = boundedIds(committed.createdIds);
|
|
12
|
+
const updated = boundedIds(committed.updatedIds);
|
|
13
|
+
const statusChanged = boundedIds(committed.statusChangedIds);
|
|
14
|
+
const pending = boundedIds(committed.pendingIds);
|
|
15
|
+
dslog("local_memory.commit_applied", "结构化本地记忆提交已验证", {
|
|
16
|
+
execution_id: input.executionId, agent_handle: input.agentHandle, prune_trace_id: input.pruneTraceId,
|
|
17
|
+
storage_version_before: committed.storageVersionBefore,
|
|
18
|
+
storage_version_after: committed.storageVersionAfter,
|
|
19
|
+
committed_state: committed.committedState,
|
|
20
|
+
writer_mode: committed.pendingReason === "legacy_requires_migration"
|
|
21
|
+
? "pending_only"
|
|
22
|
+
: committed.storageVersionAfter === 2 && committed.committedState ? "v2" : "legacy",
|
|
23
|
+
created_id_count: created.count, created_ids: created.value, created_ids_truncated: created.truncated,
|
|
24
|
+
updated_id_count: updated.count, updated_ids: updated.value, updated_ids_truncated: updated.truncated,
|
|
25
|
+
status_changed_id_count: statusChanged.count, status_changed_ids: statusChanged.value,
|
|
26
|
+
status_changed_ids_truncated: statusChanged.truncated,
|
|
27
|
+
pending_id_count: pending.count, pending_ids: pending.value, pending_ids_truncated: pending.truncated,
|
|
28
|
+
pending_reason: committed.pendingReason,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { LocalMemoryWorkspacePrepareError, prepareWorkspace } from "../workspace.js";
|
|
2
|
+
import { awaitWithCancellation } from "../runtime-cancellation.js";
|
|
3
|
+
import { logLocalMemoryContextDegraded, logLocalMemoryContextPrepareFailure } from "../local-memory-telemetry.js";
|
|
4
|
+
import { resolveLocalMemoryV2Rollout } from "./rollout.js";
|
|
5
|
+
import { initializeLocalMemoryV2ForWorkspace } from "./runtime.js";
|
|
6
|
+
import { withMemoryAccess } from "./migration-access.js";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
// A fresh Agent may receive the daemon's full ten-wide execution burst. The
|
|
10
|
+
// first turn publishes schema2 durably; the remaining turns must wait to reuse
|
|
11
|
+
// that committed fact instead of timing out on the generic short IO window.
|
|
12
|
+
const EXECUTION_MEMORY_ACCESS_WAIT_MS = 30_000;
|
|
13
|
+
function errorCode(error) {
|
|
14
|
+
const code = error?.code;
|
|
15
|
+
return typeof code === "string" ? code : error instanceof Error ? error.message : undefined;
|
|
16
|
+
}
|
|
17
|
+
function canSafelyDisableLocalMemory(error) {
|
|
18
|
+
if (error instanceof Error && error.name === "RuntimeCancelledError")
|
|
19
|
+
return false;
|
|
20
|
+
const code = errorCode(error);
|
|
21
|
+
if (code === undefined)
|
|
22
|
+
return false;
|
|
23
|
+
if (code === "memory_migration_access_busy"
|
|
24
|
+
|| code === "memory_migration_in_progress"
|
|
25
|
+
|| code === "memory_migration_path_invalid"
|
|
26
|
+
|| code === "memory_migration_process_unknown"
|
|
27
|
+
|| code === "local_memory_v2_initialization_residue_invalid")
|
|
28
|
+
return false;
|
|
29
|
+
return error instanceof LocalMemoryWorkspacePrepareError
|
|
30
|
+
|| code.startsWith("local_memory_v2_initialization_")
|
|
31
|
+
|| code.startsWith("memory_migration_")
|
|
32
|
+
|| code.startsWith("migration_");
|
|
33
|
+
}
|
|
34
|
+
async function prepareWithoutLocalMemory(input, cancellation) {
|
|
35
|
+
const workspace = await awaitWithCancellation(prepareWorkspace({
|
|
36
|
+
agentsRoot: input.launch.agentsRoot, handle: input.handle, cliPath: input.launch.cliPath,
|
|
37
|
+
executionId: input.executionId,
|
|
38
|
+
...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
|
|
39
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
40
|
+
...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
|
|
41
|
+
...(input.sessionContextFingerprint === undefined ? {} : { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
42
|
+
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
43
|
+
skipLocalMemory: true,
|
|
44
|
+
}), cancellation);
|
|
45
|
+
return {
|
|
46
|
+
workspace: {
|
|
47
|
+
...workspace,
|
|
48
|
+
memory: "",
|
|
49
|
+
localMemoryV2Initialized: false,
|
|
50
|
+
localMemoryV2Enabled: false,
|
|
51
|
+
},
|
|
52
|
+
mode: { enabled: false, deferred: true, failure: "inspection_failed" },
|
|
53
|
+
initialized: false,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export async function prepareExecutionMemoryWorkspace(input, isolated, cancellation) {
|
|
57
|
+
try {
|
|
58
|
+
const prepare = async (context) => {
|
|
59
|
+
const prepared = await prepareWorkspace({
|
|
60
|
+
agentsRoot: input.launch.agentsRoot, handle: input.handle, cliPath: input.launch.cliPath,
|
|
61
|
+
executionId: input.executionId,
|
|
62
|
+
...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
|
|
63
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
64
|
+
...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
|
|
65
|
+
...(input.sessionContextFingerprint === undefined ? {} : { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
66
|
+
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
67
|
+
...(isolated ? { skipLocalMemory: true } : {}),
|
|
68
|
+
});
|
|
69
|
+
const workspace = context?.created ? { ...prepared, agentHomePreexisted: false } : prepared;
|
|
70
|
+
const initialMode = await resolveLocalMemoryV2Rollout({ workspace, handle: input.handle, serverUrl: input.launch.serverUrl,
|
|
71
|
+
agentId: input.launch.agentId, requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
|
|
72
|
+
...(input.launch.description ? { description: input.launch.description } : {}) });
|
|
73
|
+
const initializationBinding = input.launch.workspaceId !== undefined && input.launch.machineId !== undefined
|
|
74
|
+
? { workspaceId: input.launch.workspaceId, machineId: input.launch.machineId }
|
|
75
|
+
: undefined;
|
|
76
|
+
const initialized = await initializeLocalMemoryV2ForWorkspace(workspace, initialMode.enabled, input.launch.agentId, initializationBinding);
|
|
77
|
+
const memory = initialized && !workspace.localMemoryV2Initialized
|
|
78
|
+
? await readFile(join(workspace.dir, "MEMORY.md"), "utf8")
|
|
79
|
+
: workspace.memory;
|
|
80
|
+
const currentWorkspace = { ...workspace, memory };
|
|
81
|
+
const mode = initialized && !workspace.localMemoryV2Initialized
|
|
82
|
+
? await resolveLocalMemoryV2Rollout({ workspace: currentWorkspace, handle: input.handle,
|
|
83
|
+
serverUrl: input.launch.serverUrl, agentId: input.launch.agentId,
|
|
84
|
+
requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
|
|
85
|
+
...(input.launch.description ? { description: input.launch.description } : {}) })
|
|
86
|
+
: initialMode;
|
|
87
|
+
return { workspace: { ...currentWorkspace, localMemoryV2Enabled: mode.enabled }, mode, initialized };
|
|
88
|
+
};
|
|
89
|
+
return await awaitWithCancellation(isolated ? prepare()
|
|
90
|
+
: withMemoryAccess(join(input.launch.agentsRoot, input.handle), prepare, {
|
|
91
|
+
create: true,
|
|
92
|
+
waitMs: EXECUTION_MEMORY_ACCESS_WAIT_MS,
|
|
93
|
+
initializedRecoveryIdentity: {
|
|
94
|
+
agentId: input.launch.agentId,
|
|
95
|
+
...(input.launch.workspaceId === undefined ? {} : { workspaceId: input.launch.workspaceId }),
|
|
96
|
+
...(input.launch.machineId === undefined ? {} : { machineId: input.launch.machineId }),
|
|
97
|
+
},
|
|
98
|
+
}), cancellation);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
logLocalMemoryContextPrepareFailure({ executionId: input.executionId, agentHandle: input.handle,
|
|
102
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }) }, "workspace_prepare", error);
|
|
103
|
+
if (!isolated && canSafelyDisableLocalMemory(error)) {
|
|
104
|
+
try {
|
|
105
|
+
const degraded = await prepareWithoutLocalMemory(input, cancellation);
|
|
106
|
+
logLocalMemoryContextDegraded({ executionId: input.executionId, agentHandle: input.handle,
|
|
107
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }) }, error);
|
|
108
|
+
return degraded;
|
|
109
|
+
}
|
|
110
|
+
catch (fallbackError) {
|
|
111
|
+
logLocalMemoryContextPrepareFailure({ executionId: input.executionId, agentHandle: input.handle,
|
|
112
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }) }, "workspace_prepare", fallbackError);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|