@nowcrew/daemon 0.6.98-beta.4 → 0.6.98
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 +1 -34
- package/dist/automatic-service-migration.js +6 -7
- package/dist/cloud-report-upload.js +10 -1
- package/dist/computer-service.js +42 -40
- package/dist/computer-setup-client.js +8 -22
- package/dist/computer-setup-orchestration.js +2 -13
- package/dist/computer-setup.js +6 -36
- package/dist/execution-journal.js +1 -3
- package/dist/execution-protocol.js +1 -1
- package/dist/execution-runner.js +29 -20
- package/dist/external-output.js +12 -1
- package/dist/i18n.js +0 -10
- package/dist/local-execution-prompt.js +3 -8
- package/dist/local-executor.js +52 -69
- package/dist/local-memory/index-budget.js +3 -9
- package/dist/local-memory/inventory-cli.js +8 -52
- package/dist/local-memory/inventory-source.js +8 -15
- package/dist/local-memory/pending-query.js +2 -5
- package/dist/local-memory/pending-schema.js +1 -1
- package/dist/local-memory/pending.js +2 -16
- package/dist/local-memory/prompt.js +5 -21
- package/dist/local-memory/read-cli.js +76 -98
- package/dist/local-memory/rollout.js +11 -79
- package/dist/local-memory/runtime.js +13 -181
- package/dist/local-memory/write.js +21 -189
- package/dist/local-memory-diagnostics.js +13 -94
- package/dist/local-memory-telemetry.js +2 -19
- package/dist/machine-info.js +3 -6
- package/dist/marketplace-controller.js +21 -8
- package/dist/marketplace-maintenance-bridge.js +79 -0
- package/dist/marketplace-maintenance-protocol.js +40 -0
- package/dist/marketplace-protocol.js +1 -1
- package/dist/marketplace-remote.js +1 -1
- package/dist/marketplace-runner.js +1 -1
- package/dist/marketplace-serve.js +4 -2
- package/dist/memory-prune-diagnostics.js +4 -60
- package/dist/message-file-preview.js +1 -11
- package/dist/npm-command.js +5 -5
- package/dist/project-skills/machine-hello-publisher.js +6 -95
- package/dist/prompt.js +2 -6
- package/dist/runner.js +1 -1
- package/dist/runtimes/claude-thread-runner.js +4 -25
- package/dist/runtimes/pi.js +85 -17
- package/dist/serve.js +10 -92
- package/dist/token.js +0 -1
- package/dist/windows-scheduled-task.js +3 -3
- package/dist/workspace-control-handler.js +3 -16
- package/dist/workspace.js +2 -13
- package/package.json +1 -1
- package/dist/computer-token-setup.js +0 -46
- package/dist/local-memory/commit-telemetry.js +0 -30
- package/dist/local-memory/execution-workspace.js +0 -62
- package/dist/local-memory/full-index-search.js +0 -47
- package/dist/local-memory/initialization-identity.js +0 -36
- package/dist/local-memory/inventory-v2.js +0 -362
- package/dist/local-memory/legacy-adapter.js +0 -233
- package/dist/local-memory/migration-access.js +0 -242
- package/dist/local-memory/migration-cli.js +0 -54
- package/dist/local-memory/migration-io.js +0 -199
- package/dist/local-memory/migration-pending.js +0 -9
- package/dist/local-memory/migration-plan.js +0 -432
- package/dist/local-memory/migration-schema.js +0 -55
- package/dist/local-memory/migration-state-invariants.js +0 -65
- package/dist/local-memory/migration-store.js +0 -414
- package/dist/local-memory/migration-tool-entry.js +0 -21
- package/dist/local-memory/source-path.js +0 -13
- package/dist/local-memory/storage-format.js +0 -152
- package/dist/local-memory/writer-mode.js +0 -13
- package/dist/memory-migration-controller.js +0 -89
- package/dist/memory-migration-inspect.js +0 -108
- package/dist/memory-migration-journal.js +0 -14
- package/dist/memory-migration-protocol.js +0 -14
- package/dist/memory-migration-runtime.js +0 -305
- package/dist/powershell-command.js +0 -12
- package/dist/windows-task-principal.js +0 -26
package/dist/runtimes/pi.js
CHANGED
|
@@ -1,17 +1,85 @@
|
|
|
1
|
-
export function buildPiArgs(options) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
export function buildPiArgs(options) {
|
|
2
|
+
return ["--mode", "json", "--print", "--no-session", "--system-prompt", options.systemPrompt,
|
|
3
|
+
...(options.model ? ["--model", options.model] : []),
|
|
4
|
+
...(options.reasoning && options.reasoning !== "default" ? ["--thinking", options.reasoning] : [])];
|
|
5
|
+
}
|
|
6
|
+
// 保留稳定的原因标识供 server 本地化;不要用 token 数量猜测结束原因。
|
|
7
|
+
function failureReason(message) {
|
|
8
|
+
const reason = message?.stopReason;
|
|
9
|
+
return reason === "stop" || reason === "toolUse" ? null : `pi_runtime_failed: ${reason ?? "incomplete"}`;
|
|
10
|
+
}
|
|
11
|
+
export function createPiEventDecoder() {
|
|
12
|
+
let sessionId = null;
|
|
13
|
+
let finalText = "";
|
|
14
|
+
let error = null;
|
|
15
|
+
let lastAssistant = null;
|
|
16
|
+
let assistantOpen = false;
|
|
17
|
+
let sawTurnEnd = false;
|
|
18
|
+
let usage;
|
|
19
|
+
return {
|
|
20
|
+
push(raw) {
|
|
21
|
+
const e = (raw ?? {});
|
|
22
|
+
const out = [];
|
|
23
|
+
if (e.type === "session" && typeof e.id === "string") {
|
|
24
|
+
sessionId = e.id;
|
|
25
|
+
out.push({ type: "thread.started", thread_id: e.id });
|
|
26
|
+
}
|
|
27
|
+
if (e.type === "turn_start")
|
|
28
|
+
sawTurnEnd = false;
|
|
29
|
+
if ((e.type === "message_start" || e.type === "message_update") && e.message?.role === "assistant") {
|
|
30
|
+
assistantOpen = true;
|
|
31
|
+
sawTurnEnd = false;
|
|
32
|
+
}
|
|
33
|
+
const ae = e.assistantMessageEvent;
|
|
34
|
+
if (e.type === "message_update" && ae?.type === "text_delta" && typeof ae.delta === "string") {
|
|
35
|
+
finalText += ae.delta;
|
|
36
|
+
out.push({ type: "pi.text_delta", text: ae.delta });
|
|
37
|
+
}
|
|
38
|
+
if (e.type === "message_update" && ae?.type === "thinking_delta" && typeof ae.delta === "string") {
|
|
39
|
+
out.push({ type: "pi.thinking_delta", text: ae.delta });
|
|
40
|
+
}
|
|
41
|
+
if (e.type === "message_update" && typeof ae?.type === "string" && /tool(call|_call)/iu.test(ae.type)) {
|
|
42
|
+
out.push({ type: "pi.tool_call", ...(ae.name ? { title: ae.name } : {}) });
|
|
43
|
+
}
|
|
44
|
+
if (e.type === "message_end" && e.message?.role === "assistant") {
|
|
45
|
+
lastAssistant = e.message;
|
|
46
|
+
usage = e.message.usage;
|
|
47
|
+
assistantOpen = false;
|
|
48
|
+
sawTurnEnd = false;
|
|
49
|
+
}
|
|
50
|
+
if (e.type === "turn_end") {
|
|
51
|
+
// 原生 turn_end 自带本轮消息,不能把工具调用轮的结束当成整次执行成功。
|
|
52
|
+
if (e.message?.role === "assistant") {
|
|
53
|
+
lastAssistant = e.message;
|
|
54
|
+
usage = e.message.usage;
|
|
55
|
+
assistantOpen = false;
|
|
56
|
+
}
|
|
57
|
+
else if (e.message) {
|
|
58
|
+
lastAssistant = null;
|
|
59
|
+
}
|
|
60
|
+
sawTurnEnd = true;
|
|
61
|
+
const normalizedUsage = usage ? { usage: {
|
|
62
|
+
input_tokens: usage.input ?? 0, output_tokens: usage.output ?? 0,
|
|
63
|
+
cache_read_input_tokens: usage.cacheRead ?? 0, cache_creation_input_tokens: usage.cacheWrite ?? 0,
|
|
64
|
+
} } : {};
|
|
65
|
+
const failure = failureReason(lastAssistant);
|
|
66
|
+
out.push(failure
|
|
67
|
+
? { type: "result", is_error: true, result: failure, ...normalizedUsage }
|
|
68
|
+
: { type: "turn.completed", ...normalizedUsage });
|
|
69
|
+
}
|
|
70
|
+
if (e.type === "error" || e.type === "agent_error") {
|
|
71
|
+
error = typeof e.error === "string" ? e.error : (e.error?.message ?? "Pi error");
|
|
72
|
+
out.push({ type: "pi.error", message: error });
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
},
|
|
76
|
+
finish() {
|
|
77
|
+
// 正常 stop 可为空(任务可能要求静默);length/error/aborted 必须明确失败。
|
|
78
|
+
const failure = error ?? (assistantOpen
|
|
79
|
+
? "pi_runtime_failed: incomplete"
|
|
80
|
+
: failureReason(lastAssistant)
|
|
81
|
+
?? (!sawTurnEnd || lastAssistant?.stopReason === "toolUse" ? "pi_runtime_failed: incomplete" : null));
|
|
82
|
+
return { ok: failure === null, ...(failure ? { error: failure } : {}), finalText, sessionId, usage };
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
package/dist/serve.js
CHANGED
|
@@ -9,12 +9,11 @@ import { randomUUID } from "node:crypto";
|
|
|
9
9
|
import { dslog, setSlogDefaults, drainSpool, flushSlog } from "./slog.js";
|
|
10
10
|
import { mergeRunAgentResults, reportScheduledStartFailure, runAgent } from "./runner.js";
|
|
11
11
|
import { buildOriginDecisionRetryPrompt, buildScheduledPrompt } from "./prompt.js";
|
|
12
|
-
import { daemonCapabilities, daemonCapabilityBindings,
|
|
12
|
+
import { daemonCapabilities, daemonCapabilityBindings, } from "./machine-info.js";
|
|
13
13
|
import { reconcileExecutionJournal } from "./execution-recovery.js";
|
|
14
14
|
import { initReleaseSlog, reportDaemonConnectionClose, reportReleaseError } from "./release-channel-guard.js";
|
|
15
15
|
import { handleWorkspaceControlRequest } from "./workspace-control-handler.js";
|
|
16
16
|
import { inspectRaftWorkspace, importRaftWorkspace } from "./workspace-import.js";
|
|
17
|
-
import { withMemoryAccess } from "./local-memory/migration-access.js";
|
|
18
17
|
import { normalizeScheduledContext } from "./scheduled-report.js";
|
|
19
18
|
import { formatDaemonLogLine } from "./log-format.js";
|
|
20
19
|
import { reportAgentRunComplete } from "./scheduled-run-report.js";
|
|
@@ -51,8 +50,6 @@ import { probeRuntimeHealth } from "./runtime-health.js";
|
|
|
51
50
|
import { createServeMarketplace } from "./marketplace-serve.js";
|
|
52
51
|
import { buildControlPlaneUrl } from "./control-plane-url.js";
|
|
53
52
|
import { resolveDaemonLocalStateRootFromEnv } from "./daemon-local-home.js";
|
|
54
|
-
import { createMemoryMigrationController } from "./memory-migration-controller.js";
|
|
55
|
-
import { createMemoryMigrationJournal, replayExecutionJournals } from "./memory-migration-journal.js";
|
|
56
53
|
import { bindStorageServerIdentity, createStorageIdentityAdmission, } from "./storage-serve-adapter.js";
|
|
57
54
|
export { buildControlPlaneUrl } from "./control-plane-url.js";
|
|
58
55
|
// normalize.ts 的活动种类 → activity 枚举
|
|
@@ -68,18 +65,12 @@ export function serve(config, opts = {}) {
|
|
|
68
65
|
let serverCapabilities = new Set();
|
|
69
66
|
let backoff = 1000;
|
|
70
67
|
const maxBackoff = opts.maxBackoffMs ?? 30_000;
|
|
71
|
-
// hello 重试跑满仍未 ack 时主动断连重连(破 server 侧连接归属/fence 死锁)。收到 ack 清零;
|
|
72
|
-
// 连续多次仍拿不到 ack 则停手,退回 connected-offline,避免事故期把控制面打成重连风暴。
|
|
73
|
-
const maxUnackedHelloReconnects = 3;
|
|
74
|
-
let unackedHelloReconnects = 0;
|
|
75
68
|
const testShutdown = readTestShutdownConfiguration(process.env);
|
|
76
69
|
const shutdownTimeoutMs = opts.shutdownTimeoutMs ?? testShutdown.timeoutMs ?? 30_000;
|
|
77
70
|
const createWebSocket = opts.createWebSocket ?? ((url) => new WebSocket(url));
|
|
78
71
|
let reconnectTimer = null;
|
|
79
72
|
let stopPromise = null;
|
|
80
73
|
let executionJournal;
|
|
81
|
-
let migrationExecutionJournal;
|
|
82
|
-
let migrationJournalReady = false;
|
|
83
74
|
const injectedExecutionJournal = opts.execution?.journal;
|
|
84
75
|
const agentMemory = opts.execution?.dependencies?.agentMemory
|
|
85
76
|
?? (config.agentMemory === null ? undefined : createAgentMemoryBridge(config.agentMemory));
|
|
@@ -94,15 +85,6 @@ export function serve(config, opts = {}) {
|
|
|
94
85
|
startupGapMs: config.executionLimits.startupGapMs,
|
|
95
86
|
});
|
|
96
87
|
const localSlots = createSharedSlotManager(config.executionLimits);
|
|
97
|
-
const memoryMigrations = createMemoryMigrationController({ config, coordinator: hostCoordinator,
|
|
98
|
-
isAdmissionClosed: () => stopped || storageIdentityAdmission.isAdmissionClosed(),
|
|
99
|
-
journal: () => { if (!migrationJournalReady)
|
|
100
|
-
throw new Error("memory_migration_journal_unavailable"); return migrationExecutionJournal; }, send: frame => {
|
|
101
|
-
if (frame.type === "execution:completed")
|
|
102
|
-
completionRetransmitter.track(frame);
|
|
103
|
-
else if (ws?.readyState === WebSocket.OPEN)
|
|
104
|
-
ws.send(JSON.stringify(frame));
|
|
105
|
-
} });
|
|
106
88
|
const sharedSlots = hostCoordinatedSlotManager(localSlots, hostCoordinator);
|
|
107
89
|
const concurrencyTelemetry = createExecutionConcurrencyTelemetry(sharedSlots, {
|
|
108
90
|
...(opts.execution?.concurrencySnapshotIntervalMs === undefined
|
|
@@ -136,7 +118,7 @@ export function serve(config, opts = {}) {
|
|
|
136
118
|
catch { /* reconnect/timeout reconciliation handles a lost status frame */ }
|
|
137
119
|
},
|
|
138
120
|
});
|
|
139
|
-
const marketplace = createServeMarketplace(config, localSlots, hostCoordinator);
|
|
121
|
+
const marketplace = createServeMarketplace(config, localSlots, hostCoordinator, async () => ({ ...(await machineRuntime.provider.acquire()).env }));
|
|
140
122
|
const storageIdentityAdmission = createStorageIdentityAdmission(opts.storageRuntime);
|
|
141
123
|
const projectionCoordinator = createAgentProjectionCoordinator();
|
|
142
124
|
const { projectRegistry, projectWorkspaceRegistry, projectDependencyProvisioner } = createProjectRegistryWiring(config.agentsRoot, opts.execution?.dependencies);
|
|
@@ -178,41 +160,7 @@ export function serve(config, opts = {}) {
|
|
|
178
160
|
: configuredIdentity;
|
|
179
161
|
return currentIdentity === undefined ? hello : { ...hello, ...currentIdentity };
|
|
180
162
|
},
|
|
181
|
-
onSent: (hello
|
|
182
|
-
attempt, hostname: hello.hostname, daemon_version: hello.daemonVersion,
|
|
183
|
-
}),
|
|
184
|
-
onSendFailed: (hello, attempt, error) => dslog("daemon.machine_hello_send_failed", "机器 hello 发送失败", {
|
|
185
|
-
level: "WARN", attempt, hostname: hello.hostname, daemon_version: hello.daemonVersion,
|
|
186
|
-
error_message: error instanceof Error ? error.message : String(error),
|
|
187
|
-
}),
|
|
188
|
-
onAck: (hello) => {
|
|
189
|
-
unackedHelloReconnects = 0; // 拿到确认 = 本连接登记成功,清零强制重连计数。
|
|
190
|
-
dslog("daemon.machine_hello_ack_received", "机器 hello 已收到控制面确认", {
|
|
191
|
-
hostname: hello.hostname, daemon_version: hello.daemonVersion,
|
|
192
|
-
});
|
|
193
|
-
},
|
|
194
|
-
// 仅当当前 server 声明支持 ack 才重试;老 server 收不到 ack,重试无意义(退回单次上报)。
|
|
195
|
-
ackSupported: () => serverCapabilities.has(MACHINE_HELLO_ACK_CAPABILITY),
|
|
196
|
-
// 重试跑满仍未 ack → 断开当前连接,靠重连换新连接(新 epoch/token)破 server 侧 fence 死锁。
|
|
197
|
-
onExhausted: (socket) => {
|
|
198
|
-
if (stopped || ws !== socket || socket.readyState !== WebSocket.OPEN)
|
|
199
|
-
return;
|
|
200
|
-
if (unackedHelloReconnects >= maxUnackedHelloReconnects) {
|
|
201
|
-
dslog("daemon.machine_hello_unacked_giveup", "机器 hello 连续多次重连仍未确认,停止强制重连(保持连接,等待下次事件或人工介入)", {
|
|
202
|
-
level: "ERROR", reconnects: unackedHelloReconnects,
|
|
203
|
-
});
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
unackedHelloReconnects += 1;
|
|
207
|
-
// 抖动重连间隔:控制面回滚时多台 daemon 会同时耗尽重试,固定间隔会同步重连造成羊群。
|
|
208
|
-
// close handler 用当前 backoff 排重连,这里注入 1~4s 随机值把各机错峰(open 会再把它复位)。
|
|
209
|
-
const jitteredBackoff = 1_000 + Math.floor(Math.random() * 3_000);
|
|
210
|
-
backoff = Math.min(jitteredBackoff, maxBackoff);
|
|
211
|
-
dslog("daemon.machine_hello_unacked_reconnect", "机器 hello 重试跑满仍未确认,断开重连换新连接", {
|
|
212
|
-
level: "WARN", reconnects: unackedHelloReconnects, backoff_ms: backoff,
|
|
213
|
-
});
|
|
214
|
-
socket.close(1011, "machine hello unacknowledged");
|
|
215
|
-
},
|
|
163
|
+
onSent: (hello) => log(`📤 已上报机器信息: ${hello.hostname} · ${hello.os} · installed=[${hello.runtimes.join(",")}] · executable=[${hello.executionRuntimes.join(",")}] · agents=[${hello.agentHandles.join(",")}]`),
|
|
216
164
|
});
|
|
217
165
|
const machineRuntime = createMachineRuntimeEnvironment({
|
|
218
166
|
config,
|
|
@@ -284,7 +232,7 @@ export function serve(config, opts = {}) {
|
|
|
284
232
|
return null;
|
|
285
233
|
};
|
|
286
234
|
const sendSnapshot = async (reqId) => {
|
|
287
|
-
const entries = (await
|
|
235
|
+
const entries = (await executionJournal.replay()).map(snapshotEntry).filter((entry) => entry !== null);
|
|
288
236
|
safeExecutionSend(ExecutionSnapshotSchema.parse({
|
|
289
237
|
type: "execution:snapshot", protocolVersion: 1, reqId, entries,
|
|
290
238
|
}));
|
|
@@ -362,16 +310,9 @@ export function serve(config, opts = {}) {
|
|
|
362
310
|
// 连上了才有机会把离线期间(断连原因/退出前)落盘的日志补传上去
|
|
363
311
|
void drainSpool();
|
|
364
312
|
// 上报本机信息 (hostname/os/daemon 版本/已装 runtimes)
|
|
365
|
-
machineHelloPublisher.attach(openedSocket);
|
|
366
313
|
machineRuntime.open(openedSocket, { capabilities: capabilities.machineHello, beforePublish: Promise.resolve(), connectionId });
|
|
367
314
|
opts.onOpen?.(ws);
|
|
368
315
|
void sendSnapshot(`reconnect-${randomUUID()}`);
|
|
369
|
-
// 普通回执不等待维护日志IO;两类记录分别重放到同一发送器。
|
|
370
|
-
void migrationExecutionJournal.replay().then(entries => {
|
|
371
|
-
for (const entry of entries)
|
|
372
|
-
if (entry.completion && !entry.completionAcknowledged)
|
|
373
|
-
completionRetransmitter.track(entry.completion);
|
|
374
|
-
}).catch(() => dslog("memory_migration.journal_unavailable", "维护回执重放失败,普通回执继续", { level: "ERROR" }));
|
|
375
316
|
void executionJournal.replay()
|
|
376
317
|
.then((entries) => {
|
|
377
318
|
for (const entry of entries) {
|
|
@@ -411,11 +352,6 @@ export function serve(config, opts = {}) {
|
|
|
411
352
|
if (typeof decoded !== "object" || decoded === null)
|
|
412
353
|
return;
|
|
413
354
|
const rawType = "type" in decoded && typeof decoded.type === "string" ? decoded.type : "";
|
|
414
|
-
if (rawType === "machine:hello_ack") {
|
|
415
|
-
const ackSeq = "helloSeq" in decoded && typeof decoded.helloSeq === "number" ? decoded.helloSeq : undefined;
|
|
416
|
-
machineHelloPublisher.acknowledge(connectionSocket, ackSeq);
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
355
|
if (rawType === "machine:environment:get" || rawType === "machine:environment:refresh") {
|
|
420
356
|
await handleMachineEnvironmentFrame(decoded, machineRuntime.provider, sendToConnection);
|
|
421
357
|
return;
|
|
@@ -451,8 +387,7 @@ export function serve(config, opts = {}) {
|
|
|
451
387
|
return;
|
|
452
388
|
if (frame.type === "execution:completion-ack") {
|
|
453
389
|
try {
|
|
454
|
-
|
|
455
|
-
await journal.acknowledgeCompletion(frame.executionId);
|
|
390
|
+
await executionJournal.acknowledgeCompletion(frame.executionId);
|
|
456
391
|
const attempts = completionRetransmitter.acknowledge(frame.executionId);
|
|
457
392
|
dslog("execution.completion_acknowledged", "execution completion ACK 已持久化", {
|
|
458
393
|
execution_id: frame.executionId,
|
|
@@ -478,8 +413,6 @@ export function serve(config, opts = {}) {
|
|
|
478
413
|
return;
|
|
479
414
|
}
|
|
480
415
|
if (frame.type === "execution:cancel") {
|
|
481
|
-
if (memoryMigrations.cancel(frame.executionId))
|
|
482
|
-
return;
|
|
483
416
|
if (!knownExecutionHashes.has(frame.executionId)
|
|
484
417
|
&& !executionRuns.has(frame.executionId)
|
|
485
418
|
&& await executionJournal.get(frame.executionId) === null)
|
|
@@ -712,7 +645,6 @@ export function serve(config, opts = {}) {
|
|
|
712
645
|
const execution = executeProtocol(config, spec, {
|
|
713
646
|
...opts.execution?.dependencies,
|
|
714
647
|
machineEnvironment: machineRuntime.provider,
|
|
715
|
-
...(memoryMigrations.getIdentity() === null ? {} : { controlIdentity: memoryMigrations.getIdentity() }),
|
|
716
648
|
capabilities: capabilities.executionRunner,
|
|
717
649
|
projectSkills: opts.execution?.dependencies?.projectSkills ?? initializedProjectSkills,
|
|
718
650
|
abilityRelease: opts.execution?.dependencies?.abilityRelease ?? agentAbilityRuntime.materializer,
|
|
@@ -803,13 +735,6 @@ export function serve(config, opts = {}) {
|
|
|
803
735
|
// ready 帧带 server 视角的 machineId/workspaceId → 作为后续所有日志的默认关联键
|
|
804
736
|
const r = msg;
|
|
805
737
|
setSlogDefaults({ machine_id: r.machineId, workspace_id: r.workspaceId });
|
|
806
|
-
if (r.workspaceId && r.machineId)
|
|
807
|
-
memoryMigrations.setIdentity({ workspaceId: r.workspaceId, machineId: r.machineId });
|
|
808
|
-
// 旧 server 无此字段 → 空集合(daemon 保持全部旧行为)。ackSupported() 依赖它判断是否重试,
|
|
809
|
-
// 必须在任何 republish() 之前就位;否则本轮 republish 看到空集合→不排重试→整套 ack/重连机制哑火。
|
|
810
|
-
serverCapabilities = new Set(Array.isArray(r.serverCapabilities)
|
|
811
|
-
? r.serverCapabilities.filter((c) => typeof c === "string")
|
|
812
|
-
: []);
|
|
813
738
|
if (opts.storageRuntime !== undefined && typeof r.workspaceId === "string" && typeof r.machineId === "string") {
|
|
814
739
|
const bindingSocket = ws;
|
|
815
740
|
bindStorageServerIdentity(opts.storageRuntime, { workspaceId: r.workspaceId, machineId: r.machineId }, {
|
|
@@ -826,7 +751,10 @@ export function serve(config, opts = {}) {
|
|
|
826
751
|
},
|
|
827
752
|
});
|
|
828
753
|
}
|
|
829
|
-
|
|
754
|
+
// 旧 server 无此字段 → 空集合(daemon 保持全部旧行为)。
|
|
755
|
+
serverCapabilities = new Set(Array.isArray(r.serverCapabilities)
|
|
756
|
+
? r.serverCapabilities.filter((c) => typeof c === "string")
|
|
757
|
+
: []);
|
|
830
758
|
if (serverCapabilities.has(PROJECT_SKILLS_CAPABILITY)) {
|
|
831
759
|
void projectSkillsController.initialize()
|
|
832
760
|
.then(() => projectSkillsController.publishCurrent())
|
|
@@ -873,8 +801,6 @@ export function serve(config, opts = {}) {
|
|
|
873
801
|
}
|
|
874
802
|
catch { /* server 会按请求超时处理 */ } }))
|
|
875
803
|
return;
|
|
876
|
-
if (await memoryMigrations.handle(msg))
|
|
877
|
-
return;
|
|
878
804
|
if (await agentAbilityRuntime.tryHandleControlMessage(msg, serverCapabilities, (frame) => ws?.send(JSON.stringify(frame))))
|
|
879
805
|
return;
|
|
880
806
|
// 导入 raft agent 工作区:inspect 反填 name/description;import 复制用户内容
|
|
@@ -889,7 +815,7 @@ export function serve(config, opts = {}) {
|
|
|
889
815
|
try {
|
|
890
816
|
const data2 = req.type === "raft:inspect"
|
|
891
817
|
? await inspectRaftWorkspace(req.path)
|
|
892
|
-
: await
|
|
818
|
+
: await importRaftWorkspace(req.path, join(config.agentsRoot, req.handle));
|
|
893
819
|
if (req.type === "raft:import") {
|
|
894
820
|
log(`📦 已导入 raft 工作区 → ${req.handle}: 复制 ${data2.copied.length} 项`);
|
|
895
821
|
}
|
|
@@ -1277,12 +1203,10 @@ export function serve(config, opts = {}) {
|
|
|
1277
1203
|
});
|
|
1278
1204
|
connectionSocket.on("close", (code) => {
|
|
1279
1205
|
machineRuntime.close(connectionSocket);
|
|
1280
|
-
machineHelloPublisher.detach(connectionSocket);
|
|
1281
1206
|
if (stopped || ws !== connectionSocket)
|
|
1282
1207
|
return;
|
|
1283
1208
|
// server 能力随连接失效;下个连接的 ready 帧重新声明(防降级重连后沿用过期能力)。
|
|
1284
1209
|
serverCapabilities = new Set();
|
|
1285
|
-
memoryMigrations.clearIdentity();
|
|
1286
1210
|
completionRetransmitter.pause();
|
|
1287
1211
|
// 4001 = 控制面应用级「鉴权失败」关闭码(见 server control-plane.ts)。即使上面的
|
|
1288
1212
|
// error 帧因 close 抢先而丢失,也能据关闭码识别这是凭证失效——退避拉满,不再每秒热循环。
|
|
@@ -1335,9 +1259,6 @@ export function serve(config, opts = {}) {
|
|
|
1335
1259
|
writeStderr: (line) => process.stderr.write(line),
|
|
1336
1260
|
});
|
|
1337
1261
|
await runProjectSkillStartupCleanup(config.agentsRoot, executionJournal, dslog);
|
|
1338
|
-
migrationExecutionJournal = createMemoryMigrationJournal(config.agentsRoot);
|
|
1339
|
-
await migrationExecutionJournal.reconcileAfterRestart().then(() => { migrationJournalReady = true; })
|
|
1340
|
-
.catch(() => dslog("memory_migration.journal_unavailable", "迁移日志恢复失败,普通执行继续,迁移请求单独报错", { level: "ERROR" }));
|
|
1341
1262
|
await connect();
|
|
1342
1263
|
})();
|
|
1343
1264
|
const stop = () => {
|
|
@@ -1355,7 +1276,6 @@ export function serve(config, opts = {}) {
|
|
|
1355
1276
|
const webSocketClosed = closeWebSocketWithinDeadline(ws, deadline.signal);
|
|
1356
1277
|
const pending = [
|
|
1357
1278
|
machineRuntime.stop(),
|
|
1358
|
-
memoryMigrations.stop(),
|
|
1359
1279
|
webSocketClosed,
|
|
1360
1280
|
updateController.drain(),
|
|
1361
1281
|
marketplace.stop(),
|
|
@@ -1374,8 +1294,6 @@ export function serve(config, opts = {}) {
|
|
|
1374
1294
|
if (executionJournal !== undefined) {
|
|
1375
1295
|
await executionJournal.close({ signal: deadline.signal });
|
|
1376
1296
|
}
|
|
1377
|
-
if (migrationExecutionJournal !== undefined)
|
|
1378
|
-
await migrationExecutionJournal.close({ signal: deadline.signal });
|
|
1379
1297
|
}
|
|
1380
1298
|
finally {
|
|
1381
1299
|
deadline.dispose();
|
package/dist/token.js
CHANGED
|
@@ -7,7 +7,6 @@ export async function mintAgentToken(serverUrl, machineToken, handle, displayNam
|
|
|
7
7
|
},
|
|
8
8
|
// 把本轮唤醒的线程根钉到 per-launch 令牌:服务端据此让 task/消息默认绑/回当前线程。
|
|
9
9
|
body: JSON.stringify({
|
|
10
|
-
memoryStateGuardVersion: 1,
|
|
11
10
|
handle,
|
|
12
11
|
...(displayName ? { displayName } : {}),
|
|
13
12
|
...(options.wakeThreadRoot ? { wakeThreadRoot: options.wakeThreadRoot } : {}),
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { systemCommandRunner, windowsCommandArg, } from "./computer-service.js";
|
|
2
2
|
import { win32 } from "node:path";
|
|
3
|
-
import { powershellCommandArgs } from "./powershell-command.js";
|
|
4
3
|
function encoded(value) {
|
|
5
4
|
return Buffer.from(value, "utf16le").toString("base64");
|
|
6
5
|
}
|
|
@@ -34,9 +33,10 @@ export async function inspectWindowsServiceUpdateScope(spec, npmPrefix, daemonPi
|
|
|
34
33
|
"$enginePid=if($instances.Count -eq 1){[int64]$instances[0].EnginePID}else{0};",
|
|
35
34
|
"[pscustomobject]@{count=1;state=[int]$task.State;execute=if($actions.Count -eq 1){$actions[0].Execute}else{$null};arguments=if($actions.Count -eq 1){$actions[0].Arguments}else{$null};instanceCount=$instances.Count;enginePid=$enginePid;engineOwned=($enginePid -eq $pidValue -or $ancestors -contains $enginePid);processIdentity=$processIdentity;conflictingPrefixes=$conflicts.Count}|ConvertTo-Json -Compress;",
|
|
36
35
|
].join("");
|
|
37
|
-
const result = await runner("powershell.exe",
|
|
36
|
+
const result = await runner("powershell.exe", [
|
|
37
|
+
"-NoProfile", "-NonInteractive", "-Command", script,
|
|
38
38
|
encoded(spec.id), encoded(entryMarker), String(daemonPid),
|
|
39
|
-
])
|
|
39
|
+
]);
|
|
40
40
|
if (result.exitCode !== 0)
|
|
41
41
|
return { valid: false };
|
|
42
42
|
let inspection;
|
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
/** 控制面文件/技能查看的按需处理,独立于执行生命周期。 */
|
|
2
|
-
import {
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
2
|
+
import { join } from "node:path";
|
|
4
3
|
import { readSharedMessageFile } from "./message-file-preview.js";
|
|
5
4
|
import { listWorkspace, readWorkspaceFile } from "./workspace-fs.js";
|
|
6
5
|
import { listSkills } from "./skills.js";
|
|
7
6
|
import { listRuntimeModels } from "./list-models.js";
|
|
8
|
-
import { withMemoryAccess } from "./local-memory/migration-access.js";
|
|
9
|
-
async function listProtectedWorkspace(root, path) {
|
|
10
|
-
try {
|
|
11
|
-
await lstat(root);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
if (error.code !== "ENOENT")
|
|
15
|
-
throw error;
|
|
16
|
-
return { root: resolve(root), path: path.replace(/^\/+/, ""), entries: [] };
|
|
17
|
-
}
|
|
18
|
-
return withMemoryAccess(root, () => listWorkspace(root, path));
|
|
19
|
-
}
|
|
20
7
|
export async function handleWorkspaceControlRequest(raw, agentsRoot, registry, models = listRuntimeModels) {
|
|
21
8
|
if (!raw || typeof raw !== "object")
|
|
22
9
|
return null;
|
|
@@ -28,8 +15,8 @@ export async function handleWorkspaceControlRequest(raw, agentsRoot, registry, m
|
|
|
28
15
|
try {
|
|
29
16
|
const root = join(agentsRoot, request.handle);
|
|
30
17
|
const data = request.type === "fs:read-shared" ? await readSharedMessageFile(agentsRoot, raw, registry)
|
|
31
|
-
: request.type === "fs:list" ? await
|
|
32
|
-
: request.type === "fs:read" ? await
|
|
18
|
+
: request.type === "fs:list" ? await listWorkspace(root, request.path)
|
|
19
|
+
: request.type === "fs:read" ? await readWorkspaceFile(root, request.path)
|
|
33
20
|
: request.type === "skills:list" ? await listSkills(request.runtime)
|
|
34
21
|
: { models: await models(request.runtime ?? "") };
|
|
35
22
|
return { type: "fs:result", reqId: request.reqId, ok: true, data };
|
package/dist/workspace.js
CHANGED
|
@@ -8,15 +8,12 @@
|
|
|
8
8
|
*
|
|
9
9
|
* spawn runtime 时把 <ws>/.crew 置于 PATH 最前,于是 agent 的 `crew ...` 命中 wrapper。
|
|
10
10
|
*/
|
|
11
|
-
import { mkdir, writeFile, readFile, chmod, access, lstat
|
|
11
|
+
import { mkdir, writeFile, readFile, chmod, access, lstat } from "node:fs/promises";
|
|
12
12
|
import { createHash, randomUUID } from "node:crypto";
|
|
13
13
|
import { dirname, join } from "node:path";
|
|
14
14
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
15
15
|
import { createRequire } from "node:module";
|
|
16
16
|
import { dslog } from "./slog.js";
|
|
17
|
-
import { MigrationStateSchema } from "./local-memory/migration-schema.js";
|
|
18
|
-
import { assertMigrationStateIntegrity } from "./local-memory/migration-state-invariants.js";
|
|
19
|
-
import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
|
|
20
17
|
/** 文件系统安全的 taskKey:仅留 [\w.-],其余转 _,截断,避免路径穿越/超长。 */
|
|
21
18
|
export function safeKey(key) {
|
|
22
19
|
return key.replace(/[^\w.-]+/g, "_").replace(/^[-.]+/, "").slice(0, 80) || "default";
|
|
@@ -52,15 +49,7 @@ async function hasLocalMemoryV2Marker(agentDir) {
|
|
|
52
49
|
const stat = await lstat(markerPath);
|
|
53
50
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
54
51
|
return false;
|
|
55
|
-
|
|
56
|
-
return false;
|
|
57
|
-
const root = await realpath(agentDir);
|
|
58
|
-
const state = MigrationStateSchema.parse(JSON.parse(await readFile(join(memoryDir, "migration.v1.json"), "utf8")));
|
|
59
|
-
assertMigrationStateIntegrity(state, state.identity);
|
|
60
|
-
return state.phase === "committed" && state.storageVersion === 2
|
|
61
|
-
&& state.identity.rootFingerprint === createHash("sha256").update(root).digest("hex")
|
|
62
|
-
&& state.identity.ownerIdentity === String((await lstat(root)).uid)
|
|
63
|
-
&& detectLocalMemoryStorageVersion(await readFile(join(root, "MEMORY.md"), "utf8")) === 2;
|
|
52
|
+
return (await readFile(markerPath, "utf8")) === "1\n";
|
|
64
53
|
}
|
|
65
54
|
catch {
|
|
66
55
|
return false;
|
package/package.json
CHANGED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { assertBootstrapMatches, localPathsMatch } from "./computer-setup-orchestration.js";
|
|
2
|
-
import { redactSetupSecrets } from "./computer-setup-client.js";
|
|
3
|
-
export async function runMachineTokenSetup(input, deps, machineToken) {
|
|
4
|
-
try {
|
|
5
|
-
deps.reportPairing("Checking computer connection information...");
|
|
6
|
-
const target = await deps.client.tokenTarget(machineToken);
|
|
7
|
-
assertBootstrapMatches(target, input);
|
|
8
|
-
deps.reportPairing("Downloading, installing, and starting the Daemon service...");
|
|
9
|
-
const installation = await deps.installAutomatically({
|
|
10
|
-
serverUrl: target.serverUrl, machineToken, workspaceId: target.workspaceId, machineId: target.machineId,
|
|
11
|
-
requestedProfile: target.profile,
|
|
12
|
-
...(target.releaseTag === undefined ? {} : { requestedReleaseTag: target.releaseTag }),
|
|
13
|
-
...(target.registryUrl === undefined ? {} : { requestedRegistryUrl: target.registryUrl }),
|
|
14
|
-
verifyAfterStart: async (candidate) => {
|
|
15
|
-
deps.reportPairing("Confirming the computer connection...");
|
|
16
|
-
const deadline = deps.now() + 120_000;
|
|
17
|
-
for (;;) {
|
|
18
|
-
const current = await deps.client.tokenTarget(machineToken);
|
|
19
|
-
assertBootstrapMatches(current, input);
|
|
20
|
-
const connection = current.connection;
|
|
21
|
-
const platform = deps.platform ?? process.platform;
|
|
22
|
-
if (connection.status === "online" && connection.epoch > target.minimumConnectionEpoch
|
|
23
|
-
&& connection.credentialMatchesConnection && current.environment === target.environment
|
|
24
|
-
&& connection.profile === candidate.profile
|
|
25
|
-
&& connection.daemonHome !== null && localPathsMatch(connection.daemonHome, candidate.daemonHome, platform)
|
|
26
|
-
&& connection.agentsRoot !== null && localPathsMatch(connection.agentsRoot, candidate.agentsRoot, platform)
|
|
27
|
-
&& (target.storageId === undefined || connection.storageId === target.storageId))
|
|
28
|
-
return;
|
|
29
|
-
if (deps.now() >= deadline)
|
|
30
|
-
throw new Error("Timed out confirming the new computer connection");
|
|
31
|
-
await deps.sleep(Math.min(2_000, Math.max(0, deadline - deps.now())));
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
return {
|
|
36
|
-
workspaceId: target.workspaceId, workspaceSlug: target.workspaceSlug, machineId: target.machineId,
|
|
37
|
-
environment: target.environment, profile: installation.profile, daemonVersion: installation.version,
|
|
38
|
-
serviceId: installation.serviceId, serviceStatus: "running", helloConfirmed: true,
|
|
39
|
-
localNowworkHome: installation.localHome, daemonHome: installation.daemonHome, agentsRoot: installation.agentsRoot,
|
|
40
|
-
...(target.storageId === undefined ? {} : { storageId: target.storageId }),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
throw new Error(redactSetupSecrets(error instanceof Error ? error.message : String(error), [machineToken]));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { prepareWorkspace } from "../workspace.js";
|
|
2
|
-
import { awaitWithCancellation } from "../runtime-cancellation.js";
|
|
3
|
-
import { 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
|
-
export async function prepareExecutionMemoryWorkspace(input, isolated, cancellation) {
|
|
14
|
-
try {
|
|
15
|
-
const prepare = async (context) => {
|
|
16
|
-
const prepared = await prepareWorkspace({
|
|
17
|
-
agentsRoot: input.launch.agentsRoot, handle: input.handle, cliPath: input.launch.cliPath,
|
|
18
|
-
executionId: input.executionId,
|
|
19
|
-
...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
|
|
20
|
-
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
21
|
-
...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
|
|
22
|
-
...(input.sessionContextFingerprint === undefined ? {} : { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
23
|
-
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
24
|
-
...(isolated ? { skipLocalMemory: true } : {}),
|
|
25
|
-
});
|
|
26
|
-
const workspace = context?.created ? { ...prepared, agentHomePreexisted: false } : prepared;
|
|
27
|
-
const initialMode = await resolveLocalMemoryV2Rollout({ workspace, handle: input.handle, serverUrl: input.launch.serverUrl,
|
|
28
|
-
agentId: input.launch.agentId, requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
|
|
29
|
-
...(input.launch.description ? { description: input.launch.description } : {}) });
|
|
30
|
-
const initializationBinding = input.launch.workspaceId !== undefined && input.launch.machineId !== undefined
|
|
31
|
-
? { workspaceId: input.launch.workspaceId, machineId: input.launch.machineId }
|
|
32
|
-
: undefined;
|
|
33
|
-
const initialized = await initializeLocalMemoryV2ForWorkspace(workspace, initialMode.enabled, input.launch.agentId, initializationBinding);
|
|
34
|
-
const memory = initialized && !workspace.localMemoryV2Initialized
|
|
35
|
-
? await readFile(join(workspace.dir, "MEMORY.md"), "utf8")
|
|
36
|
-
: workspace.memory;
|
|
37
|
-
const currentWorkspace = { ...workspace, memory };
|
|
38
|
-
const mode = initialized && !workspace.localMemoryV2Initialized
|
|
39
|
-
? await resolveLocalMemoryV2Rollout({ workspace: currentWorkspace, handle: input.handle,
|
|
40
|
-
serverUrl: input.launch.serverUrl, agentId: input.launch.agentId,
|
|
41
|
-
requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
|
|
42
|
-
...(input.launch.description ? { description: input.launch.description } : {}) })
|
|
43
|
-
: initialMode;
|
|
44
|
-
return { workspace: { ...currentWorkspace, localMemoryV2Enabled: mode.enabled }, mode, initialized };
|
|
45
|
-
};
|
|
46
|
-
return await awaitWithCancellation(isolated ? prepare()
|
|
47
|
-
: withMemoryAccess(join(input.launch.agentsRoot, input.handle), prepare, {
|
|
48
|
-
create: true,
|
|
49
|
-
waitMs: EXECUTION_MEMORY_ACCESS_WAIT_MS,
|
|
50
|
-
initializedRecoveryIdentity: {
|
|
51
|
-
agentId: input.launch.agentId,
|
|
52
|
-
...(input.launch.workspaceId === undefined ? {} : { workspaceId: input.launch.workspaceId }),
|
|
53
|
-
...(input.launch.machineId === undefined ? {} : { machineId: input.launch.machineId }),
|
|
54
|
-
},
|
|
55
|
-
}), cancellation);
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
logLocalMemoryContextPrepareFailure({ executionId: input.executionId, agentHandle: input.handle,
|
|
59
|
-
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }) }, "workspace_prepare", error);
|
|
60
|
-
throw error;
|
|
61
|
-
}
|
|
62
|
-
}
|