@kafca/agentdock 0.1.22 → 0.1.23
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 +3 -0
- package/dist/renderer/assets/{Badge-B_rgzxYO.js → Badge-C2K5apfV.js} +1 -1
- package/dist/renderer/assets/{Chat-CYtp6m7T.js → Chat-DI2YeVKb.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-DOBMwa9d.js → ChatMarkdown-DMAr15Oi.js} +1 -1
- package/dist/renderer/assets/{Config-DppMSPHF.js → Config-7rP3EuUf.js} +1 -1
- package/dist/renderer/assets/{CronList-BDtB1SuA.js → CronList-81QslYE8.js} +1 -1
- package/dist/renderer/assets/{Dashboard-iFlRnd7Y.js → Dashboard-Db2T7rSZ.js} +2 -2
- package/dist/renderer/assets/{EmptyState-bKDt_T88.js → EmptyState-BBJ3cTvB.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-CKPhKPIg.js → KnowledgeDetail-Dz_6flG3.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-CFeJre6i.js → KnowledgeHome-DIh046mN.js} +3 -3
- package/dist/renderer/assets/{Logs-CyxSVOFK.js → Logs-BXBtHJLf.js} +1 -1
- package/dist/renderer/assets/{Modal-CxPnk1Ey.js → Modal-BB2Av_Xs.js} +1 -1
- package/dist/renderer/assets/{Page-kU9vubzj.js → Page-DPSdvMgU.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-D9FY9NWZ.js → ProjectDetail-C6EWGvGg.js} +1 -1
- package/dist/renderer/assets/{ProjectList-DIwr2TXg.js → ProjectList-BBo5ygnS.js} +1 -1
- package/dist/renderer/assets/{Select-BaWoz5Dn.js → Select-CNX-Tx_O.js} +1 -1
- package/dist/renderer/assets/{SessionChat-Cm9CW8Zx.js → SessionChat-BIn46jqZ.js} +1 -1
- package/dist/renderer/assets/{SessionList-UPnWlXXO.js → SessionList-CZt6f1Rd.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-YvVsACW3.js → ThreadChat-BotD0gKQ.js} +1 -1
- package/dist/renderer/assets/Workspace-C_4tdpjX.js +14 -0
- package/dist/renderer/assets/{arrow-left-BmZAVGV7.js → arrow-left-cHr5wkpq.js} +1 -1
- package/dist/renderer/assets/{book-open-DZ3GXFgI.js → book-open-4nx5C8T-.js} +1 -1
- package/dist/renderer/assets/{check-CeVSvDCv.js → check-exTS-R-x.js} +1 -1
- package/dist/renderer/assets/{chevron-down-yryuMoQ-.js → chevron-down-DSvxXQa0.js} +1 -1
- package/dist/renderer/assets/{circle-eASsFISH.js → circle-DyvEovdw.js} +1 -1
- package/dist/renderer/assets/desktop-B-KVT10D.js +1 -0
- package/dist/renderer/assets/{desktop-Che1cbpE.js → desktop-CVibRyAw.js} +3 -3
- package/dist/renderer/assets/{funnel-pwAe2Ixp.js → funnel-DA9qVdTy.js} +1 -1
- package/dist/renderer/assets/{heart-B2Sp-bCm.js → heart-DuEV0ZRJ.js} +1 -1
- package/dist/renderer/assets/{index-Cse2Br64.js → index-BgflqkCN.js} +3 -3
- package/dist/renderer/assets/{index-BC3MWbS1.js → index-Biz-aexG.js} +39 -39
- package/dist/renderer/assets/{pencil-BfEunUF3.js → pencil-DBDxeNmO.js} +1 -1
- package/dist/renderer/assets/{play-Dcs9Lj_Z.js → play-IzlP83_7.js} +1 -1
- package/dist/renderer/assets/{plug-B_YschQe.js → plug-CuT-qFnW.js} +1 -1
- package/dist/renderer/assets/{plus-Pqo-cXHQ.js → plus-DEqgkn63.js} +1 -1
- package/dist/renderer/assets/projects-DDtDN1rc.js +1 -0
- package/dist/renderer/assets/{save-BKM5yi1A.js → save-D4sRo07y.js} +1 -1
- package/dist/renderer/assets/{search-BU42h10M.js → search-DbPZLuV8.js} +1 -1
- package/dist/renderer/assets/{server-DA5t3Rtr.js → server-D1jUQmwN.js} +1 -1
- package/dist/renderer/assets/{session-utils-Cr9VhNSq.js → session-utils-Aife8ep2.js} +1 -1
- package/dist/renderer/assets/{sessions-bvV8ZMfX.js → sessions-DaH3H7gC.js} +1 -1
- package/dist/renderer/assets/{shield-check-BeOJKur_.js → shield-check-BGwUFWNr.js} +1 -1
- package/dist/renderer/assets/{trash-2-CQ7HKO3q.js → trash-2-CIFBioBa.js} +1 -1
- package/dist/renderer/assets/{user-CtFjY9SV.js → user-CnKcvHdo.js} +1 -1
- package/dist/renderer/assets/{wifi-off-Ci5m0ysf.js → wifi-off-ClO53WGa.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/electron/local-core-refactor.test.js +505 -0
- package/dist-electron/electron/plugin-kernel.test.js +74 -14
- package/dist-electron/packages/core-sdk/src/index.js +40 -20
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +5 -1
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +55 -3
- package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +210 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/config.js +54 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +212 -471
- package/dist-electron/services/local-ai-core/src/channel/lark/registration.js +50 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +191 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/types.js +2 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/plugin.js +31 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +125 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +141 -324
- package/dist-electron/services/local-ai-core/src/channel/weixin/transport.js +169 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/types.js +2 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +5 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +18 -39
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +18 -39
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +55 -44
- package/dist-electron/services/local-ai-core/src/runtime/server.js +10 -8
- package/dist-electron/shared/desktop.js +10 -0
- package/package.json +1 -1
- package/dist/renderer/assets/Workspace-ST7V8u6T.js +0 -14
- package/dist/renderer/assets/desktop-DkrP_s-b.js +0 -1
- package/dist/renderer/assets/projects-BCj0k_Gy.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z as t}from"./index-Biz-aexG.js";const e=()=>t.get("/projects"),r=o=>t.get(`/projects/${o}`);export{r as g,e as l};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as o}from"./index-
|
|
1
|
+
import{z as o}from"./index-Biz-aexG.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,7 +5,7 @@
|
|
|
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-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-Biz-aexG.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="./assets/index-DFiJR0vv.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-[#f5f5f7] dark:bg-[#151516]">
|
|
@@ -18,6 +18,7 @@ const local_core_weixin_gateway_js_1 = require("../services/local-ai-core/src/ch
|
|
|
18
18
|
const local_core_lark_gateway_js_1 = require("../services/local-ai-core/src/channel/lark/local-core-lark-gateway.js");
|
|
19
19
|
const local_core_acp_turn_coordinator_js_1 = require("../services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js");
|
|
20
20
|
const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/local-core-acp-store.js");
|
|
21
|
+
const workspace_acp_permissions_js_1 = require("../services/local-ai-core/src/acp/workspace-acp-permissions.js");
|
|
21
22
|
(0, node_test_1.default)('ACP tool call update is emitted with its pending tool name', () => {
|
|
22
23
|
const appended = [];
|
|
23
24
|
const emitted = [];
|
|
@@ -71,6 +72,29 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
71
72
|
strict_1.default.equal(emitted.length, 1);
|
|
72
73
|
strict_1.default.equal(emitted[0]?.content, appended[0]?.content);
|
|
73
74
|
});
|
|
75
|
+
(0, node_test_1.default)('ACP permission normalization treats allow_all as allow all', () => {
|
|
76
|
+
strict_1.default.equal((0, workspace_acp_permissions_js_1.normalizePermissionAction)('allow_all'), 'allow all');
|
|
77
|
+
strict_1.default.equal((0, workspace_acp_permissions_js_1.normalizePermissionAction)('allow_always'), 'allow all');
|
|
78
|
+
strict_1.default.equal((0, workspace_acp_permissions_js_1.normalizePermissionAction)('always'), 'allow all');
|
|
79
|
+
strict_1.default.equal((0, workspace_acp_permissions_js_1.normalizePermissionAction)('allow_once'), 'allow');
|
|
80
|
+
});
|
|
81
|
+
(0, node_test_1.default)('ACP permission normalization preserves always-allow option semantics', () => {
|
|
82
|
+
strict_1.default.equal((0, workspace_acp_permissions_js_1.normalizePermissionOptionAction)({
|
|
83
|
+
optionId: 'approve',
|
|
84
|
+
name: 'Always allow',
|
|
85
|
+
kind: 'allow',
|
|
86
|
+
}), 'allow all');
|
|
87
|
+
strict_1.default.equal((0, workspace_acp_permissions_js_1.normalizePermissionOptionAction)({
|
|
88
|
+
optionId: 'allow-all-tools',
|
|
89
|
+
name: '始终允许',
|
|
90
|
+
kind: 'allow',
|
|
91
|
+
}), 'allow all');
|
|
92
|
+
strict_1.default.equal((0, workspace_acp_permissions_js_1.normalizePermissionOptionAction)({
|
|
93
|
+
optionId: 'allow_once',
|
|
94
|
+
name: 'Allow once',
|
|
95
|
+
kind: 'allow',
|
|
96
|
+
}), 'allow');
|
|
97
|
+
});
|
|
74
98
|
(0, node_test_1.default)('ACP tool call running and completed updates share one message id', () => {
|
|
75
99
|
const upserted = [];
|
|
76
100
|
const emitted = [];
|
|
@@ -305,6 +329,55 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
305
329
|
strict_1.default.match(upserted[0]?.content || '', /ls -la ~\/Desktop/);
|
|
306
330
|
strict_1.default.match(upserted[0]?.content || '', /completed - Desktop file list/);
|
|
307
331
|
});
|
|
332
|
+
(0, node_test_1.default)('ACP permission button rows preserve always allow actions', () => {
|
|
333
|
+
const emitted = [];
|
|
334
|
+
const coordinator = new local_core_acp_turn_coordinator_js_1.LocalCoreAcpTurnCoordinator({
|
|
335
|
+
appendMessage: () => { },
|
|
336
|
+
emitBridge: (event) => emitted.push(event),
|
|
337
|
+
updateRunStatus: () => { },
|
|
338
|
+
sendRaw: () => true,
|
|
339
|
+
});
|
|
340
|
+
const session = {
|
|
341
|
+
threadId: 'thread-1',
|
|
342
|
+
bridgeSessionKey: 'session:thread-1',
|
|
343
|
+
currentRunId: 'run-1',
|
|
344
|
+
currentTurn: {
|
|
345
|
+
runId: 'run-1',
|
|
346
|
+
replyCtx: 'run-1',
|
|
347
|
+
previewHandle: 'preview-1',
|
|
348
|
+
assistantText: '',
|
|
349
|
+
typingStarted: true,
|
|
350
|
+
previewStarted: false,
|
|
351
|
+
permission: null,
|
|
352
|
+
},
|
|
353
|
+
pendingPermissionByRun: new Map(),
|
|
354
|
+
loadReplayMode: false,
|
|
355
|
+
schedulerJobCreatedByRun: new Map(),
|
|
356
|
+
};
|
|
357
|
+
coordinator.handleAgentRequest(session, {
|
|
358
|
+
method: 'session/request_permission',
|
|
359
|
+
id: 42,
|
|
360
|
+
params: {
|
|
361
|
+
toolCall: {
|
|
362
|
+
title: 'Terminal',
|
|
363
|
+
parameters: {
|
|
364
|
+
command: 'system_profiler SPHardwareDataType',
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
options: [
|
|
368
|
+
{ optionId: 'approve-once', name: 'Allow once', kind: 'allow' },
|
|
369
|
+
{ optionId: 'approve-always', name: 'Always allow', kind: 'allow' },
|
|
370
|
+
{ optionId: 'reject', name: 'Reject', kind: 'reject' },
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
strict_1.default.deepEqual(emitted[0]?.buttonRows, [[
|
|
375
|
+
{ text: 'allow', data: 'allow' },
|
|
376
|
+
{ text: 'allow all', data: 'allow all' },
|
|
377
|
+
{ text: 'deny', data: 'deny' },
|
|
378
|
+
]]);
|
|
379
|
+
strict_1.default.equal(session.pendingPermissionByRun.get('run-1')?.options[1]?.optionId, 'approve-always');
|
|
380
|
+
});
|
|
308
381
|
(0, node_test_1.default)('ACP bare tool call is flushed before assistant text', () => {
|
|
309
382
|
const appended = [];
|
|
310
383
|
const emitted = [];
|
|
@@ -573,6 +646,81 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
573
646
|
strict_1.default.equal(patchedCards[0]?.text, '💭 先理解问题,再检查代码');
|
|
574
647
|
strict_1.default.deepEqual(storedMessageIds, ['lark-msg-2']);
|
|
575
648
|
});
|
|
649
|
+
(0, node_test_1.default)('lark bridge sends final reply as a separate card after streamed final updates', async () => {
|
|
650
|
+
const createdCards = [];
|
|
651
|
+
const patchedCards = [];
|
|
652
|
+
const storedMessageIds = [];
|
|
653
|
+
const client = {
|
|
654
|
+
im: {
|
|
655
|
+
message: {
|
|
656
|
+
create: async (request) => {
|
|
657
|
+
const messageId = `lark-msg-${createdCards.length + 1}`;
|
|
658
|
+
const card = JSON.parse(String(request.data.content || '{}'));
|
|
659
|
+
createdCards.push({
|
|
660
|
+
messageId,
|
|
661
|
+
text: String(card.elements?.[0]?.content || ''),
|
|
662
|
+
});
|
|
663
|
+
return { data: { message_id: messageId } };
|
|
664
|
+
},
|
|
665
|
+
patch: async (request) => {
|
|
666
|
+
const card = JSON.parse(String(request.data.content || '{}'));
|
|
667
|
+
patchedCards.push({
|
|
668
|
+
messageId: String(request.path.message_id || ''),
|
|
669
|
+
text: String(card.elements?.[0]?.content || ''),
|
|
670
|
+
});
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
676
|
+
store: {
|
|
677
|
+
getPlatformThreadBinding: () => ({
|
|
678
|
+
workspace_id: 'default',
|
|
679
|
+
platform: 'lark',
|
|
680
|
+
chat_id: 'chat-1',
|
|
681
|
+
platform_user_id: 'user-1',
|
|
682
|
+
thread_id: 'thread-1',
|
|
683
|
+
last_platform_message_id: null,
|
|
684
|
+
}),
|
|
685
|
+
updatePlatformThreadMessageId: (_workspaceId, _chatId, _platformUserId, messageId) => {
|
|
686
|
+
storedMessageIds.push(messageId);
|
|
687
|
+
},
|
|
688
|
+
},
|
|
689
|
+
readConfig: async () => null,
|
|
690
|
+
getWorkspaceRouter: () => ({}),
|
|
691
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
692
|
+
});
|
|
693
|
+
const internals = gateway;
|
|
694
|
+
internals.runtime.set('default', {
|
|
695
|
+
workspaceId: 'default',
|
|
696
|
+
enabled: true,
|
|
697
|
+
status: 'running',
|
|
698
|
+
connected: true,
|
|
699
|
+
appId: 'app-1',
|
|
700
|
+
client,
|
|
701
|
+
});
|
|
702
|
+
internals.threadRouting.set('session:thread-1', {
|
|
703
|
+
workspaceId: 'default',
|
|
704
|
+
platformUserId: 'user-1',
|
|
705
|
+
chatId: 'chat-1',
|
|
706
|
+
threadId: 'thread-1',
|
|
707
|
+
});
|
|
708
|
+
await gateway.onBridgeEvent({
|
|
709
|
+
type: 'update_message',
|
|
710
|
+
sessionKey: 'session:thread-1',
|
|
711
|
+
replyCtx: 'run-1',
|
|
712
|
+
content: '流式中的最终回答草稿',
|
|
713
|
+
});
|
|
714
|
+
await gateway.onBridgeEvent({
|
|
715
|
+
type: 'reply',
|
|
716
|
+
sessionKey: 'session:thread-1',
|
|
717
|
+
replyCtx: 'run-1',
|
|
718
|
+
content: '真正最终回答',
|
|
719
|
+
});
|
|
720
|
+
strict_1.default.deepEqual(createdCards.map((card) => card.text), ['流式中的最终回答草稿', '真正最终回答']);
|
|
721
|
+
strict_1.default.equal(patchedCards.length, 0);
|
|
722
|
+
strict_1.default.deepEqual(storedMessageIds, ['lark-msg-1', 'lark-msg-2']);
|
|
723
|
+
});
|
|
576
724
|
(0, node_test_1.default)('lark bridge does not leave typing placeholders or throttle thought updates', async () => {
|
|
577
725
|
const createdCards = [];
|
|
578
726
|
const patchedCards = [];
|
|
@@ -779,6 +927,116 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
779
927
|
strict_1.default.match(patchedCards[0]?.card?.elements?.[0]?.content || '', /工具确认已处理/);
|
|
780
928
|
strict_1.default.equal(patchedCards[0]?.card?.elements?.some((element) => element.tag === 'action'), false);
|
|
781
929
|
});
|
|
930
|
+
(0, node_test_1.default)('lark allow all card action preserves the final reply after tool execution', async () => {
|
|
931
|
+
const createdCards = [];
|
|
932
|
+
const patchedCards = [];
|
|
933
|
+
let nextMessageId = 1;
|
|
934
|
+
let gateway;
|
|
935
|
+
const client = {
|
|
936
|
+
im: {
|
|
937
|
+
message: {
|
|
938
|
+
create: async (request) => {
|
|
939
|
+
const messageId = `card-${nextMessageId++}`;
|
|
940
|
+
createdCards.push({
|
|
941
|
+
messageId,
|
|
942
|
+
card: JSON.parse(String(request.data.content || '{}')),
|
|
943
|
+
});
|
|
944
|
+
return { data: { message_id: messageId } };
|
|
945
|
+
},
|
|
946
|
+
patch: async (request) => {
|
|
947
|
+
patchedCards.push({
|
|
948
|
+
messageId: request.path?.message_id,
|
|
949
|
+
card: JSON.parse(String(request.data.content || '{}')),
|
|
950
|
+
});
|
|
951
|
+
},
|
|
952
|
+
},
|
|
953
|
+
},
|
|
954
|
+
};
|
|
955
|
+
gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
956
|
+
store: {
|
|
957
|
+
getPlatformThreadBinding: () => ({
|
|
958
|
+
workspace_id: 'default',
|
|
959
|
+
platform: 'lark',
|
|
960
|
+
chat_id: 'chat-1',
|
|
961
|
+
platform_user_id: 'user-1',
|
|
962
|
+
thread_id: 'thread-1',
|
|
963
|
+
last_platform_message_id: null,
|
|
964
|
+
}),
|
|
965
|
+
clearPlatformThreadMessageId: () => { },
|
|
966
|
+
updatePlatformThreadMessageId: () => { },
|
|
967
|
+
},
|
|
968
|
+
readConfig: async () => null,
|
|
969
|
+
getWorkspaceRouter: () => ({
|
|
970
|
+
sendThreadAction: async (threadId, action) => {
|
|
971
|
+
strict_1.default.equal(threadId, 'thread-1');
|
|
972
|
+
strict_1.default.equal(action, 'allow all');
|
|
973
|
+
await gateway.onBridgeEvent({
|
|
974
|
+
type: 'typing_start',
|
|
975
|
+
sessionKey: 'session:thread-1',
|
|
976
|
+
replyCtx: 'run-1',
|
|
977
|
+
});
|
|
978
|
+
await gateway.onBridgeEvent({
|
|
979
|
+
type: 'reply',
|
|
980
|
+
sessionKey: 'session:thread-1',
|
|
981
|
+
replyCtx: 'run-1',
|
|
982
|
+
content: '桌面文件列表:AI进展报告_2026年4月.md',
|
|
983
|
+
});
|
|
984
|
+
return { runId: 'run-1' };
|
|
985
|
+
},
|
|
986
|
+
}),
|
|
987
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
988
|
+
});
|
|
989
|
+
const internals = gateway;
|
|
990
|
+
internals.runtime.set('default', {
|
|
991
|
+
workspaceId: 'default',
|
|
992
|
+
enabled: true,
|
|
993
|
+
status: 'running',
|
|
994
|
+
connected: true,
|
|
995
|
+
appId: 'app-1',
|
|
996
|
+
cardActionsEnabled: true,
|
|
997
|
+
client,
|
|
998
|
+
});
|
|
999
|
+
internals.threadRouting.set('session:thread-1', {
|
|
1000
|
+
workspaceId: 'default',
|
|
1001
|
+
platformUserId: 'user-1',
|
|
1002
|
+
chatId: 'chat-1',
|
|
1003
|
+
threadId: 'thread-1',
|
|
1004
|
+
});
|
|
1005
|
+
internals.outboundTurns.set('session:thread-1', {
|
|
1006
|
+
sessionKey: 'session:thread-1',
|
|
1007
|
+
progressMessageIds: {},
|
|
1008
|
+
permissionMessageId: 'permission-msg-1',
|
|
1009
|
+
awaitingPermission: true,
|
|
1010
|
+
processing: true,
|
|
1011
|
+
previewText: '',
|
|
1012
|
+
finalText: '',
|
|
1013
|
+
thinkingSteps: [],
|
|
1014
|
+
toolCalls: [],
|
|
1015
|
+
statusLines: [],
|
|
1016
|
+
buttonRows: [[{ text: '始终允许', data: 'allow all' }]],
|
|
1017
|
+
lastPatchedAt: 0,
|
|
1018
|
+
lastPatchedAtByMessageId: {},
|
|
1019
|
+
});
|
|
1020
|
+
await internals.handleCardActionEvent('default', {
|
|
1021
|
+
event: {
|
|
1022
|
+
action: {
|
|
1023
|
+
value: {
|
|
1024
|
+
action: 'permission_response',
|
|
1025
|
+
response: 'allow all',
|
|
1026
|
+
thread_id: 'thread-1',
|
|
1027
|
+
session_key: 'session:thread-1',
|
|
1028
|
+
},
|
|
1029
|
+
},
|
|
1030
|
+
context: {
|
|
1031
|
+
open_message_id: 'permission-msg-1',
|
|
1032
|
+
},
|
|
1033
|
+
},
|
|
1034
|
+
});
|
|
1035
|
+
strict_1.default.equal(patchedCards[0]?.messageId, 'permission-msg-1');
|
|
1036
|
+
strict_1.default.match(patchedCards[0]?.card?.elements?.[0]?.content || '', /工具确认已处理/);
|
|
1037
|
+
strict_1.default.equal(createdCards.length, 1);
|
|
1038
|
+
strict_1.default.match(createdCards[0]?.card?.elements?.[0]?.content || '', /桌面文件列表/);
|
|
1039
|
+
});
|
|
782
1040
|
(0, node_test_1.default)('lark channel folds tool result output in progress cards', async () => {
|
|
783
1041
|
const createdCards = [];
|
|
784
1042
|
const patchedCards = [];
|
|
@@ -1310,6 +1568,80 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
1310
1568
|
line.includes('sender=user-1')));
|
|
1311
1569
|
strict_1.default.ok(logs.some((line) => line.includes('handling message event') && line.includes('contentBytes=')));
|
|
1312
1570
|
});
|
|
1571
|
+
(0, node_test_1.default)('lark inbound messages use active runtime binding before config refresh catches up', async () => {
|
|
1572
|
+
const users = new Map();
|
|
1573
|
+
const threadBindings = new Map();
|
|
1574
|
+
const createdThreads = [];
|
|
1575
|
+
const sentCards = [];
|
|
1576
|
+
const platformKey = 'lark:lark-hot';
|
|
1577
|
+
const bindingKey = `${platformKey}:chat-1:user-1`;
|
|
1578
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
1579
|
+
store: {
|
|
1580
|
+
expirePendingPairings: () => { },
|
|
1581
|
+
listPendingPairings: () => [],
|
|
1582
|
+
listAuthorizedUsers: () => [...users.values()],
|
|
1583
|
+
getAuthorizedUser: (_workspaceId, platformUserId, requestedPlatform) => users.get(`${requestedPlatform}:${platformUserId}`),
|
|
1584
|
+
createAuthorizedUser: (user) => users.set(`${user.platform}:${user.platform_user_id}`, user),
|
|
1585
|
+
updateAuthorizedUserThread: (_workspaceId, platformUserId, threadId, requestedPlatform) => {
|
|
1586
|
+
users.set(`${requestedPlatform}:${platformUserId}`, { ...users.get(`${requestedPlatform}:${platformUserId}`), thread_id: threadId });
|
|
1587
|
+
},
|
|
1588
|
+
getPlatformThreadBinding: () => threadBindings.get(bindingKey),
|
|
1589
|
+
upsertPlatformThreadBinding: (binding) => threadBindings.set(bindingKey, binding),
|
|
1590
|
+
getLatestRunForThread: () => null,
|
|
1591
|
+
clearPlatformThreadMessageId: () => { },
|
|
1592
|
+
},
|
|
1593
|
+
readConfig: async () => ({ projects: [] }),
|
|
1594
|
+
getWorkspaceRouter: () => ({
|
|
1595
|
+
createThread: async (_workspaceId, title) => {
|
|
1596
|
+
const id = `thread-${createdThreads.length + 1}`;
|
|
1597
|
+
createdThreads.push(`${id}:${title}`);
|
|
1598
|
+
return { id };
|
|
1599
|
+
},
|
|
1600
|
+
getThreadSessionKey: (threadId) => `session:${threadId}`,
|
|
1601
|
+
sendThreadMessage: async () => ({ runId: 'run-1' }),
|
|
1602
|
+
}),
|
|
1603
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
1604
|
+
});
|
|
1605
|
+
const internals = gateway;
|
|
1606
|
+
internals.runtime.set('project-1::lark-hot', {
|
|
1607
|
+
workspaceId: 'project-1',
|
|
1608
|
+
instanceId: 'lark-hot',
|
|
1609
|
+
displayName: 'Lark Hot',
|
|
1610
|
+
platformKey,
|
|
1611
|
+
enabled: true,
|
|
1612
|
+
status: 'running',
|
|
1613
|
+
connected: true,
|
|
1614
|
+
appId: 'app-1',
|
|
1615
|
+
autoApprove: true,
|
|
1616
|
+
cardActionsEnabled: true,
|
|
1617
|
+
client: {
|
|
1618
|
+
im: {
|
|
1619
|
+
message: {
|
|
1620
|
+
create: async (request) => {
|
|
1621
|
+
sentCards.push(JSON.parse(String(request.data.content || '{}')));
|
|
1622
|
+
return { data: { message_id: 'card-1' } };
|
|
1623
|
+
},
|
|
1624
|
+
},
|
|
1625
|
+
messageReaction: {
|
|
1626
|
+
create: async () => ({ data: { reaction_id: 'reaction-1' } }),
|
|
1627
|
+
},
|
|
1628
|
+
},
|
|
1629
|
+
},
|
|
1630
|
+
});
|
|
1631
|
+
await gateway.handleInboundMessage({
|
|
1632
|
+
workspaceId: 'project-1',
|
|
1633
|
+
instanceId: 'lark-hot',
|
|
1634
|
+
platformKey,
|
|
1635
|
+
platformUserId: 'user-1',
|
|
1636
|
+
chatId: 'chat-1',
|
|
1637
|
+
displayName: 'User',
|
|
1638
|
+
text: '/new',
|
|
1639
|
+
messageId: 'msg-1',
|
|
1640
|
+
});
|
|
1641
|
+
strict_1.default.equal(users.get(`${platformKey}:user-1`)?.thread_id, 'thread-2');
|
|
1642
|
+
strict_1.default.deepEqual(createdThreads.map((item) => item.split(':')[0]), ['thread-1', 'thread-2']);
|
|
1643
|
+
strict_1.default.match(sentCards[0]?.elements?.[0]?.content || '', /已开始新会话/);
|
|
1644
|
+
});
|
|
1313
1645
|
(0, node_test_1.default)('ACP skips empty generic running tool updates', () => {
|
|
1314
1646
|
const appended = [];
|
|
1315
1647
|
const emitted = [];
|
|
@@ -1696,6 +2028,8 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
1696
2028
|
ticket: 'ticket-1',
|
|
1697
2029
|
expiresIn: 180,
|
|
1698
2030
|
qrCodeUrl: 'https://liteapp.weixin.qq.com/q/test?qrcode=ticket-1&bot_type=3',
|
|
2031
|
+
instanceId: 'default',
|
|
2032
|
+
displayName: 'WeChat 1',
|
|
1699
2033
|
});
|
|
1700
2034
|
strict_1.default.equal(requests[0]?.url, 'https://ilinkai.weixin.qq.com/ilink/bot/get_bot_qrcode?bot_type=3');
|
|
1701
2035
|
strict_1.default.equal(requests[0]?.headers.has('Authorization'), false);
|
|
@@ -1764,6 +2098,177 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
1764
2098
|
(0, node_fs_1.rmSync)(stateDir, { recursive: true, force: true });
|
|
1765
2099
|
}
|
|
1766
2100
|
});
|
|
2101
|
+
(0, node_test_1.default)('lark channel can request an official app registration QR code without extra setup', async () => {
|
|
2102
|
+
const originalFetch = globalThis.fetch;
|
|
2103
|
+
const requests = [];
|
|
2104
|
+
globalThis.fetch = (async (input, init) => {
|
|
2105
|
+
requests.push({
|
|
2106
|
+
url: String(input),
|
|
2107
|
+
method: init?.method,
|
|
2108
|
+
body: String(init?.body || ''),
|
|
2109
|
+
headers: new Headers(init?.headers),
|
|
2110
|
+
});
|
|
2111
|
+
return new Response(JSON.stringify({
|
|
2112
|
+
device_code: 'device-code-1',
|
|
2113
|
+
user_code: 'ABCD-EFGH',
|
|
2114
|
+
expires_in: 300,
|
|
2115
|
+
interval: 5,
|
|
2116
|
+
}), {
|
|
2117
|
+
status: 200,
|
|
2118
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2119
|
+
});
|
|
2120
|
+
});
|
|
2121
|
+
try {
|
|
2122
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
2123
|
+
store: {},
|
|
2124
|
+
readConfig: async () => ({
|
|
2125
|
+
projects: [
|
|
2126
|
+
{
|
|
2127
|
+
name: 'default',
|
|
2128
|
+
agent: { type: 'localcore-acp', providers: [] },
|
|
2129
|
+
platforms: [{ type: 'lark', options: {} }],
|
|
2130
|
+
},
|
|
2131
|
+
],
|
|
2132
|
+
}),
|
|
2133
|
+
getWorkspaceRouter: () => ({}),
|
|
2134
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
2135
|
+
});
|
|
2136
|
+
const result = await gateway.getQrCode('default');
|
|
2137
|
+
strict_1.default.deepEqual(result, {
|
|
2138
|
+
ticket: 'device-code-1',
|
|
2139
|
+
expiresIn: 300,
|
|
2140
|
+
interval: 5,
|
|
2141
|
+
qrCodeUrl: 'https://open.feishu.cn/page/openclaw?user_code=ABCD-EFGH&from=openclaw',
|
|
2142
|
+
instanceId: 'default',
|
|
2143
|
+
displayName: 'Lark 1',
|
|
2144
|
+
});
|
|
2145
|
+
strict_1.default.equal(requests[0]?.url, 'https://accounts.feishu.cn/oauth/v1/app/registration');
|
|
2146
|
+
strict_1.default.equal(requests[0]?.method, 'POST');
|
|
2147
|
+
strict_1.default.equal(requests[0]?.headers.get('Content-Type'), 'application/x-www-form-urlencoded');
|
|
2148
|
+
strict_1.default.equal(new URLSearchParams(requests[0]?.body).get('action'), 'begin');
|
|
2149
|
+
strict_1.default.equal(new URLSearchParams(requests[0]?.body).get('archetype'), 'PersonalAgent');
|
|
2150
|
+
strict_1.default.equal(new URLSearchParams(requests[0]?.body).get('request_callbacks'), null);
|
|
2151
|
+
}
|
|
2152
|
+
finally {
|
|
2153
|
+
globalThis.fetch = originalFetch;
|
|
2154
|
+
}
|
|
2155
|
+
});
|
|
2156
|
+
(0, node_test_1.default)('lark app registration QR confirmation returns app credentials', async () => {
|
|
2157
|
+
const originalFetch = globalThis.fetch;
|
|
2158
|
+
const requests = [];
|
|
2159
|
+
globalThis.fetch = (async (input, init) => {
|
|
2160
|
+
const url = String(input);
|
|
2161
|
+
requests.push({ url, body: String(init?.body || '') });
|
|
2162
|
+
return new Response(JSON.stringify({
|
|
2163
|
+
client_id: 'cli_lark_1',
|
|
2164
|
+
client_secret: 'secret-1',
|
|
2165
|
+
}), {
|
|
2166
|
+
status: 200,
|
|
2167
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2168
|
+
});
|
|
2169
|
+
});
|
|
2170
|
+
try {
|
|
2171
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
2172
|
+
store: {},
|
|
2173
|
+
readConfig: async () => ({
|
|
2174
|
+
projects: [
|
|
2175
|
+
{
|
|
2176
|
+
name: 'default',
|
|
2177
|
+
agent: { type: 'localcore-acp', providers: [] },
|
|
2178
|
+
platforms: [{ type: 'lark', options: {} }],
|
|
2179
|
+
},
|
|
2180
|
+
],
|
|
2181
|
+
}),
|
|
2182
|
+
getWorkspaceRouter: () => ({}),
|
|
2183
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
2184
|
+
});
|
|
2185
|
+
const result = await gateway.checkQrCodeStatus('default', 'lark-ticket-1');
|
|
2186
|
+
strict_1.default.equal(requests[0]?.url, 'https://accounts.feishu.cn/oauth/v1/app/registration');
|
|
2187
|
+
strict_1.default.equal(new URLSearchParams(requests[0]?.body).get('action'), 'poll');
|
|
2188
|
+
strict_1.default.equal(new URLSearchParams(requests[0]?.body).get('device_code'), 'lark-ticket-1');
|
|
2189
|
+
strict_1.default.deepEqual(result, {
|
|
2190
|
+
status: 'confirmed',
|
|
2191
|
+
credentials: {
|
|
2192
|
+
appId: 'cli_lark_1',
|
|
2193
|
+
appSecret: 'secret-1',
|
|
2194
|
+
},
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
finally {
|
|
2198
|
+
globalThis.fetch = originalFetch;
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
(0, node_test_1.default)('lark channel keeps multiple bot instances in one workspace isolated', async () => {
|
|
2202
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
2203
|
+
store: {
|
|
2204
|
+
expirePendingPairings: () => { },
|
|
2205
|
+
listPendingPairings: () => [],
|
|
2206
|
+
listAuthorizedUsers: () => [],
|
|
2207
|
+
},
|
|
2208
|
+
readConfig: async () => ({
|
|
2209
|
+
projects: [
|
|
2210
|
+
{
|
|
2211
|
+
name: 'default',
|
|
2212
|
+
agent: { type: 'localcore-acp', providers: [] },
|
|
2213
|
+
platforms: [
|
|
2214
|
+
{ type: 'lark', options: { instance_id: 'bot-a', app_id: 'cli_a', app_secret: 'secret-a' } },
|
|
2215
|
+
{ type: 'lark', options: { instance_id: 'bot-b', app_id: 'cli_b', app_secret: 'secret-b' } },
|
|
2216
|
+
],
|
|
2217
|
+
},
|
|
2218
|
+
],
|
|
2219
|
+
}),
|
|
2220
|
+
getWorkspaceRouter: () => ({}),
|
|
2221
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
2222
|
+
});
|
|
2223
|
+
gateway.larkModulePromise = Promise.resolve({
|
|
2224
|
+
AppType: { SelfBuild: 'self-build' },
|
|
2225
|
+
Domain: { Feishu: 'feishu' },
|
|
2226
|
+
LoggerLevel: { info: 'info' },
|
|
2227
|
+
Client: class {
|
|
2228
|
+
},
|
|
2229
|
+
EventDispatcher: class {
|
|
2230
|
+
register() { }
|
|
2231
|
+
},
|
|
2232
|
+
WSClient: class {
|
|
2233
|
+
async start() { }
|
|
2234
|
+
},
|
|
2235
|
+
});
|
|
2236
|
+
await gateway.refreshBindings();
|
|
2237
|
+
const statuses = gateway.listStatuses();
|
|
2238
|
+
strict_1.default.deepEqual(statuses.map((status) => [status.workspaceId, status.instanceId, status.appId, status.status]), [
|
|
2239
|
+
['default', 'bot-a', 'cli_a', 'running'],
|
|
2240
|
+
['default', 'bot-b', 'cli_b', 'running'],
|
|
2241
|
+
]);
|
|
2242
|
+
});
|
|
2243
|
+
(0, node_test_1.default)('weixin channel keeps multiple bot instances in one workspace isolated', async () => {
|
|
2244
|
+
const gateway = new local_core_weixin_gateway_js_1.LocalCoreWeixinGateway({
|
|
2245
|
+
store: {
|
|
2246
|
+
expirePendingPairings: () => { },
|
|
2247
|
+
listPendingPairings: () => [],
|
|
2248
|
+
listAuthorizedUsers: () => [],
|
|
2249
|
+
},
|
|
2250
|
+
readConfig: async () => ({
|
|
2251
|
+
projects: [
|
|
2252
|
+
{
|
|
2253
|
+
name: 'default',
|
|
2254
|
+
agent: { type: 'localcore-acp', providers: [] },
|
|
2255
|
+
platforms: [
|
|
2256
|
+
{ type: 'weixin', options: { instance_id: 'wx-a', account_id: 'account-a' } },
|
|
2257
|
+
{ type: 'weixin', options: { instance_id: 'wx-b', account_id: 'account-b' } },
|
|
2258
|
+
],
|
|
2259
|
+
},
|
|
2260
|
+
],
|
|
2261
|
+
}),
|
|
2262
|
+
getWorkspaceRouter: () => ({}),
|
|
2263
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
2264
|
+
});
|
|
2265
|
+
await gateway.refreshBindings();
|
|
2266
|
+
const statuses = gateway.listStatuses();
|
|
2267
|
+
strict_1.default.deepEqual(statuses.map((status) => [status.workspaceId, status.instanceId, status.appId, status.status]), [
|
|
2268
|
+
['default', 'wx-a', 'account-a', 'stopped'],
|
|
2269
|
+
['default', 'wx-b', 'account-b', 'stopped'],
|
|
2270
|
+
]);
|
|
2271
|
+
});
|
|
1767
2272
|
(0, node_test_1.default)('weixin inbound message handling is idempotent by message identity', async () => {
|
|
1768
2273
|
const sentThreadMessages = [];
|
|
1769
2274
|
const users = new Map();
|