@kafca/agentdock 0.1.47 → 0.1.48
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 +5 -0
- package/dist/renderer/assets/{Badge-BYREM3t3.js → Badge-C92lMj9Q.js} +1 -1
- package/dist/renderer/assets/{Chat-Dtb5X7sB.js → Chat-DqoKCPwz.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-_slLloCh.js → ChatMarkdown-C4psQvmt.js} +1 -1
- package/dist/renderer/assets/{Config-pHichs7H.js → Config-1uk8FQL7.js} +2 -2
- package/dist/renderer/assets/{CronList-CJQMeCjz.js → CronList-DnKCiYWC.js} +1 -1
- package/dist/renderer/assets/{Dashboard-CY77Imde.js → Dashboard-rOAQcJA0.js} +2 -2
- package/dist/renderer/assets/{EmptyState-DCqmct2y.js → EmptyState-bF6Sc61O.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-DFrxa-pv.js → KnowledgeDetail-C5-Dp95R.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-DL-vAfrH.js → KnowledgeHome-DGa1EWXD.js} +2 -2
- package/dist/renderer/assets/{Logs-jw9Uv590.js → Logs-CKKVW2k8.js} +1 -1
- package/dist/renderer/assets/{Modal-ChSm7tk6.js → Modal-DIc9HxD5.js} +3 -3
- package/dist/renderer/assets/{MonitorList-DrEwyS71.js → MonitorList-D2YOJRIX.js} +1 -1
- package/dist/renderer/assets/{Page-DhD-zgMU.js → Page-vZ-_l6Kn.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-BVSjpfpL.js → ProjectDetail-CqTa6kAh.js} +2 -2
- package/dist/renderer/assets/{ProjectList-CHGbTJjk.js → ProjectList-LgDQVVyZ.js} +1 -1
- package/dist/renderer/assets/{Select-rHs9CSam.js → Select-BN2HMOmY.js} +1 -1
- package/dist/renderer/assets/SessionChat-Beco1N1T.js +1 -0
- package/dist/renderer/assets/{SessionList-Mr1uAnRW.js → SessionList-3NkskCJJ.js} +1 -1
- package/dist/renderer/assets/ThreadChat-Ji8pOm5p.js +28 -0
- package/dist/renderer/assets/{Workspace-MRRg8ndJ.js → Workspace-yarrGItB.js} +1 -1
- package/dist/renderer/assets/{arrow-left-BU2NB2LA.js → arrow-left-DNovvfPp.js} +1 -1
- package/dist/renderer/assets/{book-open-D-TGvWwa.js → book-open-CarZFsXv.js} +1 -1
- package/dist/renderer/assets/{bot-IYNh8tH5.js → bot-g16rGMp6.js} +1 -1
- package/dist/renderer/assets/{check-CCZ0JO_S.js → check-DjFX73Zi.js} +1 -1
- package/dist/renderer/assets/{chevron-down-00bRZi15.js → chevron-down-B02YlQS_.js} +1 -1
- package/dist/renderer/assets/{circle-CpQ8x4k_.js → circle-DPfWdG1F.js} +1 -1
- package/dist/renderer/assets/{desktop-D0k2aGSj.js → desktop-DMkue1T6.js} +1 -1
- package/dist/renderer/assets/{funnel-UbcrCBCp.js → funnel-Dy1VL-D9.js} +1 -1
- package/dist/renderer/assets/{heart-DvLsV7tL.js → heart-YjvGwq5-.js} +1 -1
- package/dist/renderer/assets/{index-B2L4G-b_.js → index-CZN1STMc.js} +2 -2
- package/dist/renderer/assets/index-CjCuR6DI.css +11 -0
- package/dist/renderer/assets/{index-dy-g2Bh4.js → index-mvjDN9uV.js} +9 -9
- package/dist/renderer/assets/{pencil-qBYOgW5M.js → pencil-qpMjLIFd.js} +1 -1
- package/dist/renderer/assets/{play-Dn6b4AGj.js → play-CPCcNQcH.js} +1 -1
- package/dist/renderer/assets/{plus-CaApUwEm.js → plus-B76JWGKd.js} +1 -1
- package/dist/renderer/assets/projects-C1nFINjh.js +1 -0
- package/dist/renderer/assets/{save-CN6yvTfD.js → save-DtvrD3W1.js} +1 -1
- package/dist/renderer/assets/{search-Dn2MxYiO.js → search-Ddth-YHH.js} +1 -1
- package/dist/renderer/assets/{server-DpcVLHeh.js → server-D0zmghb3.js} +1 -1
- package/dist/renderer/assets/{session-utils-DnD2Q_y1.js → session-utils-C9oe-21F.js} +1 -1
- package/dist/renderer/assets/{sessions-eK5D4FLt.js → sessions-BXOnLLah.js} +1 -1
- package/dist/renderer/assets/{shield-check-DSSJkacw.js → shield-check-Cv5d_blH.js} +1 -1
- package/dist/renderer/assets/{trash-2-DmYJlEvO.js → trash-2-C2mimX2b.js} +1 -1
- package/dist/renderer/assets/{user-Cvf_uiyQ.js → user-BrLJ4elW.js} +1 -1
- package/dist/renderer/assets/{wifi-off-CCTloj-V.js → wifi-off-DvRJYLbG.js} +1 -1
- package/dist/renderer/index.html +2 -2
- package/dist-electron/packages/core-sdk/src/index.js +4 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +51 -6
- package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +3 -0
- package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +13 -5
- package/dist-electron/services/local-ai-core/src/acp/store/schema.js +1 -0
- package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +3 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/base-channel-gateway.js +4 -1
- package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +14 -3
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +8 -1
- package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +4 -0
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +3 -0
- package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +23 -2
- package/dist-electron/services/local-ai-core/src/thread/thread-slash-command-dispatcher.js +1 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +2 -0
- package/dist-electron/tests/electron/workspace-task-store.test.js +22 -3
- package/dist-electron/tests/integration/local-core-refactor.test.js +177 -0
- package/dist-electron/tests/integration/local-core-routes.test.js +45 -0
- package/package.json +2 -2
- package/dist/renderer/assets/SessionChat-CDc2FNMA.js +0 -1
- package/dist/renderer/assets/ThreadChat-Detu5UfN.js +0 -23
- package/dist/renderer/assets/index-CO4fGqmv.css +0 -11
- package/dist/renderer/assets/projects-BwF5RlNV.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{D as t}from"./index-mvjDN9uV.js";const e=()=>t.get("/projects"),r=o=>t.get(`/projects/${o}`);export{r as g,e as l};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{D as o}from"./index-mvjDN9uV.js";const i=s=>o.get(`/projects/${s}/sessions`),c=(s,e,t)=>o.get(`/projects/${s}/sessions/${e}`,{history_limit:String(t)}),r=(s,e,t)=>o.patch(`/projects/${s}/sessions/${e}`,t),a=(s,e)=>o.delete(`/projects/${s}/sessions/${e}`),p=(s,e)=>o.post(`/projects/${s}/sessions/switch`,e),$=(s,e)=>o.post(`/projects/${s}/send`,e);export{$ as a,a as d,c as g,i as l,r,p as s};
|
package/dist/renderer/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>AgentDock</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-mvjDN9uV.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CjCuR6DI.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-[#f5f5f7] dark:bg-[#151516]">
|
|
12
12
|
<div id="root"></div>
|
|
@@ -85,6 +85,7 @@ exports.createThread = createThread;
|
|
|
85
85
|
exports.getThread = getThread;
|
|
86
86
|
exports.renameThread = renameThread;
|
|
87
87
|
exports.updateThreadKnowledgeBases = updateThreadKnowledgeBases;
|
|
88
|
+
exports.updateThreadMode = updateThreadMode;
|
|
88
89
|
exports.deleteThread = deleteThread;
|
|
89
90
|
exports.sendMessage = sendMessage;
|
|
90
91
|
exports.sendAction = sendAction;
|
|
@@ -498,6 +499,9 @@ async function renameThread(threadId, title) {
|
|
|
498
499
|
async function updateThreadKnowledgeBases(threadId, knowledgeBaseIds) {
|
|
499
500
|
return coreRequest('PATCH', `/threads/${encodeURIComponent(threadId)}/knowledge-bases`, { knowledgeBaseIds });
|
|
500
501
|
}
|
|
502
|
+
async function updateThreadMode(threadId, mode) {
|
|
503
|
+
return coreRequest('PATCH', `/threads/${encodeURIComponent(threadId)}/mode`, { mode });
|
|
504
|
+
}
|
|
501
505
|
async function deleteThread(threadId) {
|
|
502
506
|
return coreRequest('DELETE', `/threads/${encodeURIComponent(threadId)}`);
|
|
503
507
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LocalCoreAcpSessionCoordinator = void 0;
|
|
4
4
|
exports.buildAgentPath = buildAgentPath;
|
|
5
5
|
const node_path_1 = require("node:path");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
6
7
|
const node_os_1 = require("node:os");
|
|
7
8
|
const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
|
|
8
9
|
const env_utils_js_1 = require("../runtime/env-utils.js");
|
|
@@ -290,11 +291,14 @@ exports.LocalCoreAcpSessionCoordinator = LocalCoreAcpSessionCoordinator;
|
|
|
290
291
|
function acpSessionCwd(config) {
|
|
291
292
|
return config.sandbox?.enabled ? config.sandbox.workspaceMountPath : config.workDir;
|
|
292
293
|
}
|
|
293
|
-
function buildAgentPath(existingPath, cliBinDir) {
|
|
294
|
+
function buildAgentPath(existingPath, cliBinDir, options = {}) {
|
|
295
|
+
const platform = options.platform || process.platform;
|
|
296
|
+
const pathDelimiter = platform === 'win32' ? ';' : node_path_1.delimiter;
|
|
294
297
|
const entries = [
|
|
295
298
|
cliBinDir,
|
|
296
|
-
...userBinDirs(),
|
|
297
|
-
...
|
|
299
|
+
...userBinDirs(platform),
|
|
300
|
+
...windowsGitBashDirs(existingPath, platform, options.pathExists || node_fs_1.existsSync),
|
|
301
|
+
...String(existingPath || '').split(pathDelimiter),
|
|
298
302
|
];
|
|
299
303
|
const seen = new Set();
|
|
300
304
|
return entries
|
|
@@ -306,12 +310,53 @@ function buildAgentPath(existingPath, cliBinDir) {
|
|
|
306
310
|
seen.add(entry);
|
|
307
311
|
return true;
|
|
308
312
|
})
|
|
309
|
-
.join(
|
|
313
|
+
.join(pathDelimiter);
|
|
310
314
|
}
|
|
311
|
-
function userBinDirs() {
|
|
312
|
-
if (
|
|
315
|
+
function userBinDirs(platform) {
|
|
316
|
+
if (platform === 'win32') {
|
|
313
317
|
return [];
|
|
314
318
|
}
|
|
315
319
|
const home = process.env.HOME || (0, node_os_1.homedir)();
|
|
316
320
|
return home ? [`${home}/.local/bin`, `${home}/bin`] : [];
|
|
317
321
|
}
|
|
322
|
+
function windowsGitBashDirs(existingPath, platform, pathExists) {
|
|
323
|
+
if (platform !== 'win32') {
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
const pathEntries = String(existingPath || '')
|
|
327
|
+
.split(';')
|
|
328
|
+
.map((entry) => entry.trim())
|
|
329
|
+
.filter(Boolean);
|
|
330
|
+
const gitRoots = new Set();
|
|
331
|
+
for (const entry of pathEntries) {
|
|
332
|
+
const normalized = node_path_1.win32.normalize(entry).replace(/[\\/]+$/, '');
|
|
333
|
+
const base = node_path_1.win32.basename(normalized).toLowerCase();
|
|
334
|
+
const parent = node_path_1.win32.dirname(normalized);
|
|
335
|
+
const parentBase = node_path_1.win32.basename(parent).toLowerCase();
|
|
336
|
+
const grandParent = node_path_1.win32.dirname(parent);
|
|
337
|
+
if (base === 'cmd' && parentBase === 'git') {
|
|
338
|
+
gitRoots.add(parent);
|
|
339
|
+
}
|
|
340
|
+
else if (base === 'bin' && parentBase === 'git') {
|
|
341
|
+
gitRoots.add(parent);
|
|
342
|
+
}
|
|
343
|
+
else if (base === 'bin' && parentBase === 'usr' && node_path_1.win32.basename(grandParent).toLowerCase() === 'git') {
|
|
344
|
+
gitRoots.add(grandParent);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
for (const root of ['C:\\Program Files\\Git', 'C:\\Program Files (x86)\\Git', 'D:\\Program Files\\Git']) {
|
|
348
|
+
gitRoots.add(root);
|
|
349
|
+
}
|
|
350
|
+
const dirs = [];
|
|
351
|
+
for (const root of gitRoots) {
|
|
352
|
+
const binDir = node_path_1.win32.join(root, 'bin');
|
|
353
|
+
if (pathExists(node_path_1.win32.join(binDir, 'bash.exe'))) {
|
|
354
|
+
dirs.push(binDir);
|
|
355
|
+
}
|
|
356
|
+
const usrBinDir = node_path_1.win32.join(root, 'usr', 'bin');
|
|
357
|
+
if (pathExists(node_path_1.win32.join(usrBinDir, 'bash.exe'))) {
|
|
358
|
+
dirs.push(usrBinDir);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return dirs;
|
|
362
|
+
}
|
|
@@ -281,6 +281,9 @@ class LocalCoreAcpStore {
|
|
|
281
281
|
upsertPlatformThreadBinding(input) {
|
|
282
282
|
this.platform.upsertPlatformThreadBinding(input);
|
|
283
283
|
}
|
|
284
|
+
updatePlatformThreadPreferredAgent(workspaceId, chatId, platformUserId, agentType, platform = 'lark') {
|
|
285
|
+
this.platform.updatePlatformThreadPreferredAgent(workspaceId, chatId, platformUserId, agentType, platform);
|
|
286
|
+
}
|
|
284
287
|
updatePlatformThreadMessageId(workspaceId, chatId, platformUserId, messageId, platform = 'lark') {
|
|
285
288
|
this.platform.updatePlatformThreadMessageId(workspaceId, chatId, platformUserId, messageId, platform);
|
|
286
289
|
}
|
|
@@ -107,14 +107,14 @@ class LocalPlatformStore {
|
|
|
107
107
|
}
|
|
108
108
|
getPlatformThreadBinding(workspaceId, chatId, platformUserId, platform = 'lark') {
|
|
109
109
|
return this.db.prepare(`
|
|
110
|
-
SELECT workspace_id, platform, chat_id, platform_user_id, thread_id, last_platform_message_id, created_at, updated_at
|
|
110
|
+
SELECT workspace_id, platform, chat_id, platform_user_id, thread_id, last_platform_message_id, preferred_agent_type, created_at, updated_at
|
|
111
111
|
FROM platform_thread_bindings
|
|
112
112
|
WHERE workspace_id = ? AND platform = ? AND chat_id = ? AND platform_user_id = ?
|
|
113
113
|
`).get(workspaceId, platform, chatId, platformUserId);
|
|
114
114
|
}
|
|
115
115
|
getPlatformThreadBindingByThreadId(threadId) {
|
|
116
116
|
return this.db.prepare(`
|
|
117
|
-
SELECT workspace_id, platform, chat_id, platform_user_id, thread_id, last_platform_message_id, created_at, updated_at
|
|
117
|
+
SELECT workspace_id, platform, chat_id, platform_user_id, thread_id, last_platform_message_id, preferred_agent_type, created_at, updated_at
|
|
118
118
|
FROM platform_thread_bindings
|
|
119
119
|
WHERE thread_id = ?
|
|
120
120
|
ORDER BY updated_at DESC
|
|
@@ -127,13 +127,21 @@ class LocalPlatformStore {
|
|
|
127
127
|
upsertPlatformThreadBinding(input) {
|
|
128
128
|
this.db.prepare(`
|
|
129
129
|
INSERT INTO platform_thread_bindings
|
|
130
|
-
(workspace_id, platform, chat_id, platform_user_id, thread_id, last_platform_message_id, created_at, updated_at)
|
|
131
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
130
|
+
(workspace_id, platform, chat_id, platform_user_id, thread_id, last_platform_message_id, preferred_agent_type, created_at, updated_at)
|
|
131
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
132
132
|
ON CONFLICT(workspace_id, platform, chat_id, platform_user_id) DO UPDATE SET
|
|
133
133
|
thread_id = excluded.thread_id,
|
|
134
134
|
last_platform_message_id = COALESCE(excluded.last_platform_message_id, platform_thread_bindings.last_platform_message_id),
|
|
135
|
+
preferred_agent_type = COALESCE(excluded.preferred_agent_type, platform_thread_bindings.preferred_agent_type),
|
|
135
136
|
updated_at = excluded.updated_at
|
|
136
|
-
`).run(input.workspace_id, input.platform || 'lark', input.chat_id, input.platform_user_id, input.thread_id, input.last_platform_message_id, input.created_at, input.updated_at);
|
|
137
|
+
`).run(input.workspace_id, input.platform || 'lark', input.chat_id, input.platform_user_id, input.thread_id, input.last_platform_message_id, input.preferred_agent_type ?? null, input.created_at, input.updated_at);
|
|
138
|
+
}
|
|
139
|
+
updatePlatformThreadPreferredAgent(workspaceId, chatId, platformUserId, agentType, platform = 'lark') {
|
|
140
|
+
this.db.prepare(`
|
|
141
|
+
UPDATE platform_thread_bindings
|
|
142
|
+
SET preferred_agent_type = ?, updated_at = ?
|
|
143
|
+
WHERE workspace_id = ? AND platform = ? AND chat_id = ? AND platform_user_id = ?
|
|
144
|
+
`).run(agentType, new Date().toISOString(), workspaceId, platform, chatId, platformUserId);
|
|
137
145
|
}
|
|
138
146
|
updatePlatformThreadMessageId(workspaceId, chatId, platformUserId, messageId, platform = 'lark') {
|
|
139
147
|
this.db.prepare(`
|
|
@@ -301,6 +301,7 @@ function ensureLocalCoreAcpSchema(db) {
|
|
|
301
301
|
ensureColumn(db, 'messages', 'tool_call_json', 'TEXT');
|
|
302
302
|
ensureColumn(db, 'messages', 'bridge_kind', 'TEXT');
|
|
303
303
|
ensureColumn(db, 'messages', 'bridge_status', 'TEXT');
|
|
304
|
+
ensureColumn(db, 'platform_thread_bindings', 'preferred_agent_type', 'TEXT');
|
|
304
305
|
ensureColumn(db, 'scheduled_jobs', 'execution_mode', "TEXT NOT NULL DEFAULT 'same-thread'");
|
|
305
306
|
ensureColumn(db, 'scheduled_job_runs', 'platform_message_ids_json', 'TEXT');
|
|
306
307
|
ensureColumn(db, 'scheduled_job_runs', 'delivery_mode', 'TEXT');
|
|
@@ -31,6 +31,7 @@ class LocalThreadStore {
|
|
|
31
31
|
runId: undefined,
|
|
32
32
|
bridgeSessionKey: row.bridge_session_key,
|
|
33
33
|
agentType: row.agent_type,
|
|
34
|
+
agentMode: row.agent_mode,
|
|
34
35
|
}));
|
|
35
36
|
}
|
|
36
37
|
count(workspaceId) {
|
|
@@ -57,6 +58,7 @@ class LocalThreadStore {
|
|
|
57
58
|
excerpt: '',
|
|
58
59
|
bridgeSessionKey,
|
|
59
60
|
agentType,
|
|
61
|
+
agentMode: agentMode || 'default',
|
|
60
62
|
messages: [],
|
|
61
63
|
selectedKnowledgeBaseIds: [],
|
|
62
64
|
pendingPermissionRequest: null,
|
|
@@ -84,6 +86,7 @@ class LocalThreadStore {
|
|
|
84
86
|
excerpt: row.excerpt,
|
|
85
87
|
bridgeSessionKey: row.bridge_session_key,
|
|
86
88
|
agentType: row.agent_type,
|
|
89
|
+
agentMode: row.agent_mode,
|
|
87
90
|
messages: messages.map((message) => ({
|
|
88
91
|
id: message.id,
|
|
89
92
|
role: message.role,
|
|
@@ -35,9 +35,12 @@ class BaseChannelGateway extends node_events_1.EventEmitter {
|
|
|
35
35
|
getLatestRunForThread: (threadId) => options.store.getLatestRunForThread(threadId),
|
|
36
36
|
createAuditEvent: (input) => options.store.createAuditEvent(input),
|
|
37
37
|
getAgentTypes: () => options.getWorkspaceRouter().getAgentTypes(),
|
|
38
|
-
setThreadMode: (threadId, mode) =>
|
|
38
|
+
setThreadMode: async (threadId, mode) => {
|
|
39
|
+
await options.getWorkspaceRouter().setThreadMode(threadId, mode);
|
|
40
|
+
},
|
|
39
41
|
closeThreadSession: (threadId) => options.getWorkspaceRouter().closeThreadSession(threadId),
|
|
40
42
|
interruptRun: (runId) => options.getWorkspaceRouter().interruptRun(runId),
|
|
43
|
+
setChannelPreferredAgent: (input) => options.store.updatePlatformThreadPreferredAgent(input.workspaceId, input.chatId, input.platformUserId, input.agentType, input.platform),
|
|
41
44
|
log: options.log,
|
|
42
45
|
},
|
|
43
46
|
});
|
|
@@ -13,6 +13,11 @@ class ChannelSessionCommandRuntime {
|
|
|
13
13
|
content: input.text,
|
|
14
14
|
defaultTitle: input.defaultTitle,
|
|
15
15
|
defaultAgentType: input.defaultAgentType,
|
|
16
|
+
channel: {
|
|
17
|
+
chatId: input.chatId,
|
|
18
|
+
platformUserId: input.platformUserId,
|
|
19
|
+
platform: input.platformKey,
|
|
20
|
+
},
|
|
16
21
|
});
|
|
17
22
|
if (!result.handled) {
|
|
18
23
|
return { handled: false, threadId: input.currentThreadId };
|
|
@@ -20,7 +25,7 @@ class ChannelSessionCommandRuntime {
|
|
|
20
25
|
let activeThreadId = input.currentThreadId;
|
|
21
26
|
for (const effect of result.effects || []) {
|
|
22
27
|
if (effect.type === 'created_thread') {
|
|
23
|
-
this.
|
|
28
|
+
this.inheritAgentState(input, input.currentThreadId, effect.threadId);
|
|
24
29
|
}
|
|
25
30
|
if (effect.type === 'activate_thread') {
|
|
26
31
|
activeThreadId = effect.threadId;
|
|
@@ -30,11 +35,17 @@ class ChannelSessionCommandRuntime {
|
|
|
30
35
|
await this.options.sendResult(input, result);
|
|
31
36
|
return { handled: true, threadId: activeThreadId, result };
|
|
32
37
|
}
|
|
33
|
-
|
|
34
|
-
const
|
|
38
|
+
inheritAgentState(input, sourceThreadId, targetThreadId) {
|
|
39
|
+
const sourceRow = this.options.store.getThreadRow?.(sourceThreadId);
|
|
40
|
+
const inheritedMode = sourceRow?.agent_mode || '';
|
|
35
41
|
if (inheritedMode && inheritedMode !== 'default') {
|
|
36
42
|
this.options.store.updateThreadAgentMode?.(targetThreadId, inheritedMode);
|
|
37
43
|
}
|
|
44
|
+
const binding = this.options.store.getPlatformThreadBinding?.(input.workspaceId, input.chatId, input.platformUserId, input.platformKey);
|
|
45
|
+
const preferredAgent = binding?.preferred_agent_type || sourceRow?.agent_type || '';
|
|
46
|
+
if (preferredAgent) {
|
|
47
|
+
this.options.store.updateThreadAgentType?.(targetThreadId, preferredAgent);
|
|
48
|
+
}
|
|
38
49
|
}
|
|
39
50
|
activateThread(input, threadId) {
|
|
40
51
|
const now = new Date().toISOString();
|
|
@@ -5,6 +5,7 @@ exports.createWorkspaceRouter = createWorkspaceRouter;
|
|
|
5
5
|
const node_fs_1 = require("node:fs");
|
|
6
6
|
const node_child_process_1 = require("node:child_process");
|
|
7
7
|
const local_core_acp_backend_js_1 = require("../acp/local-core-acp-backend.js");
|
|
8
|
+
const local_core_slash_commands_js_1 = require("../acp/local-core-slash-commands.js");
|
|
8
9
|
const workspace_thread_id_js_1 = require("../thread/workspace-thread-id.js");
|
|
9
10
|
const command_risk_js_1 = require("../security/command-risk.js");
|
|
10
11
|
const workspace_route_config_js_1 = require("./workspace-route-config.js");
|
|
@@ -226,7 +227,13 @@ class WorkspaceRouter {
|
|
|
226
227
|
async setThreadMode(threadId, mode) {
|
|
227
228
|
const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
|
|
228
229
|
await this.getWorkspaceRoute(workspaceId);
|
|
229
|
-
|
|
230
|
+
const normalizedMode = (0, local_core_slash_commands_js_1.normalizeAgentMode)(mode) || (String(mode || '').trim() === '' ? local_core_slash_commands_js_1.DEFAULT_AGENT_MODE : '');
|
|
231
|
+
if (!normalizedMode) {
|
|
232
|
+
throw new Error(`Unknown thread mode: ${mode}`);
|
|
233
|
+
}
|
|
234
|
+
this.store.updateThreadAgentMode(threadId, normalizedMode);
|
|
235
|
+
await this.localCoreAcp.setThreadMode(threadId, normalizedMode);
|
|
236
|
+
return this.getThread(threadId);
|
|
230
237
|
}
|
|
231
238
|
closeThreadSession(threadId) {
|
|
232
239
|
this.localCoreAcp.closeThreadSession(threadId);
|
|
@@ -21,6 +21,10 @@ function registerThreadHandlers(map, workspaceRouter) {
|
|
|
21
21
|
: [];
|
|
22
22
|
(0, server_helpers_js_1.json)(res, 200, await workspaceRouter.updateThreadKnowledgeBases(route.threadId, knowledgeBaseIds));
|
|
23
23
|
});
|
|
24
|
+
map.set('thread.update-mode', async (route, req, res) => {
|
|
25
|
+
const body = await (0, server_helpers_js_1.readJsonBody)(req);
|
|
26
|
+
(0, server_helpers_js_1.json)(res, 200, await workspaceRouter.setThreadMode(route.threadId, String(body.mode || '')));
|
|
27
|
+
});
|
|
24
28
|
map.set('thread.rename', async (route, req, res) => {
|
|
25
29
|
const body = await (0, server_helpers_js_1.readJsonBody)(req);
|
|
26
30
|
(0, server_helpers_js_1.json)(res, 200, await workspaceRouter.renameThread(route.threadId, String(body.title || '')));
|
|
@@ -239,6 +239,9 @@ function parseThreadsRoute(method, segments) {
|
|
|
239
239
|
if (method === 'PATCH' && segments.length === 3 && segments[2] === 'knowledge-bases') {
|
|
240
240
|
return { name: 'thread.update-knowledge-bases', threadId };
|
|
241
241
|
}
|
|
242
|
+
if (method === 'PATCH' && segments.length === 3 && segments[2] === 'mode') {
|
|
243
|
+
return { name: 'thread.update-mode', threadId };
|
|
244
|
+
}
|
|
242
245
|
if (method === 'POST' && segments.length === 3 && segments[2] === 'messages') {
|
|
243
246
|
return { name: 'thread.messages.send', threadId };
|
|
244
247
|
}
|
|
@@ -27,7 +27,7 @@ class ThreadCommandService {
|
|
|
27
27
|
names: ['agent'],
|
|
28
28
|
execute: (command, input) => ({
|
|
29
29
|
handled: true,
|
|
30
|
-
displayText: this.executeAgentCommand(input.threadId, input.workspaceId, command.args, input.defaultAgentType),
|
|
30
|
+
displayText: this.executeAgentCommand(input.threadId, input.workspaceId, command.args, input.defaultAgentType, input.channel),
|
|
31
31
|
}),
|
|
32
32
|
});
|
|
33
33
|
}
|
|
@@ -64,7 +64,7 @@ class ThreadCommandService {
|
|
|
64
64
|
}
|
|
65
65
|
return `已切换到 ${(0, local_core_slash_commands_js_1.formatAgentMode)(mode)} 模式。`;
|
|
66
66
|
}
|
|
67
|
-
executeAgentCommand(threadId, workspaceId, args, defaultAgentType) {
|
|
67
|
+
executeAgentCommand(threadId, workspaceId, args, defaultAgentType, channel) {
|
|
68
68
|
const row = this.options.getThreadRow(threadId);
|
|
69
69
|
const currentAgent = (0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)(row?.agent_type || defaultAgentType);
|
|
70
70
|
const defaultAgent = (0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)(defaultAgentType);
|
|
@@ -84,6 +84,7 @@ class ThreadCommandService {
|
|
|
84
84
|
}
|
|
85
85
|
if (action === 'reset') {
|
|
86
86
|
if (currentAgent === defaultAgent) {
|
|
87
|
+
this.persistChannelPreferredAgent(channel, workspaceId, null);
|
|
87
88
|
return `当前线程已经使用默认 Agent:${defaultAgent}。`;
|
|
88
89
|
}
|
|
89
90
|
const activeRun = this.hasActiveRun(threadId);
|
|
@@ -91,6 +92,7 @@ class ThreadCommandService {
|
|
|
91
92
|
if (!activeRun) {
|
|
92
93
|
this.options.closeThreadSession?.(threadId);
|
|
93
94
|
}
|
|
95
|
+
this.persistChannelPreferredAgent(channel, workspaceId, null);
|
|
94
96
|
this.options.createAuditEvent({
|
|
95
97
|
type: 'agent.changed',
|
|
96
98
|
workspaceId,
|
|
@@ -114,6 +116,7 @@ class ThreadCommandService {
|
|
|
114
116
|
return `Agent "${canonicalAgent}" 当前不可用。\n可用 Agent:${availableAgents.length ? availableAgents.join(', ') : '无'}`;
|
|
115
117
|
}
|
|
116
118
|
if (canonicalAgent === currentAgent) {
|
|
119
|
+
this.persistChannelPreferredAgent(channel, workspaceId, canonicalAgent);
|
|
117
120
|
return `当前线程已经使用 Agent:${canonicalAgent}。`;
|
|
118
121
|
}
|
|
119
122
|
const activeRun = this.hasActiveRun(threadId);
|
|
@@ -121,6 +124,7 @@ class ThreadCommandService {
|
|
|
121
124
|
if (!activeRun) {
|
|
122
125
|
this.options.closeThreadSession?.(threadId);
|
|
123
126
|
}
|
|
127
|
+
this.persistChannelPreferredAgent(channel, workspaceId, canonicalAgent);
|
|
124
128
|
const runningNote = activeRun
|
|
125
129
|
? `\n当前正在运行的任务仍会继续使用 ${currentAgent},下一轮开始生效。`
|
|
126
130
|
: '';
|
|
@@ -133,6 +137,23 @@ class ThreadCommandService {
|
|
|
133
137
|
});
|
|
134
138
|
return `已将当前线程 Agent 切换为 ${canonicalAgent}。\n后续消息将使用 ${canonicalAgent} 处理。${runningNote}`;
|
|
135
139
|
}
|
|
140
|
+
persistChannelPreferredAgent(channel, workspaceId, agentType) {
|
|
141
|
+
if (!channel || !this.options.setChannelPreferredAgent) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
this.options.setChannelPreferredAgent({
|
|
146
|
+
workspaceId,
|
|
147
|
+
chatId: channel.chatId,
|
|
148
|
+
platformUserId: channel.platformUserId,
|
|
149
|
+
platform: channel.platform,
|
|
150
|
+
agentType,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
this.options.log?.(`setChannelPreferredAgent failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
136
157
|
async executeStopCommand(threadId, workspaceId) {
|
|
137
158
|
const latestRun = this.options.getLatestRunForThread(threadId);
|
|
138
159
|
if (!latestRun || !['queued', 'running', 'awaiting_input'].includes(latestRun.status)) {
|
|
@@ -170,6 +170,7 @@ function toChatThreadSummary(project, session) {
|
|
|
170
170
|
updatedAt: session.updated_at,
|
|
171
171
|
excerpt: extractVisibleMessageContent(session.last_message?.content || ''),
|
|
172
172
|
agentType: session.agent_type,
|
|
173
|
+
agentMode: undefined,
|
|
173
174
|
bridgeSessionKey: session.session_key,
|
|
174
175
|
};
|
|
175
176
|
}
|
|
@@ -183,6 +184,7 @@ function toCoreChatThreadSummary(thread) {
|
|
|
183
184
|
updatedAt: thread.updatedAt,
|
|
184
185
|
excerpt: extractVisibleMessageContent(thread.excerpt),
|
|
185
186
|
agentType: thread.agentType,
|
|
187
|
+
agentMode: thread.agentMode,
|
|
186
188
|
bridgeSessionKey: thread.bridgeSessionKey,
|
|
187
189
|
};
|
|
188
190
|
}
|
|
@@ -585,7 +585,7 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
585
585
|
process.env.HOME = '/home/agentdock-test';
|
|
586
586
|
try {
|
|
587
587
|
const existingPath = ['/usr/bin', '/bin'].join(node_path_1.delimiter);
|
|
588
|
-
const path = (0, local_core_acp_session_coordinator_js_1.buildAgentPath)(existingPath, '/opt/agentdock/bin');
|
|
588
|
+
const path = (0, local_core_acp_session_coordinator_js_1.buildAgentPath)(existingPath, '/opt/agentdock/bin', { pathExists: () => false });
|
|
589
589
|
const expectedEntries = process.platform === 'win32'
|
|
590
590
|
? ['/opt/agentdock/bin', '/usr/bin', '/bin']
|
|
591
591
|
: ['/opt/agentdock/bin', '/home/agentdock-test/.local/bin', '/home/agentdock-test/bin', '/usr/bin', '/bin'];
|
|
@@ -600,6 +600,21 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
600
600
|
}
|
|
601
601
|
}
|
|
602
602
|
});
|
|
603
|
+
(0, node_test_1.default)('ACP runtime PATH adds Git Bash bin when Windows PATH only has Git cmd', () => {
|
|
604
|
+
const existingPath = [
|
|
605
|
+
'C:\\Windows\\System32',
|
|
606
|
+
'D:\\Program Files\\Git\\cmd',
|
|
607
|
+
].join(';');
|
|
608
|
+
const path = (0, local_core_acp_session_coordinator_js_1.buildAgentPath)(existingPath, undefined, {
|
|
609
|
+
platform: 'win32',
|
|
610
|
+
pathExists: (candidate) => candidate === 'D:\\Program Files\\Git\\bin\\bash.exe',
|
|
611
|
+
});
|
|
612
|
+
strict_1.default.equal(path, [
|
|
613
|
+
'D:\\Program Files\\Git\\bin',
|
|
614
|
+
'C:\\Windows\\System32',
|
|
615
|
+
'D:\\Program Files\\Git\\cmd',
|
|
616
|
+
].join(';'));
|
|
617
|
+
});
|
|
603
618
|
(0, node_test_1.default)('ACP runtime reads Windows Path env regardless of key casing', () => {
|
|
604
619
|
strict_1.default.equal((0, env_utils_js_1.getPathEnv)({ Path: 'C:\\Windows\\System32;C:\\Program Files\\nodejs' }), 'C:\\Windows\\System32;C:\\Program Files\\nodejs');
|
|
605
620
|
strict_1.default.equal((0, env_utils_js_1.getPathEnv)({ PATH: '/usr/bin:/bin' }), '/usr/bin:/bin');
|
|
@@ -635,8 +650,9 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
635
650
|
});
|
|
636
651
|
(0, node_test_1.default)('ACP scheduled session can override permission mode without changing thread mode', async () => {
|
|
637
652
|
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-permission-mode-'));
|
|
653
|
+
let store = null;
|
|
638
654
|
try {
|
|
639
|
-
|
|
655
|
+
store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
|
|
640
656
|
const thread = store.createThread('workspace-a', 'Thread');
|
|
641
657
|
const capturedSessionNewParams = [];
|
|
642
658
|
let closeCount = 0;
|
|
@@ -702,13 +718,15 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
702
718
|
});
|
|
703
719
|
}
|
|
704
720
|
finally {
|
|
721
|
+
store?.close();
|
|
705
722
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
706
723
|
}
|
|
707
724
|
});
|
|
708
725
|
(0, node_test_1.default)('ACP sandbox sessions use container workspace cwd', async () => {
|
|
709
726
|
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'sandbox-session-cwd-'));
|
|
727
|
+
let store = null;
|
|
710
728
|
try {
|
|
711
|
-
|
|
729
|
+
store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
|
|
712
730
|
const thread = store.createThread('workspace-a', 'Thread');
|
|
713
731
|
let sessionNewParams;
|
|
714
732
|
const coordinator = new local_core_acp_session_coordinator_js_1.LocalCoreAcpSessionCoordinator({
|
|
@@ -779,6 +797,7 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
779
797
|
strict_1.default.equal(sessionNewParams?.cwd, '/workspace');
|
|
780
798
|
}
|
|
781
799
|
finally {
|
|
800
|
+
store?.close();
|
|
782
801
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
783
802
|
}
|
|
784
803
|
});
|