@kafca/agentdock 0.1.30 → 0.1.33
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/LICENSE.md +73 -0
- package/README.md +15 -0
- package/dist/renderer/assets/{Badge-DlVJI1Ys.js → Badge-VeSLCPPV.js} +1 -1
- package/dist/renderer/assets/{Chat-oa8OjaHQ.js → Chat-DWTQeTgn.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-C-N8KS5C.js → ChatMarkdown-C9gSQIVb.js} +1 -1
- package/dist/renderer/assets/{Config-D9sL_d4D.js → Config-CTA-pZNR.js} +1 -1
- package/dist/renderer/assets/{CronList-Z5JU3DHk.js → CronList-BngBCnFY.js} +1 -1
- package/dist/renderer/assets/{Dashboard-D3BwbG43.js → Dashboard-D4pGvDpc.js} +2 -2
- package/dist/renderer/assets/{EmptyState-QOj765Ul.js → EmptyState-DMf8rzDs.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-J7n01mPu.js → KnowledgeDetail-C1Ym_cHk.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-BFnH0NVk.js → KnowledgeHome-DPRiR72G.js} +1 -1
- package/dist/renderer/assets/{Logs-DfSUifXc.js → Logs-CRHecmzO.js} +1 -1
- package/dist/renderer/assets/{Modal-QjEGhyru.js → Modal-BDhhPv2l.js} +1 -1
- package/dist/renderer/assets/{Page-qdHFSw7x.js → Page-DdDZN7AE.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-DS_rfvhh.js → ProjectDetail-DCsr3LkW.js} +1 -1
- package/dist/renderer/assets/{ProjectList-COtyZd7H.js → ProjectList-Cnm-iLvg.js} +1 -1
- package/dist/renderer/assets/{Select-BQ8mncVu.js → Select-Dw4FCXhJ.js} +1 -1
- package/dist/renderer/assets/{SessionChat-DjVnjuQy.js → SessionChat-O-6abK8x.js} +1 -1
- package/dist/renderer/assets/{SessionList-88dgGZJ8.js → SessionList-5yptvVL9.js} +1 -1
- package/dist/renderer/assets/ThreadChat-CIM_o2HO.js +23 -0
- package/dist/renderer/assets/{Workspace-D_hzSJjX.js → Workspace-D9UeUCNr.js} +1 -1
- package/dist/renderer/assets/{arrow-left-BMpknulW.js → arrow-left-CKfxNOXE.js} +1 -1
- package/dist/renderer/assets/{book-open-CiaOeQbU.js → book-open-CQddlENV.js} +1 -1
- package/dist/renderer/assets/{check-CgwYH4GF.js → check-CZYvOmIS.js} +1 -1
- package/dist/renderer/assets/{chevron-down-BzD2S1OO.js → chevron-down-CVIWFoXF.js} +1 -1
- package/dist/renderer/assets/{circle-BDHD7g7l.js → circle-DSfdQM7k.js} +1 -1
- package/dist/renderer/assets/{desktop-BiR5LPL5.js → desktop-B9KUgeOV.js} +1 -1
- package/dist/renderer/assets/{desktop-BkMW-h5p.js → desktop-O8_6ZCVZ.js} +2 -2
- package/dist/renderer/assets/{funnel-Bruf5FYA.js → funnel-pB5NegZB.js} +1 -1
- package/dist/renderer/assets/{heart-D7Mz04B0.js → heart-BT5laZ_b.js} +1 -1
- package/dist/renderer/assets/{index-CL1e8m3U.js → index-BYyDk28K.js} +2 -2
- package/dist/renderer/assets/{index-gZIRr4_o.js → index-zTUUYax3.js} +1 -1
- package/dist/renderer/assets/{pencil-C6gzDMse.js → pencil-C0thxLi6.js} +1 -1
- package/dist/renderer/assets/{play-DqTXX-Pr.js → play-CmZ0kWtt.js} +1 -1
- package/dist/renderer/assets/{plug-ykmbeaO3.js → plug-CeDQatBe.js} +1 -1
- package/dist/renderer/assets/{plus-DHE60vMX.js → plus-Di__xFOZ.js} +1 -1
- package/dist/renderer/assets/projects-B-pbhhtH.js +1 -0
- package/dist/renderer/assets/{save-CGIvrdQI.js → save-BDatCjfO.js} +1 -1
- package/dist/renderer/assets/{search-D7IFAwyE.js → search-DnTOjP0C.js} +1 -1
- package/dist/renderer/assets/{server-aOsirp7I.js → server-Ey_iHY6m.js} +1 -1
- package/dist/renderer/assets/{session-utils-Dxfp4ohQ.js → session-utils-DWaM7Rkr.js} +1 -1
- package/dist/renderer/assets/{sessions-Db1XPbG2.js → sessions-CYYjLD5I.js} +1 -1
- package/dist/renderer/assets/{shield-check-ChXeQK-d.js → shield-check-Br8BQzcn.js} +1 -1
- package/dist/renderer/assets/{trash-2-CfN-c1zw.js → trash-2-7YD616fw.js} +1 -1
- package/dist/renderer/assets/{user-C7OHaBp4.js → user-BR_5jmr9.js} +1 -1
- package/dist/renderer/assets/{wifi-off-CpaJigye.js → wifi-off-By9QdREz.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +28 -4
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +2 -4
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +102 -15
- package/dist-electron/services/local-ai-core/src/agents/claudecode/behavior.js +5 -0
- package/dist-electron/services/local-ai-core/src/agents/claudecode/definition.js +36 -0
- package/dist-electron/services/local-ai-core/src/agents/claudecode/index.js +15 -0
- package/dist-electron/services/local-ai-core/src/agents/codex/behavior.js +5 -0
- package/dist-electron/services/local-ai-core/src/agents/codex/definition.js +24 -0
- package/dist-electron/services/local-ai-core/src/agents/codex/index.js +15 -0
- package/dist-electron/services/local-ai-core/src/agents/hermes/behavior.js +29 -0
- package/dist-electron/services/local-ai-core/src/agents/hermes/definition.js +22 -0
- package/dist-electron/services/local-ai-core/src/agents/hermes/index.js +15 -0
- package/dist-electron/services/local-ai-core/src/agents/index.js +98 -0
- package/dist-electron/services/local-ai-core/src/agents/localcore-acp/behavior.js +5 -0
- package/dist-electron/services/local-ai-core/src/agents/localcore-acp/definition.js +14 -0
- package/dist-electron/services/local-ai-core/src/agents/localcore-acp/index.js +27 -0
- package/dist-electron/services/local-ai-core/src/agents/opencode/behavior.js +5 -0
- package/dist-electron/services/local-ai-core/src/agents/opencode/definition.js +18 -0
- package/dist-electron/services/local-ai-core/src/agents/opencode/index.js +15 -0
- package/dist-electron/services/local-ai-core/src/agents/opencode/launch.js +119 -0
- package/dist-electron/services/local-ai-core/src/agents/pi/behavior.js +5 -0
- package/dist-electron/services/local-ai-core/src/agents/pi/definition.js +23 -0
- package/dist-electron/services/local-ai-core/src/agents/pi/index.js +15 -0
- package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +139 -0
- package/dist-electron/services/local-ai-core/src/agents/shared/acp-behavior.js +11 -0
- package/dist-electron/services/local-ai-core/src/agents/shared/agent-plugin.js +60 -0
- package/dist-electron/services/local-ai-core/src/agents/shared/definition.js +12 -0
- package/dist-electron/services/local-ai-core/src/agents/shared/launch-utils.js +122 -0
- package/dist-electron/services/local-ai-core/src/agents/shared/progress-replay.js +19 -0
- package/dist-electron/services/local-ai-core/src/agents/shared/replay-prefix.js +68 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +0 -2
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +0 -1
- package/dist-electron/services/local-ai-core/src/cli/lac.js +2 -1
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +17 -11
- package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -130
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +22 -397
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +9 -45
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +9 -4
- package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +62 -1
- package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +2 -12
- package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +16 -7
- package/dist-electron/services/local-ai-core/src/scheduler/local-schedule-adapter.js +10 -2
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-route.js +24 -0
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +15 -6
- package/dist-electron/shared/desktop.js +3 -1
- package/dist-electron/src/pages/Threads/thread-chat-model.js +27 -18
- package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +57 -18
- package/dist-electron/{electron → tests/contracts}/local-core-contracts.test.js +1 -1
- package/dist-electron/{electron → tests/electron}/agent-runtime-detector.test.js +31 -1
- package/dist-electron/{electron → tests/electron}/lac-cli.test.js +6 -3
- package/dist-electron/{electron → tests/electron}/plugin-kernel.test.js +93 -13
- package/dist-electron/{electron → tests/electron}/renderer-packaging.test.js +11 -6
- package/dist-electron/{electron → tests/electron}/runtime-detection-service.test.js +1 -1
- package/dist-electron/{electron → tests/electron}/security-approval-store.test.js +2 -2
- package/dist-electron/{electron → tests/electron}/workspace-task-store.test.js +95 -7
- package/dist-electron/{electron → tests/integration}/channel-content.test.js +2 -2
- package/dist-electron/{electron → tests/integration}/local-core-acp-content.test.js +1 -1
- package/dist-electron/{electron → tests/integration}/local-core-refactor.test.js +437 -15
- package/package.json +3 -2
- package/dist/renderer/assets/ThreadChat-BCdbTxBo.js +0 -23
- package/dist/renderer/assets/projects-Bx5p10th.js +0 -1
- /package/dist-electron/{electron → tests/contracts}/architecture-docs.test.js +0 -0
- /package/dist-electron/{electron → tests/electron}/knowledge-skill-script.test.js +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RuntimeDetectionService = void 0;
|
|
4
4
|
const desktop_js_1 = require("../../../../shared/desktop.js");
|
|
5
|
+
const index_js_1 = require("../agents/index.js");
|
|
5
6
|
const agent_runtime_detector_js_1 = require("./agent-runtime-detector.js");
|
|
6
7
|
const runtime_detection_store_js_1 = require("./runtime-detection-store.js");
|
|
7
8
|
class RuntimeDetectionService {
|
|
@@ -124,16 +125,5 @@ function changedRuntimes(previous, next) {
|
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
127
|
function displayName(agentType) {
|
|
127
|
-
|
|
128
|
-
pi: 'Pi',
|
|
129
|
-
opencode: 'OpenCode',
|
|
130
|
-
codex: 'Codex',
|
|
131
|
-
claudecode: 'Claude Code',
|
|
132
|
-
cursor: 'Cursor',
|
|
133
|
-
gemini: 'Gemini',
|
|
134
|
-
qoder: 'Qoder',
|
|
135
|
-
iflow: 'iFlow',
|
|
136
|
-
[desktop_js_1.LOCALCORE_ACP_AGENT_TYPE]: 'LocalCore ACP',
|
|
137
|
-
};
|
|
138
|
-
return names[agentType] || agentType;
|
|
128
|
+
return (0, index_js_1.resolveAgentRuntimeDefinition)(agentType)?.displayName || agentType;
|
|
139
129
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LarkScheduleAdapter = void 0;
|
|
4
4
|
const scheduled_conversation_executor_js_1 = require("./scheduled-conversation-executor.js");
|
|
5
5
|
const lark_execution_policies_js_1 = require("./lark-execution-policies.js");
|
|
6
|
+
const scheduled_job_route_js_1 = require("./scheduled-job-route.js");
|
|
6
7
|
class LarkScheduleAdapter {
|
|
7
8
|
options;
|
|
8
9
|
executor;
|
|
@@ -31,7 +32,7 @@ class LarkScheduleAdapter {
|
|
|
31
32
|
if (!channelRuntime.sendScheduledMessage) {
|
|
32
33
|
throw new Error('Lark channel runtime does not support scheduled delivery.');
|
|
33
34
|
}
|
|
34
|
-
platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, job.route, execution.replyText);
|
|
35
|
+
platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, (0, scheduled_job_route_js_1.withoutThreadRoute)(job.route), execution.replyText);
|
|
35
36
|
if (!platformMessageId) {
|
|
36
37
|
throw new Error('Lark gateway did not return a message id for scheduled delivery.');
|
|
37
38
|
}
|
|
@@ -46,16 +47,15 @@ class LarkScheduleAdapter {
|
|
|
46
47
|
async resolveThread(job) {
|
|
47
48
|
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
48
49
|
const route = job.route;
|
|
49
|
-
if (route.threadId) {
|
|
50
|
-
await workspaceRouter.getThread(route.threadId);
|
|
51
|
-
return route.threadId;
|
|
52
|
-
}
|
|
53
50
|
const channelId = route.channelId;
|
|
54
51
|
const participantId = route.participantId || '';
|
|
55
|
-
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId);
|
|
56
|
-
if (binding?.thread_id) {
|
|
52
|
+
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, 'lark');
|
|
53
|
+
if (binding?.thread_id && await this.threadExists(binding.thread_id)) {
|
|
57
54
|
return binding.thread_id;
|
|
58
55
|
}
|
|
56
|
+
if (route.threadId && await this.threadExists(route.threadId)) {
|
|
57
|
+
return route.threadId;
|
|
58
|
+
}
|
|
59
59
|
const thread = await workspaceRouter.createThread(job.workspaceId, job.description || `Scheduled ${job.platform} task`);
|
|
60
60
|
const now = new Date().toISOString();
|
|
61
61
|
this.options.store.upsertPlatformThreadBinding({
|
|
@@ -73,5 +73,14 @@ class LarkScheduleAdapter {
|
|
|
73
73
|
}
|
|
74
74
|
return thread.id;
|
|
75
75
|
}
|
|
76
|
+
async threadExists(threadId) {
|
|
77
|
+
try {
|
|
78
|
+
await this.options.getWorkspaceRouter().getThread(threadId);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
76
85
|
}
|
|
77
86
|
exports.LarkScheduleAdapter = LarkScheduleAdapter;
|
|
@@ -33,8 +33,7 @@ class LocalScheduleAdapter {
|
|
|
33
33
|
}
|
|
34
34
|
async resolveThread(job) {
|
|
35
35
|
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
36
|
-
if (job.route.threadId) {
|
|
37
|
-
await workspaceRouter.getThread(job.route.threadId);
|
|
36
|
+
if (job.route.threadId && await this.threadExists(job.route.threadId)) {
|
|
38
37
|
return job.route.threadId;
|
|
39
38
|
}
|
|
40
39
|
const title = `[Scheduled] ${job.description || job.id}`;
|
|
@@ -46,6 +45,15 @@ class LocalScheduleAdapter {
|
|
|
46
45
|
const created = await workspaceRouter.createThread(job.workspaceId, title);
|
|
47
46
|
return created.id;
|
|
48
47
|
}
|
|
48
|
+
async threadExists(threadId) {
|
|
49
|
+
try {
|
|
50
|
+
await this.options.getWorkspaceRouter().getThread(threadId);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
49
57
|
async waitForRun(runId, timeoutMs = 15 * 60 * 1000) {
|
|
50
58
|
const startedAt = Date.now();
|
|
51
59
|
while (Date.now() - startedAt < timeoutMs) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withoutThreadRoute = withoutThreadRoute;
|
|
4
|
+
exports.scheduledJobMatchesPlatformBinding = scheduledJobMatchesPlatformBinding;
|
|
5
|
+
exports.scheduledJobMatchesCliContext = scheduledJobMatchesCliContext;
|
|
6
|
+
function withoutThreadRoute(route) {
|
|
7
|
+
const { threadId: _threadId, ...deliveryRoute } = route;
|
|
8
|
+
return deliveryRoute;
|
|
9
|
+
}
|
|
10
|
+
function scheduledJobMatchesPlatformBinding(job, binding) {
|
|
11
|
+
return (job.workspaceId === binding.workspace_id &&
|
|
12
|
+
job.platform === binding.platform &&
|
|
13
|
+
job.route.channelId === binding.chat_id &&
|
|
14
|
+
String(job.route.participantId || '') === String(binding.platform_user_id || ''));
|
|
15
|
+
}
|
|
16
|
+
function scheduledJobMatchesCliContext(job, context) {
|
|
17
|
+
if (!context.workspaceId || !context.platform || !context.chatId) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return (job.workspaceId === context.workspaceId &&
|
|
21
|
+
job.platform === context.platform &&
|
|
22
|
+
job.route.channelId === context.chatId &&
|
|
23
|
+
String(job.route.participantId || '') === String(context.platformUserId || ''));
|
|
24
|
+
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.WeixinScheduleAdapter = void 0;
|
|
4
4
|
const scheduled_conversation_executor_js_1 = require("./scheduled-conversation-executor.js");
|
|
5
5
|
const weixin_execution_policies_js_1 = require("./weixin-execution-policies.js");
|
|
6
|
+
const scheduled_job_route_js_1 = require("./scheduled-job-route.js");
|
|
6
7
|
class WeixinScheduleAdapter {
|
|
7
8
|
options;
|
|
8
9
|
executor;
|
|
@@ -31,7 +32,7 @@ class WeixinScheduleAdapter {
|
|
|
31
32
|
if (!channelRuntime.sendScheduledMessage) {
|
|
32
33
|
throw new Error('WeChat channel runtime does not support scheduled delivery.');
|
|
33
34
|
}
|
|
34
|
-
platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, job.route, execution.replyText);
|
|
35
|
+
platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, (0, scheduled_job_route_js_1.withoutThreadRoute)(job.route), execution.replyText);
|
|
35
36
|
if (!platformMessageId) {
|
|
36
37
|
throw new Error('WeChat gateway did not return a message id for scheduled delivery.');
|
|
37
38
|
}
|
|
@@ -46,16 +47,15 @@ class WeixinScheduleAdapter {
|
|
|
46
47
|
async resolveThread(job) {
|
|
47
48
|
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
48
49
|
const route = job.route;
|
|
49
|
-
if (route.threadId) {
|
|
50
|
-
await workspaceRouter.getThread(route.threadId);
|
|
51
|
-
return route.threadId;
|
|
52
|
-
}
|
|
53
50
|
const channelId = route.channelId;
|
|
54
51
|
const participantId = route.participantId || '';
|
|
55
52
|
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, 'weixin');
|
|
56
|
-
if (binding?.thread_id) {
|
|
53
|
+
if (binding?.thread_id && await this.threadExists(binding.thread_id)) {
|
|
57
54
|
return binding.thread_id;
|
|
58
55
|
}
|
|
56
|
+
if (route.threadId && await this.threadExists(route.threadId)) {
|
|
57
|
+
return route.threadId;
|
|
58
|
+
}
|
|
59
59
|
const thread = await workspaceRouter.createThread(job.workspaceId, job.description || `Scheduled ${job.platform} task`);
|
|
60
60
|
const now = new Date().toISOString();
|
|
61
61
|
this.options.store.upsertPlatformThreadBinding({
|
|
@@ -74,5 +74,14 @@ class WeixinScheduleAdapter {
|
|
|
74
74
|
}
|
|
75
75
|
return thread.id;
|
|
76
76
|
}
|
|
77
|
+
async threadExists(threadId) {
|
|
78
|
+
try {
|
|
79
|
+
await this.options.getWorkspaceRouter().getThread(threadId);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
77
86
|
}
|
|
78
87
|
exports.WeixinScheduleAdapter = WeixinScheduleAdapter;
|
|
@@ -29,6 +29,7 @@ exports.DESKTOP_AGENT_TYPE_OPTIONS = [
|
|
|
29
29
|
'gemini',
|
|
30
30
|
'qoder',
|
|
31
31
|
'iflow',
|
|
32
|
+
'hermes',
|
|
32
33
|
'localcore-acp',
|
|
33
34
|
];
|
|
34
35
|
exports.DESKTOP_PLATFORM_TYPE_OPTIONS = [
|
|
@@ -56,7 +57,7 @@ exports.DESKTOP_PROVIDER_PRESET_OPTIONS = [
|
|
|
56
57
|
'ollama',
|
|
57
58
|
];
|
|
58
59
|
exports.DESKTOP_PROVIDER_THINKING_OPTIONS = ['', 'enabled', 'disabled'];
|
|
59
|
-
exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['pi', 'opencode', 'codex', 'claudecode', 'acp', 'localcore-acp'];
|
|
60
|
+
exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['pi', 'opencode', 'codex', 'claudecode', 'hermes', 'acp', 'localcore-acp'];
|
|
60
61
|
exports.LOCALCORE_ACP_AGENT_TYPE = 'localcore-acp';
|
|
61
62
|
exports.SCHEDULER_PROTOCOL_INSTRUCTION = [
|
|
62
63
|
'[Scheduler Tools]',
|
|
@@ -242,5 +243,6 @@ function isAcpAgentType(agentType) {
|
|
|
242
243
|
|| normalized === 'opencode'
|
|
243
244
|
|| normalized === 'codex'
|
|
244
245
|
|| normalized === 'claudecode'
|
|
246
|
+
|| normalized === 'hermes'
|
|
245
247
|
|| normalized === exports.LOCALCORE_ACP_AGENT_TYPE;
|
|
246
248
|
}
|
|
@@ -5,7 +5,7 @@ exports.isInternalProgressBridgeKind = isInternalProgressBridgeKind;
|
|
|
5
5
|
exports.isAwaitingInputBridgeStatus = isAwaitingInputBridgeStatus;
|
|
6
6
|
exports.findStreamingPreviewMessage = findStreamingPreviewMessage;
|
|
7
7
|
exports.shouldReplacePreviewWithReply = shouldReplacePreviewWithReply;
|
|
8
|
-
exports.
|
|
8
|
+
exports.shouldAcceptLiveBridgeEvent = shouldAcceptLiveBridgeEvent;
|
|
9
9
|
exports.settlePreviewMessages = settlePreviewMessages;
|
|
10
10
|
exports.finalizeTurnMessageKinds = finalizeTurnMessageKinds;
|
|
11
11
|
exports.extractVisibleMessageContent = extractVisibleMessageContent;
|
|
@@ -50,26 +50,37 @@ function findStreamingPreviewMessage(messages, previewHandle, replyCtx) {
|
|
|
50
50
|
}
|
|
51
51
|
return messages.find((message) => message.preview && message.turnKey === replyCtx);
|
|
52
52
|
}
|
|
53
|
-
function shouldReplacePreviewWithReply(message, replyContent, replyCtx) {
|
|
54
|
-
if (!message.preview ||
|
|
53
|
+
function shouldReplacePreviewWithReply(message, replyContent, replyCtx, replyBridgeKind) {
|
|
54
|
+
if (!message.preview ||
|
|
55
|
+
message.role !== 'assistant' ||
|
|
56
|
+
!replyCtx ||
|
|
57
|
+
message.turnKey !== replyCtx ||
|
|
58
|
+
isInternalProgressBridgeKind(replyBridgeKind) ||
|
|
59
|
+
isInternalProgressBridgeKind(message.bridgeKind)) {
|
|
55
60
|
return false;
|
|
56
61
|
}
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
return Boolean(replyContent && (message.content === replyContent ||
|
|
63
|
+
!message.bridgeKind ||
|
|
64
|
+
message.bridgeKind === 'assistant'));
|
|
59
65
|
}
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!content || !target.startsWith(content)) {
|
|
65
|
-
return target.slice(0, Math.min(target.length, Math.max(1, Math.ceil(target.length / 24))));
|
|
66
|
+
function shouldAcceptLiveBridgeEvent(input) {
|
|
67
|
+
const replyCtx = String(input.event.replyCtx || '').trim();
|
|
68
|
+
if (!replyCtx) {
|
|
69
|
+
return true;
|
|
66
70
|
}
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
const activeRunId = String(input.activeRunId || '').trim();
|
|
72
|
+
const pendingTurn = input.pendingTurn;
|
|
73
|
+
if (pendingTurn && pendingTurn.sessionKey === input.event.sessionKey) {
|
|
74
|
+
const pendingRunId = String(pendingTurn.runId || '').trim();
|
|
75
|
+
if (pendingRunId) {
|
|
76
|
+
return replyCtx === pendingRunId;
|
|
77
|
+
}
|
|
78
|
+
const supersededRunId = String(pendingTurn.supersededRunId || '').trim();
|
|
79
|
+
if (supersededRunId && replyCtx === supersededRunId) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
69
82
|
}
|
|
70
|
-
|
|
71
|
-
const step = remaining > 160 ? 14 : remaining > 80 ? 8 : remaining > 24 ? 4 : 2;
|
|
72
|
-
return target.slice(0, Math.min(target.length, content.length + step));
|
|
83
|
+
return !activeRunId || replyCtx === activeRunId;
|
|
73
84
|
}
|
|
74
85
|
function settlePreviewMessages(messages, turnKey) {
|
|
75
86
|
let changed = false;
|
|
@@ -83,8 +94,6 @@ function settlePreviewMessages(messages, turnKey) {
|
|
|
83
94
|
changed = true;
|
|
84
95
|
return {
|
|
85
96
|
...message,
|
|
86
|
-
content: message.streamTargetContent ?? message.content,
|
|
87
|
-
streamTargetContent: undefined,
|
|
88
97
|
preview: false,
|
|
89
98
|
previewPlainText: false,
|
|
90
99
|
};
|
|
@@ -170,8 +170,7 @@ function createKnowledgeBase(overrides) {
|
|
|
170
170
|
{
|
|
171
171
|
id: 'thought-preview',
|
|
172
172
|
role: 'assistant',
|
|
173
|
-
content: 'checking',
|
|
174
|
-
streamTargetContent: 'checking the request',
|
|
173
|
+
content: 'checking the request',
|
|
175
174
|
kind: 'progress',
|
|
176
175
|
bridgeKind: 'thought',
|
|
177
176
|
order: 1,
|
|
@@ -182,8 +181,7 @@ function createKnowledgeBase(overrides) {
|
|
|
182
181
|
{
|
|
183
182
|
id: 'answer-preview',
|
|
184
183
|
role: 'assistant',
|
|
185
|
-
content: 'Hi',
|
|
186
|
-
streamTargetContent: 'Hi! How can I help you today?',
|
|
184
|
+
content: 'Hi! How can I help you today?',
|
|
187
185
|
kind: 'progress',
|
|
188
186
|
order: 2,
|
|
189
187
|
turnKey: 'run-1',
|
|
@@ -216,8 +214,7 @@ function createKnowledgeBase(overrides) {
|
|
|
216
214
|
const thoughtPreview = {
|
|
217
215
|
id: 'thought-preview',
|
|
218
216
|
role: 'assistant',
|
|
219
|
-
content: 'checking',
|
|
220
|
-
streamTargetContent: 'checking the request',
|
|
217
|
+
content: 'checking the request',
|
|
221
218
|
kind: 'progress',
|
|
222
219
|
bridgeKind: 'thought',
|
|
223
220
|
order: 0,
|
|
@@ -228,8 +225,7 @@ function createKnowledgeBase(overrides) {
|
|
|
228
225
|
const answerPreview = {
|
|
229
226
|
id: 'answer-preview',
|
|
230
227
|
role: 'assistant',
|
|
231
|
-
content: 'Hi',
|
|
232
|
-
streamTargetContent: 'Hi! How can I help you today?',
|
|
228
|
+
content: 'Hi! How can I help you today?',
|
|
233
229
|
kind: 'progress',
|
|
234
230
|
order: 1,
|
|
235
231
|
turnKey: 'run-1',
|
|
@@ -238,6 +234,56 @@ function createKnowledgeBase(overrides) {
|
|
|
238
234
|
};
|
|
239
235
|
strict_1.default.equal((0, thread_chat_model_1.shouldReplacePreviewWithReply)(thoughtPreview, 'Hi! How can I help you today?', 'run-1'), false);
|
|
240
236
|
strict_1.default.equal((0, thread_chat_model_1.shouldReplacePreviewWithReply)(answerPreview, 'Hi! How can I help you today?', 'run-1'), true);
|
|
237
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldReplacePreviewWithReply)(answerPreview, 'Hi! Final answer.', 'run-1'), true);
|
|
238
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldReplacePreviewWithReply)(answerPreview, 'tool result', 'run-1', 'tool'), false);
|
|
239
|
+
});
|
|
240
|
+
(0, node_test_1.default)('shouldAcceptLiveBridgeEvent rejects stale events from the superseded run while a new turn is pending', () => {
|
|
241
|
+
const pendingTurn = {
|
|
242
|
+
sessionKey: 'session-1',
|
|
243
|
+
userOrder: 3,
|
|
244
|
+
supersededRunId: 'run-old',
|
|
245
|
+
};
|
|
246
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldAcceptLiveBridgeEvent)({
|
|
247
|
+
event: { sessionKey: 'session-1', replyCtx: 'run-old' },
|
|
248
|
+
activeRunId: 'run-old',
|
|
249
|
+
pendingTurn,
|
|
250
|
+
}), false);
|
|
251
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldAcceptLiveBridgeEvent)({
|
|
252
|
+
event: { sessionKey: 'session-1', replyCtx: 'run-new' },
|
|
253
|
+
activeRunId: 'run-old',
|
|
254
|
+
pendingTurn,
|
|
255
|
+
}), false);
|
|
256
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldAcceptLiveBridgeEvent)({
|
|
257
|
+
event: { sessionKey: 'session-1', replyCtx: 'run-new' },
|
|
258
|
+
activeRunId: '',
|
|
259
|
+
pendingTurn,
|
|
260
|
+
}), true);
|
|
261
|
+
});
|
|
262
|
+
(0, node_test_1.default)('shouldAcceptLiveBridgeEvent pins live events to the current run once known', () => {
|
|
263
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldAcceptLiveBridgeEvent)({
|
|
264
|
+
event: { sessionKey: 'session-1', replyCtx: 'run-current' },
|
|
265
|
+
activeRunId: 'run-current',
|
|
266
|
+
pendingTurn: null,
|
|
267
|
+
}), true);
|
|
268
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldAcceptLiveBridgeEvent)({
|
|
269
|
+
event: { sessionKey: 'session-1', replyCtx: 'run-stale' },
|
|
270
|
+
activeRunId: 'run-current',
|
|
271
|
+
pendingTurn: null,
|
|
272
|
+
}), false);
|
|
273
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldAcceptLiveBridgeEvent)({
|
|
274
|
+
event: { sessionKey: 'session-1', replyCtx: 'run-current' },
|
|
275
|
+
activeRunId: 'run-current',
|
|
276
|
+
pendingTurn: {
|
|
277
|
+
sessionKey: 'session-1',
|
|
278
|
+
userOrder: 1,
|
|
279
|
+
runId: 'run-current',
|
|
280
|
+
},
|
|
281
|
+
}), true);
|
|
282
|
+
strict_1.default.equal((0, thread_chat_model_1.shouldAcceptLiveBridgeEvent)({
|
|
283
|
+
event: { sessionKey: 'session-1' },
|
|
284
|
+
activeRunId: 'run-current',
|
|
285
|
+
pendingTurn: null,
|
|
286
|
+
}), true);
|
|
241
287
|
});
|
|
242
288
|
(0, node_test_1.default)('finalizeTurnMessageKinds marks only the last non-progress turn message as final', () => {
|
|
243
289
|
const messages = [
|
|
@@ -350,8 +396,7 @@ function createKnowledgeBase(overrides) {
|
|
|
350
396
|
{
|
|
351
397
|
id: 'preview-1',
|
|
352
398
|
role: 'assistant',
|
|
353
|
-
content: '
|
|
354
|
-
streamTargetContent: 'Hello',
|
|
399
|
+
content: 'Hello',
|
|
355
400
|
kind: 'progress',
|
|
356
401
|
order: 1,
|
|
357
402
|
turnKey: 'run-1',
|
|
@@ -361,8 +406,7 @@ function createKnowledgeBase(overrides) {
|
|
|
361
406
|
{
|
|
362
407
|
id: 'preview-2',
|
|
363
408
|
role: 'assistant',
|
|
364
|
-
content: '
|
|
365
|
-
streamTargetContent: 'World',
|
|
409
|
+
content: 'World',
|
|
366
410
|
kind: 'progress',
|
|
367
411
|
order: 2,
|
|
368
412
|
turnKey: 'run-2',
|
|
@@ -373,14 +417,9 @@ function createKnowledgeBase(overrides) {
|
|
|
373
417
|
const settled = (0, thread_chat_model_1.settlePreviewMessages)(messages, 'run-1');
|
|
374
418
|
strict_1.default.equal(settled[0]?.content, 'Hello');
|
|
375
419
|
strict_1.default.equal(settled[0]?.preview, false);
|
|
376
|
-
strict_1.default.equal(settled[1]?.content, '
|
|
420
|
+
strict_1.default.equal(settled[1]?.content, 'World');
|
|
377
421
|
strict_1.default.equal(settled[1]?.preview, true);
|
|
378
422
|
});
|
|
379
|
-
(0, node_test_1.default)('advancePreviewContent moves monotonically toward the target content', () => {
|
|
380
|
-
strict_1.default.equal((0, thread_chat_model_1.advancePreviewContent)('', 'Hello'), 'H');
|
|
381
|
-
strict_1.default.equal((0, thread_chat_model_1.advancePreviewContent)('Hel', 'Hello'), 'Hello');
|
|
382
|
-
strict_1.default.equal((0, thread_chat_model_1.advancePreviewContent)('Mismatch', 'Hello'), 'H');
|
|
383
|
-
});
|
|
384
423
|
(0, node_test_1.default)('tool result card prefers structured tool call fields', () => {
|
|
385
424
|
const card = (0, thread_chat_message_blocks_1.toolCallToResultCard)({
|
|
386
425
|
name: 'bash',
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const node_test_1 = __importDefault(require("node:test"));
|
|
7
7
|
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
-
const index_js_1 = require("
|
|
8
|
+
const index_js_1 = require("../../packages/contracts/src/index.js");
|
|
9
9
|
(0, node_test_1.default)('scheduled job execution mode normalization accepts canonical aliases', () => {
|
|
10
10
|
strict_1.default.equal((0, index_js_1.normalizeScheduledJobExecutionMode)(undefined), 'same-thread');
|
|
11
11
|
strict_1.default.equal((0, index_js_1.normalizeScheduledJobExecutionMode)('same_thread'), 'same-thread');
|
|
@@ -8,7 +8,16 @@ const strict_1 = __importDefault(require("node:assert/strict"));
|
|
|
8
8
|
const node_fs_1 = require("node:fs");
|
|
9
9
|
const node_path_1 = require("node:path");
|
|
10
10
|
const node_os_1 = require("node:os");
|
|
11
|
-
const agent_runtime_detector_js_1 = require("
|
|
11
|
+
const agent_runtime_detector_js_1 = require("../../services/local-ai-core/src/runtime/agent-runtime-detector.js");
|
|
12
|
+
const index_js_1 = require("../../services/local-ai-core/src/agents/index.js");
|
|
13
|
+
(0, node_test_1.default)('agent runtime definitions own runtime detection metadata', () => {
|
|
14
|
+
strict_1.default.deepEqual((0, index_js_1.resolveAgentRuntimeDefinition)('hermes')?.detection?.commandCandidates, ['hermes']);
|
|
15
|
+
strict_1.default.deepEqual((0, index_js_1.resolveAgentRuntimeDefinition)('codex')?.detection?.bundledRuntimes?.[0], {
|
|
16
|
+
packageName: '@zed-industries/codex-acp',
|
|
17
|
+
candidates: ['bin/codex-acp.js'],
|
|
18
|
+
});
|
|
19
|
+
strict_1.default.equal((0, index_js_1.resolveAgentRuntimeDefinition)('localcore-acp')?.detection?.builtin, true);
|
|
20
|
+
});
|
|
12
21
|
(0, node_test_1.default)('agent runtime detector only marks commands present on PATH as installed', () => {
|
|
13
22
|
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agent-runtime-detector-'));
|
|
14
23
|
try {
|
|
@@ -30,6 +39,8 @@ const agent_runtime_detector_js_1 = require("../services/local-ai-core/src/runti
|
|
|
30
39
|
strict_1.default.equal(byType.get('pi')?.status, 'not_installed');
|
|
31
40
|
strict_1.default.equal(byType.get('codex')?.installed, false);
|
|
32
41
|
strict_1.default.equal(byType.get('codex')?.status, 'not_installed');
|
|
42
|
+
strict_1.default.equal(byType.get('hermes')?.installed, false);
|
|
43
|
+
strict_1.default.equal(byType.get('hermes')?.status, 'not_installed');
|
|
33
44
|
strict_1.default.equal(byType.get('localcore-acp')?.installed, true);
|
|
34
45
|
strict_1.default.equal(byType.get('localcore-acp')?.status, 'installed');
|
|
35
46
|
strict_1.default.equal(byType.get('localcore-acp')?.source, 'builtin');
|
|
@@ -179,6 +190,25 @@ const agent_runtime_detector_js_1 = require("../services/local-ai-core/src/runti
|
|
|
179
190
|
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
180
191
|
}
|
|
181
192
|
});
|
|
193
|
+
(0, node_test_1.default)('agent runtime detector reports Hermes when hermes command is available', () => {
|
|
194
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agent-runtime-hermes-version-'));
|
|
195
|
+
try {
|
|
196
|
+
const hermes = (0, node_path_1.join)(dir, 'hermes');
|
|
197
|
+
(0, node_fs_1.writeFileSync)(hermes, '#!/bin/sh\necho "hermes 0.9.1"\n', 'utf8');
|
|
198
|
+
(0, node_fs_1.chmodSync)(hermes, 0o755);
|
|
199
|
+
const hermesRuntime = (0, agent_runtime_detector_js_1.detectInstalledAgentRuntimes)({
|
|
200
|
+
env: { PATH: dir },
|
|
201
|
+
}).find((runtime) => runtime.agentType === 'hermes');
|
|
202
|
+
strict_1.default.equal(hermesRuntime?.status, 'installed');
|
|
203
|
+
strict_1.default.equal(hermesRuntime?.source, 'path');
|
|
204
|
+
strict_1.default.equal(hermesRuntime?.command, hermes);
|
|
205
|
+
strict_1.default.equal(hermesRuntime?.version, '0.9.1');
|
|
206
|
+
strict_1.default.equal(hermesRuntime?.issues.length, 0);
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
210
|
+
}
|
|
211
|
+
});
|
|
182
212
|
(0, node_test_1.default)('agent runtime detector keeps runtime installed when version command fails', () => {
|
|
183
213
|
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agent-runtime-version-fail-'));
|
|
184
214
|
try {
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const node_test_1 = __importDefault(require("node:test"));
|
|
7
7
|
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
8
|
const node_http_1 = require("node:http");
|
|
9
|
-
const lac_js_1 = require("
|
|
9
|
+
const lac_js_1 = require("../../services/local-ai-core/src/cli/lac.js");
|
|
10
10
|
function createIo() {
|
|
11
11
|
let stdout = '';
|
|
12
12
|
let stderr = '';
|
|
@@ -516,7 +516,7 @@ function createIo() {
|
|
|
516
516
|
id: 'job-1',
|
|
517
517
|
workspaceId: '知识库',
|
|
518
518
|
platform: 'lark',
|
|
519
|
-
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1'
|
|
519
|
+
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1' },
|
|
520
520
|
executionMode: 'same-thread',
|
|
521
521
|
triggerType: 'cron',
|
|
522
522
|
cronExpr: '*/2 * * * *',
|
|
@@ -531,7 +531,7 @@ function createIo() {
|
|
|
531
531
|
id: 'job-2',
|
|
532
532
|
workspaceId: '知识库',
|
|
533
533
|
platform: 'lark',
|
|
534
|
-
route: { type: 'channel.chat', channelId: 'chat-2', participantId: 'user-2'
|
|
534
|
+
route: { type: 'channel.chat', channelId: 'chat-2', participantId: 'user-2' },
|
|
535
535
|
executionMode: 'side-thread',
|
|
536
536
|
triggerType: 'cron',
|
|
537
537
|
cronExpr: '0 9 * * *',
|
|
@@ -558,6 +558,9 @@ function createIo() {
|
|
|
558
558
|
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
559
559
|
LOCAL_AI_WORKSPACE_ID: '知识库',
|
|
560
560
|
LOCAL_AI_THREAD_ID: 'thread-1',
|
|
561
|
+
LOCAL_AI_PLATFORM: 'lark',
|
|
562
|
+
LOCAL_AI_CHAT_ID: 'chat-1',
|
|
563
|
+
LOCAL_AI_PLATFORM_USER_ID: 'user-1',
|
|
561
564
|
}, io);
|
|
562
565
|
server.close();
|
|
563
566
|
strict_1.default.equal(exitCode, 0);
|