@kafca/agentdock 0.1.43 → 0.1.45
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 +77 -11
- package/bin/agentdock.mjs +5 -5
- package/dist/renderer/assets/{Badge-CbG6yRSm.js → Badge-BIojwD6s.js} +1 -1
- package/dist/renderer/assets/{Chat-BvNNWGGX.js → Chat-wjBR3XEX.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-Ct-PvJB8.js → ChatMarkdown-DqszsPB_.js} +1 -1
- package/dist/renderer/assets/Config-BDCHs5A2.js +21 -0
- package/dist/renderer/assets/{CronList-Dj_3muVG.js → CronList-CEWQYTov.js} +1 -1
- package/dist/renderer/assets/Dashboard-DrWftfk3.js +26 -0
- package/dist/renderer/assets/{EmptyState-Bn2Qh14U.js → EmptyState-BqCx1oWr.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-Bsz6Ou41.js → KnowledgeDetail-BwK8Gpfa.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-Cgj4XFXn.js → KnowledgeHome-hhDTZMDO.js} +3 -3
- package/dist/renderer/assets/{Logs-Dp-NF6GN.js → Logs-C9xPEhFT.js} +1 -1
- package/dist/renderer/assets/{Modal-B6YPPBN6.js → Modal-D2U4r2V0.js} +1 -1
- package/dist/renderer/assets/{MonitorList-xEZWg460.js → MonitorList-CayKbfwJ.js} +1 -1
- package/dist/renderer/assets/{Page-Bn7RjGOS.js → Page-urf5GcT_.js} +1 -1
- package/dist/renderer/assets/ProjectDetail-B1GyAr7a.js +11 -0
- package/dist/renderer/assets/{ProjectList-BDk5_gqY.js → ProjectList-BoipQypE.js} +1 -1
- package/dist/renderer/assets/{Select-xshfMIEQ.js → Select-CAscWpy5.js} +1 -1
- package/dist/renderer/assets/{SessionChat-BkHy90z3.js → SessionChat-BAVy5221.js} +1 -1
- package/dist/renderer/assets/{SessionList-BZyXT92L.js → SessionList-BZpuMvh0.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-DUOIyXrS.js → ThreadChat-JX7m9biG.js} +1 -1
- package/dist/renderer/assets/Workspace-CFW8otjU.js +14 -0
- package/dist/renderer/assets/{arrow-left-C54ZI-AS.js → arrow-left-7HrNuS-V.js} +1 -1
- package/dist/renderer/assets/{book-open-Dl7GO0zn.js → book-open-BDoAu82s.js} +1 -1
- package/dist/renderer/assets/{check-CiqgtrOL.js → check-DGlyq4xX.js} +1 -1
- package/dist/renderer/assets/{chevron-down-DTL2OuVh.js → chevron-down-Bb_3EHq9.js} +1 -1
- package/dist/renderer/assets/{circle-DaVKfa3P.js → circle-DIpqZnYw.js} +1 -1
- package/dist/renderer/assets/desktop-Ci1fnRDR.js +1 -0
- package/dist/renderer/assets/{desktop-C6q6wBae.js → desktop-Do_UrC-o.js} +5 -5
- package/dist/renderer/assets/en-CmAr_0e6.js +1 -0
- package/dist/renderer/assets/es-Cs9x52ca.js +1 -0
- package/dist/renderer/assets/{funnel-CrmnLMJI.js → funnel-Bbf0ERLP.js} +1 -1
- package/dist/renderer/assets/{heart-BMfQI7y_.js → heart-CGqU-qfw.js} +1 -1
- package/dist/renderer/assets/{index-nreiKY1f.js → index-Df-Trovt.js} +2 -2
- package/dist/renderer/assets/{index-HPNb1zfx.js → index-DwhTjLA1.js} +36 -36
- package/dist/renderer/assets/index-RaTga2BC.css +11 -0
- package/dist/renderer/assets/ja-DtvtBRTW.js +1 -0
- package/dist/renderer/assets/{pencil-wTQ4l465.js → pencil-CHiy1MvK.js} +1 -1
- package/dist/renderer/assets/{play-BK--MXmw.js → play-CGYnmC4Q.js} +1 -1
- package/dist/renderer/assets/{plug-BIx9fjip.js → plug-Mexu4gyV.js} +1 -1
- package/dist/renderer/assets/{plus-Dn7JFWQ8.js → plus-B_Q5-Oj7.js} +1 -1
- package/dist/renderer/assets/projects-C6bbkC-O.js +1 -0
- package/dist/renderer/assets/{save-CC3zOSWb.js → save-CJ_QFPw0.js} +1 -1
- package/dist/renderer/assets/{search-CDTy9Czu.js → search-D8Dkhsyq.js} +1 -1
- package/dist/renderer/assets/{server-DtQk3t2a.js → server-Cd96R7WL.js} +1 -1
- package/dist/renderer/assets/{session-utils-4ep5D66T.js → session-utils-BNUbQBfF.js} +1 -1
- package/dist/renderer/assets/{sessions-Dor1LteH.js → sessions-BACfV8s1.js} +1 -1
- package/dist/renderer/assets/{shield-check-Cz2LpU6r.js → shield-check-Cnn-yQUA.js} +1 -1
- package/dist/renderer/assets/{trash-2-C2EmWFZV.js → trash-2-oWCxwQ9D.js} +1 -1
- package/dist/renderer/assets/{user-I8B-cs5A.js → user-BzE9BwsY.js} +1 -1
- package/dist/renderer/assets/{wifi-off-CPevTQJn.js → wifi-off-DHxnNkdY.js} +1 -1
- package/dist/renderer/assets/zh-CcJ9vBZj.js +1 -0
- package/dist/renderer/assets/zh-TW-elI72AC1.js +1 -0
- package/dist/renderer/index.html +2 -2
- package/dist-electron/electron/main.js +26 -1
- package/dist-electron/packages/core-sdk/src/index.js +28 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +111 -62
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +80 -7
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +78 -5
- package/dist-electron/services/local-ai-core/src/acp/store/external-store.js +98 -0
- package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +33 -0
- package/dist-electron/services/local-ai-core/src/acp/store/model-provider-store.js +88 -0
- package/dist-electron/services/local-ai-core/src/acp/store/schema.js +43 -0
- package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +2 -119
- package/dist-electron/services/local-ai-core/src/agents/pi/provider-materializer.js +148 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/inbound.js +114 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +117 -75
- package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +4 -2
- package/dist-electron/services/local-ai-core/src/channel/shared/thread-routing.js +34 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +151 -47
- package/dist-electron/services/local-ai-core/src/execution/agent-execution-backend.js +56 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +18 -57
- package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +255 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/catalog.js +78 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +3 -1
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +64 -9
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -2
- package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +152 -0
- package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +175 -0
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +330 -3
- package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +11 -2
- package/dist-electron/services/local-ai-core/src/runtime/provider-config-migration.js +32 -0
- package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +76 -8
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +62 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +708 -4
- package/dist-electron/services/local-ai-core/src/runtime/standalone.js +13 -3
- package/dist-electron/services/local-ai-core/src/sandbox/opensandbox-client.js +113 -0
- package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +273 -0
- package/dist-electron/services/local-ai-core/src/sandbox/sandbox-manager.js +215 -0
- package/dist-electron/services/local-ai-core/src/sandbox/sandbox-stdio-proxy.js +188 -0
- package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +3 -0
- package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +32 -0
- package/dist-electron/services/local-ai-core/src/thread/thread-slash-command-dispatcher.js +71 -0
- package/dist-electron/shared/desktop.js +85 -1
- package/dist-electron/tests/contracts/architecture-docs.test.js +83 -0
- package/dist-electron/tests/electron/plugin-kernel.test.js +225 -18
- package/dist-electron/tests/electron/runtime-detection-service.test.js +57 -5
- package/dist-electron/tests/electron/sandbox-config.test.js +541 -0
- package/dist-electron/tests/electron/workspace-task-store.test.js +257 -0
- package/dist-electron/tests/integration/channel-gateways.test.js +32 -0
- package/dist-electron/tests/integration/lark-gateway.test.js +1977 -0
- package/dist-electron/tests/integration/local-core-acp-progress.test.js +1772 -0
- package/dist-electron/tests/integration/local-core-refactor.test.js +775 -5156
- package/dist-electron/tests/integration/local-core-routes.test.js +238 -0
- package/dist-electron/tests/integration/weixin-gateway.test.js +927 -0
- package/package.json +2 -3
- package/dist/renderer/assets/Config-lQX2qVVV.js +0 -16
- package/dist/renderer/assets/Dashboard-eh_RhGYb.js +0 -26
- package/dist/renderer/assets/ProjectDetail-Cv_jIE61.js +0 -11
- package/dist/renderer/assets/Workspace-Dl80fNEC.js +0 -14
- package/dist/renderer/assets/desktop-jaAiayNB.js +0 -1
- package/dist/renderer/assets/en-D2SkCrhG.js +0 -1
- package/dist/renderer/assets/es-C8UBPhxM.js +0 -1
- package/dist/renderer/assets/index-CaQZSRbg.css +0 -11
- package/dist/renderer/assets/ja-ChF4vbBL.js +0 -1
- package/dist/renderer/assets/projects-brJZgwEJ.js +0 -1
- package/dist/renderer/assets/zh-DIcdHycM.js +0 -1
- package/dist/renderer/assets/zh-TW-BtRwreY_.js +0 -1
|
@@ -13,8 +13,8 @@ const local_core_slash_commands_js_1 = require("./local-core-slash-commands.js")
|
|
|
13
13
|
const local_core_acp_progress_js_1 = require("./local-core-acp-progress.js");
|
|
14
14
|
const index_js_1 = require("../agents/index.js");
|
|
15
15
|
const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
|
|
16
|
-
const
|
|
17
|
-
const
|
|
16
|
+
const thread_slash_command_dispatcher_js_1 = require("../thread/thread-slash-command-dispatcher.js");
|
|
17
|
+
const local_core_errors_js_1 = require("../kernel/local-core-errors.js");
|
|
18
18
|
const ACP_PROMPT_TIMEOUT_MS = 15 * 60 * 1000;
|
|
19
19
|
class LocalCoreAcpBackend {
|
|
20
20
|
options;
|
|
@@ -22,8 +22,7 @@ class LocalCoreAcpBackend {
|
|
|
22
22
|
turnCoordinator;
|
|
23
23
|
sessionCoordinator;
|
|
24
24
|
responseProcessor;
|
|
25
|
-
|
|
26
|
-
sessionCommandService;
|
|
25
|
+
slashCommands;
|
|
27
26
|
constructor(options) {
|
|
28
27
|
this.options = options;
|
|
29
28
|
this.transport = new local_core_acp_transport_js_1.LocalCoreAcpTransport({
|
|
@@ -91,25 +90,28 @@ class LocalCoreAcpBackend {
|
|
|
91
90
|
emitBridge: (event) => this.emitBridgeEvent(event),
|
|
92
91
|
log: options.log,
|
|
93
92
|
});
|
|
94
|
-
this.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.
|
|
93
|
+
this.slashCommands = new thread_slash_command_dispatcher_js_1.ThreadSlashCommandDispatcher({
|
|
94
|
+
session: {
|
|
95
|
+
listThreads: (workspaceId) => this.listThreads(workspaceId),
|
|
96
|
+
getThread: (targetThreadId) => this.getThread(targetThreadId),
|
|
97
|
+
createThread: (workspaceId, title) => this.createThread(workspaceId, title),
|
|
98
|
+
renameThread: (targetThreadId, title) => this.renameThread(targetThreadId, title),
|
|
99
|
+
deleteThread: (targetThreadId) => this.deleteThread(targetThreadId),
|
|
100
|
+
},
|
|
101
|
+
thread: {
|
|
102
|
+
getThreadRow: (threadId) => this.options.store.getThreadRow(threadId),
|
|
103
|
+
updateThreadAgentMode: (threadId, mode) => this.options.store.updateThreadAgentMode(threadId, mode),
|
|
104
|
+
updateThreadAgentType: (threadId, agentType) => this.options.store.updateThreadAgentType(threadId, agentType),
|
|
105
|
+
getLatestRunForThread: (threadId) => this.options.store.getLatestRunForThread(threadId),
|
|
106
|
+
createAuditEvent: (input) => {
|
|
107
|
+
this.options.store.createAuditEvent(input);
|
|
108
|
+
},
|
|
109
|
+
getAgentTypes: options.getAgentTypes,
|
|
110
|
+
setThreadMode: (threadId, mode) => this.sessionCoordinator.setThreadMode(threadId, mode),
|
|
111
|
+
closeThreadSession: (threadId) => this.sessionCoordinator.closeThreadSession(threadId),
|
|
112
|
+
interruptRun: (runId) => this.sessionCoordinator.interruptRun(runId),
|
|
113
|
+
log: options.log,
|
|
101
114
|
},
|
|
102
|
-
getAgentTypes: options.getAgentTypes,
|
|
103
|
-
setThreadMode: (threadId, mode) => this.sessionCoordinator.setThreadMode(threadId, mode),
|
|
104
|
-
closeThreadSession: (threadId) => this.sessionCoordinator.closeThreadSession(threadId),
|
|
105
|
-
log: options.log,
|
|
106
|
-
});
|
|
107
|
-
this.sessionCommandService = new session_command_service_js_1.SessionCommandService({
|
|
108
|
-
listThreads: (workspaceId) => this.listThreads(workspaceId),
|
|
109
|
-
getThread: (targetThreadId) => this.getThread(targetThreadId),
|
|
110
|
-
createThread: (workspaceId, title) => this.createThread(workspaceId, title),
|
|
111
|
-
renameThread: (targetThreadId, title) => this.renameThread(targetThreadId, title),
|
|
112
|
-
deleteThread: (targetThreadId) => this.deleteThread(targetThreadId),
|
|
113
115
|
});
|
|
114
116
|
this.responseProcessor = new local_core_acp_response_processor_js_1.LocalCoreAcpResponseProcessor({
|
|
115
117
|
getScheduledDeliveryBinding: (threadId) => {
|
|
@@ -173,22 +175,24 @@ class LocalCoreAcpBackend {
|
|
|
173
175
|
source: 'user',
|
|
174
176
|
},
|
|
175
177
|
});
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
+
const slashCommandResult = await this.slashCommands.execute({
|
|
179
|
+
threadId,
|
|
178
180
|
workspaceId: row.workspace_id,
|
|
181
|
+
content,
|
|
182
|
+
defaultAgentType: config.agentType,
|
|
179
183
|
defaultTitle: `New thread ${new Date().toLocaleTimeString()}`,
|
|
180
184
|
});
|
|
181
|
-
if (
|
|
182
|
-
const activeThreadEffect = (
|
|
185
|
+
if (slashCommandResult.handled) {
|
|
186
|
+
const activeThreadEffect = (slashCommandResult.effects || [])
|
|
183
187
|
.find((effect) => effect.type === 'activate_thread');
|
|
184
|
-
this.options.store.appendMessage(threadId, 'assistant',
|
|
188
|
+
this.options.store.appendMessage(threadId, 'assistant', slashCommandResult.displayText, 'final');
|
|
185
189
|
this.options.eventBus.emit({
|
|
186
190
|
type: 'thread.message.accepted',
|
|
187
191
|
payload: {
|
|
188
192
|
threadId,
|
|
189
193
|
workspaceId: row.workspace_id,
|
|
190
194
|
role: 'assistant',
|
|
191
|
-
content:
|
|
195
|
+
content: slashCommandResult.displayText,
|
|
192
196
|
kind: 'final',
|
|
193
197
|
source: 'system',
|
|
194
198
|
},
|
|
@@ -207,37 +211,7 @@ class LocalCoreAcpBackend {
|
|
|
207
211
|
this.emitBridgeEvent({
|
|
208
212
|
type: 'reply',
|
|
209
213
|
sessionKey: row.bridge_session_key,
|
|
210
|
-
content:
|
|
211
|
-
});
|
|
212
|
-
this.emitBridgeEvent({
|
|
213
|
-
type: 'typing_stop',
|
|
214
|
-
sessionKey: row.bridge_session_key,
|
|
215
|
-
});
|
|
216
|
-
return { runId: '' };
|
|
217
|
-
}
|
|
218
|
-
const commandResult = await this.commandService.execute({
|
|
219
|
-
threadId,
|
|
220
|
-
workspaceId: row.workspace_id,
|
|
221
|
-
content,
|
|
222
|
-
defaultAgentType: config.agentType,
|
|
223
|
-
});
|
|
224
|
-
if (commandResult.handled) {
|
|
225
|
-
this.options.store.appendMessage(threadId, 'assistant', commandResult.displayText, 'final');
|
|
226
|
-
this.options.eventBus.emit({
|
|
227
|
-
type: 'thread.message.accepted',
|
|
228
|
-
payload: {
|
|
229
|
-
threadId,
|
|
230
|
-
workspaceId: row.workspace_id,
|
|
231
|
-
role: 'assistant',
|
|
232
|
-
content: commandResult.displayText,
|
|
233
|
-
kind: 'final',
|
|
234
|
-
source: 'system',
|
|
235
|
-
},
|
|
236
|
-
});
|
|
237
|
-
this.emitBridgeEvent({
|
|
238
|
-
type: 'reply',
|
|
239
|
-
sessionKey: row.bridge_session_key,
|
|
240
|
-
content: commandResult.displayText,
|
|
214
|
+
content: slashCommandResult.displayText,
|
|
241
215
|
});
|
|
242
216
|
this.emitBridgeEvent({
|
|
243
217
|
type: 'typing_stop',
|
|
@@ -257,6 +231,24 @@ class LocalCoreAcpBackend {
|
|
|
257
231
|
title: content.trim().slice(0, 80) || row.title || 'Agent task',
|
|
258
232
|
prompt: content,
|
|
259
233
|
status: 'running',
|
|
234
|
+
metadata: {
|
|
235
|
+
execution: config.execution || {
|
|
236
|
+
mode: config.sandbox?.enabled ? 'sandbox' : 'local',
|
|
237
|
+
transport: config.sandbox?.enabled ? `sandbox-${config.sandbox.transport}-stdio-proxy` : 'stdio',
|
|
238
|
+
},
|
|
239
|
+
...(config.sandbox?.enabled
|
|
240
|
+
? {
|
|
241
|
+
sandbox: {
|
|
242
|
+
provider: config.sandbox.provider,
|
|
243
|
+
image: config.sandbox.image,
|
|
244
|
+
transport: config.sandbox.transport,
|
|
245
|
+
acpPort: config.sandbox.acpPort,
|
|
246
|
+
stateScope: config.sandbox.stateScope,
|
|
247
|
+
stateMount: config.sandbox.stateMount || null,
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
: {}),
|
|
251
|
+
},
|
|
260
252
|
});
|
|
261
253
|
this.options.eventBus.emit({
|
|
262
254
|
type: 'run.started',
|
|
@@ -320,6 +312,12 @@ class LocalCoreAcpBackend {
|
|
|
320
312
|
async interruptRun(runId) {
|
|
321
313
|
return this.sessionCoordinator.interruptRun(runId);
|
|
322
314
|
}
|
|
315
|
+
async setThreadMode(threadId, mode) {
|
|
316
|
+
return this.sessionCoordinator.setThreadMode(threadId, mode);
|
|
317
|
+
}
|
|
318
|
+
closeThreadSession(threadId) {
|
|
319
|
+
this.sessionCoordinator.closeThreadSession(threadId);
|
|
320
|
+
}
|
|
323
321
|
async runPrompt(threadId, runId, bridgeSessionKey, config, input, options = {}) {
|
|
324
322
|
const row = this.options.store.getThreadRow(threadId);
|
|
325
323
|
if (!row) {
|
|
@@ -333,11 +331,14 @@ class LocalCoreAcpBackend {
|
|
|
333
331
|
const message = (0, local_core_acp_content_js_1.normalizeThreadMessageInput)(input);
|
|
334
332
|
const content = message.displayText;
|
|
335
333
|
let session = null;
|
|
334
|
+
const runStartedAt = Date.now();
|
|
336
335
|
try {
|
|
337
336
|
session = await this.sessionCoordinator.ensureSession(threadId, bridgeSessionKey, config, {
|
|
338
337
|
permissionMode: options.permissionMode,
|
|
339
338
|
runtimeEnv: options.runtimeEnv,
|
|
339
|
+
runId,
|
|
340
340
|
});
|
|
341
|
+
this.options.log?.(`[acp.run:${runId}] session ready in ${Date.now() - runStartedAt}ms`);
|
|
341
342
|
const priorAssistantFinalMessages = this.options.store
|
|
342
343
|
.getThread(threadId, [])
|
|
343
344
|
.messages
|
|
@@ -385,8 +386,10 @@ class LocalCoreAcpBackend {
|
|
|
385
386
|
messageId: (0, node_crypto_1.randomUUID)(),
|
|
386
387
|
prompt: message.contentParts,
|
|
387
388
|
}, ACP_PROMPT_TIMEOUT_MS);
|
|
389
|
+
this.options.log?.(`[acp.run:${runId}] prompt sent in ${Date.now() - runStartedAt}ms`);
|
|
388
390
|
session.promptPromise = promptPromise;
|
|
389
391
|
const result = await promptPromise;
|
|
392
|
+
this.options.log?.(`[acp.run:${runId}] prompt completed in ${Date.now() - runStartedAt}ms`);
|
|
390
393
|
const currentTurn = session.currentTurn;
|
|
391
394
|
if (!currentTurn || currentTurn.runId !== runId) {
|
|
392
395
|
return;
|
|
@@ -492,13 +495,18 @@ class LocalCoreAcpBackend {
|
|
|
492
495
|
});
|
|
493
496
|
}
|
|
494
497
|
catch (error) {
|
|
495
|
-
const
|
|
498
|
+
const errorInfo = (0, local_core_errors_js_1.toLocalCoreErrorInfo)(error, 'internal_error', {
|
|
499
|
+
threadId,
|
|
500
|
+
workspaceId: row.workspace_id,
|
|
501
|
+
runtimeId: config.agentType,
|
|
502
|
+
});
|
|
503
|
+
const errorContent = (0, local_core_errors_js_1.formatUserError)(errorInfo);
|
|
496
504
|
this.options.store.updateRun(runId, threadId, 'failed');
|
|
497
505
|
const task = this.options.store.getAgentTaskByRunId(runId);
|
|
498
506
|
if (task) {
|
|
499
507
|
this.options.store.updateAgentTask(task.taskId, {
|
|
500
508
|
status: 'failed',
|
|
501
|
-
error:
|
|
509
|
+
error: errorInfo.message,
|
|
502
510
|
});
|
|
503
511
|
}
|
|
504
512
|
this.options.store.appendMessage(threadId, 'assistant', errorContent, 'final');
|
|
@@ -519,7 +527,21 @@ class LocalCoreAcpBackend {
|
|
|
519
527
|
runId,
|
|
520
528
|
threadId,
|
|
521
529
|
workspaceId: row.workspace_id,
|
|
522
|
-
error:
|
|
530
|
+
error: errorInfo.message,
|
|
531
|
+
errorInfo,
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
this.options.eventBus.emit({
|
|
535
|
+
type: 'localcore.error',
|
|
536
|
+
payload: {
|
|
537
|
+
scope: 'acp.run',
|
|
538
|
+
errorInfo,
|
|
539
|
+
context: {
|
|
540
|
+
threadId,
|
|
541
|
+
workspaceId: row.workspace_id,
|
|
542
|
+
runtimeId: config.agentType,
|
|
543
|
+
runId,
|
|
544
|
+
},
|
|
523
545
|
},
|
|
524
546
|
});
|
|
525
547
|
this.emitBridgeEvent({
|
|
@@ -544,16 +566,43 @@ class LocalCoreAcpBackend {
|
|
|
544
566
|
if (session) {
|
|
545
567
|
session.promptPromise = null;
|
|
546
568
|
}
|
|
569
|
+
if (config.sandbox?.enabled) {
|
|
570
|
+
this.sessionCoordinator.releaseThreadSession(threadId, config);
|
|
571
|
+
}
|
|
547
572
|
}
|
|
548
573
|
}
|
|
549
574
|
handleAgentRequest(session, payload) {
|
|
550
575
|
this.turnCoordinator.handleAgentRequest(session, payload);
|
|
551
576
|
}
|
|
552
577
|
handleAgentNotification(session, payload) {
|
|
578
|
+
if (session.currentTurn && !session.currentTurn.firstAgentUpdateLogged) {
|
|
579
|
+
session.currentTurn.firstAgentUpdateLogged = true;
|
|
580
|
+
this.options.log?.(`[acp.run:${session.currentTurn.runId}] first agent update received`);
|
|
581
|
+
}
|
|
553
582
|
this.turnCoordinator.handleAgentNotification(session, payload);
|
|
554
583
|
}
|
|
555
584
|
handleTransportSessionClosed(session, error) {
|
|
585
|
+
const row = this.options.store.getThreadRow(session.threadId);
|
|
586
|
+
const runtimeId = session.currentTurn?.agentType || row?.agent_type || '';
|
|
587
|
+
const errorInfo = (0, local_core_errors_js_1.toLocalCoreErrorInfo)(error, 'runtime_exited', {
|
|
588
|
+
threadId: session.threadId,
|
|
589
|
+
workspaceId: row?.workspace_id || '',
|
|
590
|
+
runtimeId,
|
|
591
|
+
});
|
|
556
592
|
this.sessionCoordinator.handleTransportSessionClosed(session, error);
|
|
593
|
+
this.options.eventBus.emit({
|
|
594
|
+
type: 'localcore.error',
|
|
595
|
+
payload: {
|
|
596
|
+
scope: 'acp.session',
|
|
597
|
+
errorInfo,
|
|
598
|
+
context: {
|
|
599
|
+
threadId: session.threadId,
|
|
600
|
+
workspaceId: row?.workspace_id || '',
|
|
601
|
+
runtimeId,
|
|
602
|
+
runId: session.currentRunId || '',
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
});
|
|
557
606
|
}
|
|
558
607
|
emitBridgeEvent(event) {
|
|
559
608
|
if (event.replyCtx) {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LocalCoreAcpSessionCoordinator = void 0;
|
|
4
|
+
exports.buildAgentPath = buildAgentPath;
|
|
4
5
|
const node_path_1 = require("node:path");
|
|
6
|
+
const node_os_1 = require("node:os");
|
|
5
7
|
const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
|
|
6
8
|
class LocalCoreAcpSessionCoordinator {
|
|
7
9
|
options;
|
|
@@ -14,6 +16,7 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
14
16
|
}
|
|
15
17
|
closeAll() {
|
|
16
18
|
for (const session of this.sessions.values()) {
|
|
19
|
+
this.clearIdleClose(session);
|
|
17
20
|
this.options.transport.closeSession(session);
|
|
18
21
|
}
|
|
19
22
|
this.sessions.clear();
|
|
@@ -23,9 +26,21 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
23
26
|
if (!session) {
|
|
24
27
|
return;
|
|
25
28
|
}
|
|
29
|
+
this.clearIdleClose(session);
|
|
26
30
|
this.options.transport.closeSession(session);
|
|
27
31
|
this.sessions.delete(threadId);
|
|
28
32
|
}
|
|
33
|
+
releaseThreadSession(threadId, config) {
|
|
34
|
+
if (!config.sandbox?.enabled || config.sandbox.lifecycle === 'per_run' || config.sandbox.stateScope === 'run') {
|
|
35
|
+
this.closeThreadSession(threadId);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const session = this.sessions.get(threadId);
|
|
39
|
+
if (!session || session.closed) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.scheduleIdleClose(session, config.sandbox.idleSeconds);
|
|
43
|
+
}
|
|
29
44
|
async ensureSession(threadId, bridgeSessionKey, config, options = {}) {
|
|
30
45
|
const existing = this.sessions.get(threadId);
|
|
31
46
|
const permissionMode = this.resolveLaunchPermissionMode(threadId, options.permissionMode);
|
|
@@ -37,11 +52,15 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
37
52
|
&& existing.launchPermissionMode === permissionMode
|
|
38
53
|
&& existing.launchConfigKey === configKey
|
|
39
54
|
&& existing.launchRuntimeEnvKey === runtimeEnvKey) {
|
|
55
|
+
this.clearIdleClose(existing);
|
|
56
|
+
this.options.log?.(`[acp.session:${threadId}] reuse existing session mode=${config.sandbox?.enabled ? 'sandbox' : 'local'}`);
|
|
40
57
|
return existing;
|
|
41
58
|
}
|
|
42
59
|
if (existing) {
|
|
43
60
|
this.closeThreadSession(threadId);
|
|
44
61
|
}
|
|
62
|
+
const startedAt = Date.now();
|
|
63
|
+
this.options.log?.(`[acp.session:${threadId}] spawn mode=${config.sandbox?.enabled ? 'sandbox' : 'local'} transport=${config.execution?.transport || 'stdio'}`);
|
|
45
64
|
const baseEnv = {
|
|
46
65
|
...process.env,
|
|
47
66
|
...config.env,
|
|
@@ -50,20 +69,21 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
50
69
|
threadId,
|
|
51
70
|
bridgeSessionKey,
|
|
52
71
|
config,
|
|
53
|
-
runtimeEnv: this.buildAgentRuntimeEnv(threadId, String(baseEnv.PATH || ''), options.runtimeEnv),
|
|
72
|
+
runtimeEnv: this.buildAgentRuntimeEnv(threadId, String(baseEnv.PATH || ''), options.runtimeEnv, options.runId),
|
|
54
73
|
});
|
|
55
74
|
session.launchPermissionMode = permissionMode;
|
|
56
75
|
session.launchConfigKey = configKey;
|
|
57
76
|
session.launchRuntimeEnvKey = runtimeEnvKey;
|
|
58
77
|
this.sessions.set(threadId, session);
|
|
59
78
|
await this.options.transport.initializeSession(session);
|
|
79
|
+
this.options.log?.(`[acp.session:${threadId}] initialize done in ${Date.now() - startedAt}ms`);
|
|
60
80
|
const row = this.options.store.getThreadRow(threadId);
|
|
61
81
|
if (row?.acp_session_id && row.acp_supports_load && session.supportsLoad) {
|
|
62
82
|
try {
|
|
63
83
|
session.loadReplayMode = true;
|
|
64
84
|
await this.options.transport.request(session, 'session/load', {
|
|
65
85
|
sessionId: row.acp_session_id,
|
|
66
|
-
cwd: config
|
|
86
|
+
cwd: acpSessionCwd(config),
|
|
67
87
|
mcpServers: [],
|
|
68
88
|
}, 30000);
|
|
69
89
|
session.sessionId = row.acp_session_id;
|
|
@@ -78,7 +98,7 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
78
98
|
if (!session.sessionId) {
|
|
79
99
|
try {
|
|
80
100
|
const created = await this.options.transport.request(session, 'session/new', {
|
|
81
|
-
cwd: config
|
|
101
|
+
cwd: acpSessionCwd(config),
|
|
82
102
|
mcpServers: [],
|
|
83
103
|
_meta: this.buildSessionMeta(threadId, permissionMode),
|
|
84
104
|
}, 30000);
|
|
@@ -87,12 +107,14 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
87
107
|
throw new Error('ACP session/new did not return a sessionId');
|
|
88
108
|
}
|
|
89
109
|
this.options.store.updateThreadSession(threadId, session.sessionId, session.supportsLoad);
|
|
110
|
+
this.options.log?.(`[acp.session:${threadId}] session/new done in ${Date.now() - startedAt}ms`);
|
|
90
111
|
}
|
|
91
112
|
catch (error) {
|
|
92
113
|
this.closeThreadSession(threadId);
|
|
93
114
|
throw error;
|
|
94
115
|
}
|
|
95
116
|
}
|
|
117
|
+
this.options.log?.(`[acp.session:${threadId}] ready in ${Date.now() - startedAt}ms`);
|
|
96
118
|
return session;
|
|
97
119
|
}
|
|
98
120
|
async setThreadMode(threadId, mode) {
|
|
@@ -152,6 +174,7 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
152
174
|
return;
|
|
153
175
|
}
|
|
154
176
|
const activeRunId = session.currentRunId;
|
|
177
|
+
this.clearIdleClose(session);
|
|
155
178
|
this.options.transport.closeSessionWithError(session, error);
|
|
156
179
|
if (activeRunId) {
|
|
157
180
|
this.options.store.updateRun(activeRunId, session.threadId, 'failed');
|
|
@@ -166,13 +189,31 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
166
189
|
this.sessions.delete(session.threadId);
|
|
167
190
|
}
|
|
168
191
|
}
|
|
192
|
+
scheduleIdleClose(session, idleSeconds) {
|
|
193
|
+
this.clearIdleClose(session);
|
|
194
|
+
const seconds = Number.isFinite(idleSeconds) && idleSeconds > 0 ? idleSeconds : 900;
|
|
195
|
+
this.options.log?.(`[acp.session:${session.threadId}] keep sandbox session warm for ${seconds}s`);
|
|
196
|
+
session.idleCloseTimer = setTimeout(() => {
|
|
197
|
+
if (this.sessions.get(session.threadId) === session && !session.closed && !session.currentRunId) {
|
|
198
|
+
this.options.log?.(`[acp.session:${session.threadId}] idle timeout reached; closing sandbox session`);
|
|
199
|
+
this.closeThreadSession(session.threadId);
|
|
200
|
+
}
|
|
201
|
+
}, seconds * 1000);
|
|
202
|
+
session.idleCloseTimer.unref?.();
|
|
203
|
+
}
|
|
204
|
+
clearIdleClose(session) {
|
|
205
|
+
if (session.idleCloseTimer) {
|
|
206
|
+
clearTimeout(session.idleCloseTimer);
|
|
207
|
+
session.idleCloseTimer = undefined;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
169
210
|
buildRuntimeEnvKey(runtimeEnv = {}) {
|
|
170
211
|
return Object.keys(runtimeEnv)
|
|
171
212
|
.sort()
|
|
172
213
|
.map((key) => `${key}=${runtimeEnv[key]}`)
|
|
173
214
|
.join('\n');
|
|
174
215
|
}
|
|
175
|
-
buildAgentRuntimeEnv(threadId, existingPath, runtimeEnv = {}) {
|
|
216
|
+
buildAgentRuntimeEnv(threadId, existingPath, runtimeEnv = {}, runId = '') {
|
|
176
217
|
const row = this.options.store.getThreadRow(threadId);
|
|
177
218
|
if (!row) {
|
|
178
219
|
return {};
|
|
@@ -182,6 +223,7 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
182
223
|
LOCAL_AI_CORE_BASE: this.options.localCoreBase || 'http://127.0.0.1:9831/api/local/v1',
|
|
183
224
|
LOCAL_AI_WORKSPACE_ID: row.workspace_id,
|
|
184
225
|
LOCAL_AI_THREAD_ID: threadId,
|
|
226
|
+
...(runId ? { AGENTDOCK_SANDBOX_RUN_ID: runId } : {}),
|
|
185
227
|
};
|
|
186
228
|
const workspace = this.options.store.getWorkspaceRegistryEntry(row.workspace_id);
|
|
187
229
|
if (workspace?.path) {
|
|
@@ -198,9 +240,10 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
198
240
|
env.LOCAL_AI_PLATFORM_USER_ID = binding.platform_user_id;
|
|
199
241
|
}
|
|
200
242
|
if (this.options.cliBinDir) {
|
|
201
|
-
env.PATH = existingPath
|
|
202
|
-
|
|
203
|
-
|
|
243
|
+
env.PATH = buildAgentPath(existingPath, this.options.cliBinDir);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
env.PATH = buildAgentPath(existingPath);
|
|
204
247
|
}
|
|
205
248
|
return {
|
|
206
249
|
...env,
|
|
@@ -215,6 +258,8 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
215
258
|
args: config.args || [],
|
|
216
259
|
env: config.env || {},
|
|
217
260
|
model: config.model || '',
|
|
261
|
+
execution: config.execution || null,
|
|
262
|
+
sandbox: config.sandbox || null,
|
|
218
263
|
});
|
|
219
264
|
}
|
|
220
265
|
resolveLaunchPermissionMode(threadId, permissionModeOverride = '') {
|
|
@@ -241,3 +286,31 @@ class LocalCoreAcpSessionCoordinator {
|
|
|
241
286
|
}
|
|
242
287
|
}
|
|
243
288
|
exports.LocalCoreAcpSessionCoordinator = LocalCoreAcpSessionCoordinator;
|
|
289
|
+
function acpSessionCwd(config) {
|
|
290
|
+
return config.sandbox?.enabled ? config.sandbox.workspaceMountPath : config.workDir;
|
|
291
|
+
}
|
|
292
|
+
function buildAgentPath(existingPath, cliBinDir) {
|
|
293
|
+
const entries = [
|
|
294
|
+
cliBinDir,
|
|
295
|
+
...userBinDirs(),
|
|
296
|
+
...String(existingPath || '').split(node_path_1.delimiter),
|
|
297
|
+
];
|
|
298
|
+
const seen = new Set();
|
|
299
|
+
return entries
|
|
300
|
+
.map((entry) => String(entry || '').trim())
|
|
301
|
+
.filter((entry) => {
|
|
302
|
+
if (!entry || seen.has(entry)) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
seen.add(entry);
|
|
306
|
+
return true;
|
|
307
|
+
})
|
|
308
|
+
.join(node_path_1.delimiter);
|
|
309
|
+
}
|
|
310
|
+
function userBinDirs() {
|
|
311
|
+
if (process.platform === 'win32') {
|
|
312
|
+
return [];
|
|
313
|
+
}
|
|
314
|
+
const home = process.env.HOME || (0, node_os_1.homedir)();
|
|
315
|
+
return home ? [`${home}/.local/bin`, `${home}/bin`] : [];
|
|
316
|
+
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LocalCoreAcpTransport = void 0;
|
|
4
4
|
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const local_core_errors_js_1 = require("../kernel/local-core-errors.js");
|
|
5
7
|
class LocalCoreAcpTransport {
|
|
6
8
|
options;
|
|
7
9
|
constructor(options) {
|
|
@@ -12,8 +14,9 @@ class LocalCoreAcpTransport {
|
|
|
12
14
|
...process.env,
|
|
13
15
|
...input.config.env,
|
|
14
16
|
};
|
|
17
|
+
const cwd = resolveTransportCwd(input.config);
|
|
15
18
|
const child = (0, node_child_process_1.spawn)(input.config.command, input.config.args, {
|
|
16
|
-
cwd
|
|
19
|
+
cwd,
|
|
17
20
|
env: {
|
|
18
21
|
...baseEnv,
|
|
19
22
|
...input.runtimeEnv,
|
|
@@ -51,7 +54,37 @@ class LocalCoreAcpTransport {
|
|
|
51
54
|
this.handlePipeFailure(session, error);
|
|
52
55
|
});
|
|
53
56
|
child.on('exit', (code, signal) => {
|
|
54
|
-
|
|
57
|
+
if (session.closed) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.options.onSessionClosed(session, new local_core_errors_js_1.LocalCoreError('runtime_exited', `ACP agent exited with code ${code ?? 'unknown'}${signal ? ` (${signal})` : ''}`, {
|
|
61
|
+
details: {
|
|
62
|
+
code: code ?? 'unknown',
|
|
63
|
+
signal: signal || '',
|
|
64
|
+
threadId: input.threadId,
|
|
65
|
+
runtimeId: input.config.agentType,
|
|
66
|
+
},
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
69
|
+
child.on('error', (error) => {
|
|
70
|
+
this.options.onSessionClosed(session, error.code === 'ENOENT'
|
|
71
|
+
? new local_core_errors_js_1.LocalCoreError('runtime_not_found', `ACP agent command not found: ${input.config.command}`, {
|
|
72
|
+
details: {
|
|
73
|
+
command: input.config.command,
|
|
74
|
+
cwd,
|
|
75
|
+
threadId: input.threadId,
|
|
76
|
+
runtimeId: input.config.agentType,
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
: new local_core_errors_js_1.LocalCoreError('runtime_start_failed', `ACP agent failed to start: ${error.message}`, {
|
|
80
|
+
cause: error.code,
|
|
81
|
+
details: {
|
|
82
|
+
command: input.config.command,
|
|
83
|
+
cwd,
|
|
84
|
+
threadId: input.threadId,
|
|
85
|
+
runtimeId: input.config.agentType,
|
|
86
|
+
},
|
|
87
|
+
}));
|
|
55
88
|
});
|
|
56
89
|
return session;
|
|
57
90
|
}
|
|
@@ -79,7 +112,14 @@ class LocalCoreAcpTransport {
|
|
|
79
112
|
return new Promise((resolve, reject) => {
|
|
80
113
|
const timeout = setTimeout(() => {
|
|
81
114
|
session.pending.delete(id);
|
|
82
|
-
reject(new
|
|
115
|
+
reject(new local_core_errors_js_1.LocalCoreError('runtime_protocol_timeout', `Timed out waiting for ACP ${method} after ${timeoutMs}ms`, {
|
|
116
|
+
details: {
|
|
117
|
+
method,
|
|
118
|
+
timeoutMs,
|
|
119
|
+
threadId: session.threadId,
|
|
120
|
+
runtimeId: session.currentTurn?.agentType || '',
|
|
121
|
+
},
|
|
122
|
+
}));
|
|
83
123
|
}, timeoutMs);
|
|
84
124
|
session.pending.set(id, {
|
|
85
125
|
resolve: (value) => {
|
|
@@ -175,7 +215,15 @@ class LocalCoreAcpTransport {
|
|
|
175
215
|
}
|
|
176
216
|
session.pending.delete(payload.id);
|
|
177
217
|
if (payload.error) {
|
|
178
|
-
pending.reject(new
|
|
218
|
+
pending.reject(new local_core_errors_js_1.LocalCoreError(errorCodeForAcpError(payload.error), payload.error.message || `ACP request failed: ${payload.id}`, {
|
|
219
|
+
details: {
|
|
220
|
+
payloadId: payload.id,
|
|
221
|
+
errorCode: payload.error.code,
|
|
222
|
+
errorData: payload.error.data,
|
|
223
|
+
threadId: session.threadId,
|
|
224
|
+
runtimeId: session.currentTurn?.agentType || '',
|
|
225
|
+
},
|
|
226
|
+
}));
|
|
179
227
|
}
|
|
180
228
|
else {
|
|
181
229
|
pending.resolve(payload.result);
|
|
@@ -184,9 +232,34 @@ class LocalCoreAcpTransport {
|
|
|
184
232
|
}
|
|
185
233
|
}
|
|
186
234
|
handlePipeFailure(session, error) {
|
|
235
|
+
if (session.closed) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
187
238
|
const message = error instanceof Error ? error.message : String(error);
|
|
188
239
|
this.options.log?.(`[localcore-acp:${session.threadId}] stdin failure: ${message}`);
|
|
189
|
-
this.options.onSessionClosed(session, new
|
|
240
|
+
this.options.onSessionClosed(session, new local_core_errors_js_1.LocalCoreError('runtime_protocol_error', message, {
|
|
241
|
+
details: {
|
|
242
|
+
threadId: session.threadId,
|
|
243
|
+
runtimeId: session.currentTurn?.agentType || '',
|
|
244
|
+
},
|
|
245
|
+
}));
|
|
190
246
|
}
|
|
191
247
|
}
|
|
192
248
|
exports.LocalCoreAcpTransport = LocalCoreAcpTransport;
|
|
249
|
+
function resolveTransportCwd(config) {
|
|
250
|
+
if (config.sandbox?.enabled) {
|
|
251
|
+
const proxyCwd = String(config.sandbox.proxyCwd || '').trim();
|
|
252
|
+
if (proxyCwd && (0, node_fs_1.existsSync)(proxyCwd)) {
|
|
253
|
+
return proxyCwd;
|
|
254
|
+
}
|
|
255
|
+
return process.cwd();
|
|
256
|
+
}
|
|
257
|
+
return config.workDir;
|
|
258
|
+
}
|
|
259
|
+
function errorCodeForAcpError(error) {
|
|
260
|
+
const message = String(error?.message || '').toLowerCase();
|
|
261
|
+
if (message.includes('authentication required') || message.includes('api key') || message.includes('oauth')) {
|
|
262
|
+
return 'provider_auth_failed';
|
|
263
|
+
}
|
|
264
|
+
return 'runtime_protocol_error';
|
|
265
|
+
}
|