@kafca/agentdock 0.1.20 → 0.1.22
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 +13 -0
- package/dist/renderer/assets/{Badge-C1f8JpRb.js → Badge-B_rgzxYO.js} +1 -1
- package/dist/renderer/assets/{Chat-S50iFg3I.js → Chat-CYtp6m7T.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-VWL9Vnpz.js → ChatMarkdown-DOBMwa9d.js} +1 -1
- package/dist/renderer/assets/{Config-Yc9ExUI6.js → Config-DppMSPHF.js} +2 -2
- package/dist/renderer/assets/CronList-BDtB1SuA.js +1 -0
- package/dist/renderer/assets/{Dashboard-CzXCvZVR.js → Dashboard-iFlRnd7Y.js} +2 -2
- package/dist/renderer/assets/{EmptyState-9FbY2o6z.js → EmptyState-bKDt_T88.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-D_BDc4Zt.js → KnowledgeDetail-CKPhKPIg.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-DsUA_BCR.js → KnowledgeHome-CFeJre6i.js} +3 -3
- package/dist/renderer/assets/Logs-CyxSVOFK.js +1 -0
- package/dist/renderer/assets/{Modal-Bt5VBC6S.js → Modal-CxPnk1Ey.js} +1 -1
- package/dist/renderer/assets/{Page-Da_Kc6Qm.js → Page-kU9vubzj.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-B4Ps80yv.js → ProjectDetail-D9FY9NWZ.js} +1 -1
- package/dist/renderer/assets/{ProjectList-BWTP9npz.js → ProjectList-DIwr2TXg.js} +1 -1
- package/dist/renderer/assets/{Select-DWs3hVUh.js → Select-BaWoz5Dn.js} +2 -7
- package/dist/renderer/assets/SessionChat-Cm9CW8Zx.js +1 -0
- package/dist/renderer/assets/SessionList-UPnWlXXO.js +1 -0
- package/dist/renderer/assets/{ThreadChat-nhnikHnk.js → ThreadChat-YvVsACW3.js} +7 -7
- package/dist/renderer/assets/{Workspace-pq_JYdTN.js → Workspace-ST7V8u6T.js} +2 -2
- package/dist/renderer/assets/{arrow-left-CR39hNvq.js → arrow-left-BmZAVGV7.js} +1 -1
- package/dist/renderer/assets/{book-open-Bot2WKl8.js → book-open-DZ3GXFgI.js} +1 -1
- package/dist/renderer/assets/{check-Drbl2nU3.js → check-CeVSvDCv.js} +1 -1
- package/dist/renderer/assets/chevron-down-yryuMoQ-.js +6 -0
- package/dist/renderer/assets/{circle-BXFfAwnA.js → circle-eASsFISH.js} +1 -1
- package/dist/renderer/assets/desktop-Che1cbpE.js +4 -0
- package/dist/renderer/assets/desktop-DkrP_s-b.js +1 -0
- package/dist/renderer/assets/{funnel-BNKYan_N.js → funnel-pwAe2Ixp.js} +1 -1
- package/dist/renderer/assets/{heart-wUOSwQE-.js → heart-B2Sp-bCm.js} +1 -1
- package/dist/renderer/assets/{index-DT5la73R.js → index-BC3MWbS1.js} +3 -3
- package/dist/renderer/assets/{index-CmOphqrf.js → index-Cse2Br64.js} +1 -1
- package/dist/renderer/assets/{index-3CzgyQYB.css → index-DFiJR0vv.css} +1 -1
- package/dist/renderer/assets/{pencil-D7-8ggue.js → pencil-BfEunUF3.js} +1 -1
- package/dist/renderer/assets/{play-BCYOAfet.js → play-Dcs9Lj_Z.js} +1 -1
- package/dist/renderer/assets/{plug-Dsik74Yl.js → plug-B_YschQe.js} +1 -1
- package/dist/renderer/assets/{plus-CKrU26_l.js → plus-Pqo-cXHQ.js} +1 -1
- package/dist/renderer/assets/projects-BCj0k_Gy.js +1 -0
- package/dist/renderer/assets/{save-q7M2_eAl.js → save-BKM5yi1A.js} +1 -1
- package/dist/renderer/assets/{search-BptY4_MT.js → search-BU42h10M.js} +1 -1
- package/dist/renderer/assets/{server-DSSEF0D8.js → server-DA5t3Rtr.js} +1 -1
- package/dist/renderer/assets/{session-utils-BFuqPZ5x.js → session-utils-Cr9VhNSq.js} +1 -1
- package/dist/renderer/assets/{sessions-CrWo3g3u.js → sessions-bvV8ZMfX.js} +1 -1
- package/dist/renderer/assets/{shield-check-CCU722RQ.js → shield-check-BeOJKur_.js} +1 -1
- package/dist/renderer/assets/{trash-2-DaeeiV8x.js → trash-2-CQ7HKO3q.js} +1 -1
- package/dist/renderer/assets/{user-Bkz8J7Yw.js → user-CtFjY9SV.js} +1 -1
- package/dist/renderer/assets/{wifi-off-P8xdIOHU.js → wifi-off-Ci5m0ysf.js} +1 -1
- package/dist/renderer/index.html +2 -2
- package/dist-electron/electron/agent-runtime-detector.test.js +11 -0
- package/dist-electron/electron/local-core-refactor.test.js +403 -3
- package/dist-electron/electron/plugin-kernel.test.js +43 -9
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +9 -9
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +60 -0
- package/dist-electron/services/local-ai-core/src/{gateway → channel/lark}/local-core-lark-gateway.js +371 -13
- package/dist-electron/services/local-ai-core/src/channel/shared/file-utils.js +33 -0
- package/dist-electron/services/local-ai-core/src/{gateway → channel/weixin}/local-core-weixin-gateway.js +238 -3
- package/dist-electron/services/local-ai-core/src/cli/lac.js +41 -1
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +2 -1
- package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +1 -1
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +1 -1
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +19 -8
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +23 -12
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +41 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +10 -0
- package/dist-electron/shared/desktop.js +17 -2
- package/package.json +2 -1
- package/dist/renderer/assets/CronList-DTboWazi.js +0 -1
- package/dist/renderer/assets/Logs-DDAmR67f.js +0 -1
- package/dist/renderer/assets/SessionChat-DOhUnOfH.js +0 -1
- package/dist/renderer/assets/SessionList-ChZYFXuo.js +0 -1
- package/dist/renderer/assets/desktop-5k3W66fH.js +0 -1
- package/dist/renderer/assets/desktop-D4Z7M9RM.js +0 -3
- package/dist/renderer/assets/projects-CGDtNb0M.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{z as o}from"./index-BC3MWbS1.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-BC3MWbS1.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DFiJR0vv.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-[#f5f5f7] dark:bg-[#151516]">
|
|
12
12
|
<div id="root"></div>
|
|
@@ -14,9 +14,11 @@ const agent_runtime_detector_js_1 = require("../services/local-ai-core/src/runti
|
|
|
14
14
|
try {
|
|
15
15
|
const opencode = (0, node_path_1.join)(dir, 'opencode');
|
|
16
16
|
(0, node_fs_1.writeFileSync)(opencode, '#!/bin/sh\nexit 0\n', 'utf8');
|
|
17
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, 'package.json'), '{}\n', 'utf8');
|
|
17
18
|
(0, node_fs_1.chmodSync)(opencode, 0o755);
|
|
18
19
|
const runtimes = (0, agent_runtime_detector_js_1.detectInstalledAgentRuntimes)({
|
|
19
20
|
env: { PATH: dir },
|
|
21
|
+
requireFrom: (0, node_path_1.join)(dir, 'package.json'),
|
|
20
22
|
});
|
|
21
23
|
const byType = new Map(runtimes.map((runtime) => [runtime.agentType, runtime]));
|
|
22
24
|
strict_1.default.equal(byType.get('opencode')?.installed, true);
|
|
@@ -34,6 +36,15 @@ const agent_runtime_detector_js_1 = require("../services/local-ai-core/src/runti
|
|
|
34
36
|
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
35
37
|
}
|
|
36
38
|
});
|
|
39
|
+
(0, node_test_1.default)('agent runtime detector reports bundled codex ACP when available', () => {
|
|
40
|
+
const codex = (0, agent_runtime_detector_js_1.detectInstalledAgentRuntimes)({
|
|
41
|
+
env: { PATH: '' },
|
|
42
|
+
}).find((runtime) => runtime.agentType === 'codex');
|
|
43
|
+
strict_1.default.equal(codex?.installed, true);
|
|
44
|
+
strict_1.default.equal(codex?.status, 'installed');
|
|
45
|
+
strict_1.default.equal(codex?.source, 'bundled');
|
|
46
|
+
strict_1.default.match(codex?.command || '', /@zed-industries[/\\]codex-acp[/\\]bin[/\\]codex-acp\.js$/);
|
|
47
|
+
});
|
|
37
48
|
(0, node_test_1.default)('agent runtime detector honors configured project commands', () => {
|
|
38
49
|
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agent-runtime-config-'));
|
|
39
50
|
try {
|
|
@@ -8,13 +8,14 @@ const strict_1 = __importDefault(require("node:assert/strict"));
|
|
|
8
8
|
const node_fs_1 = require("node:fs");
|
|
9
9
|
const node_os_1 = require("node:os");
|
|
10
10
|
const node_path_1 = require("node:path");
|
|
11
|
+
const node_stream_1 = require("node:stream");
|
|
11
12
|
const local_core_acp_response_processor_js_1 = require("../services/local-ai-core/src/acp/local-core-acp-response-processor.js");
|
|
12
13
|
const scheduled_conversation_executor_js_1 = require("../services/local-ai-core/src/scheduler/scheduled-conversation-executor.js");
|
|
13
14
|
const scheduler_run_lifecycle_js_1 = require("../services/local-ai-core/src/scheduler/scheduler-run-lifecycle.js");
|
|
14
15
|
const lark_execution_policies_js_1 = require("../services/local-ai-core/src/scheduler/lark-execution-policies.js");
|
|
15
16
|
const local_schedule_adapter_js_1 = require("../services/local-ai-core/src/scheduler/local-schedule-adapter.js");
|
|
16
|
-
const local_core_weixin_gateway_js_1 = require("../services/local-ai-core/src/
|
|
17
|
-
const local_core_lark_gateway_js_1 = require("../services/local-ai-core/src/
|
|
17
|
+
const local_core_weixin_gateway_js_1 = require("../services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js");
|
|
18
|
+
const local_core_lark_gateway_js_1 = require("../services/local-ai-core/src/channel/lark/local-core-lark-gateway.js");
|
|
18
19
|
const local_core_acp_turn_coordinator_js_1 = require("../services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js");
|
|
19
20
|
const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/local-core-acp-store.js");
|
|
20
21
|
(0, node_test_1.default)('ACP tool call update is emitted with its pending tool name', () => {
|
|
@@ -668,6 +669,7 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
668
669
|
});
|
|
669
670
|
(0, node_test_1.default)('lark permission requests render as clickable card buttons', async () => {
|
|
670
671
|
const createdCards = [];
|
|
672
|
+
const patchedCards = [];
|
|
671
673
|
const threadActions = [];
|
|
672
674
|
const client = {
|
|
673
675
|
im: {
|
|
@@ -676,7 +678,12 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
676
678
|
createdCards.push(JSON.parse(String(request.data.content || '{}')));
|
|
677
679
|
return { data: { message_id: 'permission-msg-1' } };
|
|
678
680
|
},
|
|
679
|
-
patch: async () => {
|
|
681
|
+
patch: async (request) => {
|
|
682
|
+
patchedCards.push({
|
|
683
|
+
messageId: request.path?.message_id,
|
|
684
|
+
card: JSON.parse(String(request.data.content || '{}')),
|
|
685
|
+
});
|
|
686
|
+
},
|
|
680
687
|
},
|
|
681
688
|
},
|
|
682
689
|
};
|
|
@@ -756,13 +763,134 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
756
763
|
action: 'permission_response',
|
|
757
764
|
response: 'allow all',
|
|
758
765
|
thread_id: 'thread-1',
|
|
766
|
+
session_key: 'session:thread-1',
|
|
759
767
|
},
|
|
760
768
|
},
|
|
769
|
+
context: {
|
|
770
|
+
open_message_id: 'permission-msg-1',
|
|
771
|
+
},
|
|
761
772
|
},
|
|
762
773
|
});
|
|
763
774
|
strict_1.default.deepEqual(threadActions, [
|
|
764
775
|
{ threadId: 'thread-1', action: 'allow all' },
|
|
765
776
|
]);
|
|
777
|
+
strict_1.default.equal(patchedCards.length, 1);
|
|
778
|
+
strict_1.default.equal(patchedCards[0]?.messageId, 'permission-msg-1');
|
|
779
|
+
strict_1.default.match(patchedCards[0]?.card?.elements?.[0]?.content || '', /工具确认已处理/);
|
|
780
|
+
strict_1.default.equal(patchedCards[0]?.card?.elements?.some((element) => element.tag === 'action'), false);
|
|
781
|
+
});
|
|
782
|
+
(0, node_test_1.default)('lark channel folds tool result output in progress cards', async () => {
|
|
783
|
+
const createdCards = [];
|
|
784
|
+
const patchedCards = [];
|
|
785
|
+
const client = {
|
|
786
|
+
im: {
|
|
787
|
+
message: {
|
|
788
|
+
create: async (request) => {
|
|
789
|
+
createdCards.push(JSON.parse(String(request.data.content || '{}')));
|
|
790
|
+
return { data: { message_id: 'tool-msg-1' } };
|
|
791
|
+
},
|
|
792
|
+
patch: async (request) => {
|
|
793
|
+
patchedCards.push(JSON.parse(String(request.data.content || '{}')));
|
|
794
|
+
},
|
|
795
|
+
},
|
|
796
|
+
},
|
|
797
|
+
};
|
|
798
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
799
|
+
store: {
|
|
800
|
+
getPlatformThreadBinding: () => ({
|
|
801
|
+
workspace_id: 'default',
|
|
802
|
+
platform: 'lark',
|
|
803
|
+
chat_id: 'chat-1',
|
|
804
|
+
platform_user_id: 'user-1',
|
|
805
|
+
thread_id: 'thread-1',
|
|
806
|
+
last_platform_message_id: null,
|
|
807
|
+
}),
|
|
808
|
+
},
|
|
809
|
+
readConfig: async () => null,
|
|
810
|
+
getWorkspaceRouter: () => ({}),
|
|
811
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
812
|
+
});
|
|
813
|
+
const internals = gateway;
|
|
814
|
+
internals.runtime.set('default', {
|
|
815
|
+
workspaceId: 'default',
|
|
816
|
+
enabled: true,
|
|
817
|
+
status: 'running',
|
|
818
|
+
connected: true,
|
|
819
|
+
appId: 'app-1',
|
|
820
|
+
client,
|
|
821
|
+
});
|
|
822
|
+
internals.threadRouting.set('session:thread-1', {
|
|
823
|
+
workspaceId: 'default',
|
|
824
|
+
platformUserId: 'user-1',
|
|
825
|
+
chatId: 'chat-1',
|
|
826
|
+
threadId: 'thread-1',
|
|
827
|
+
});
|
|
828
|
+
await gateway.onBridgeEvent({
|
|
829
|
+
type: 'reply',
|
|
830
|
+
sessionKey: 'session:thread-1',
|
|
831
|
+
replyCtx: 'run-1',
|
|
832
|
+
messageId: 'tool-1',
|
|
833
|
+
content: '🔧 Terminal: ls - completed - secret terminal output',
|
|
834
|
+
});
|
|
835
|
+
const text = createdCards[0]?.elements?.[0]?.content || patchedCards[0]?.elements?.[0]?.content || '';
|
|
836
|
+
strict_1.default.match(text, /Terminal: ls - completed/);
|
|
837
|
+
strict_1.default.doesNotMatch(text, /secret terminal output/);
|
|
838
|
+
});
|
|
839
|
+
(0, node_test_1.default)('lark card action message id can be extracted from full callback payload', async () => {
|
|
840
|
+
const patchedCards = [];
|
|
841
|
+
const threadActions = [];
|
|
842
|
+
const client = {
|
|
843
|
+
im: {
|
|
844
|
+
message: {
|
|
845
|
+
patch: async (request) => {
|
|
846
|
+
patchedCards.push({
|
|
847
|
+
messageId: request.path?.message_id,
|
|
848
|
+
card: JSON.parse(String(request.data.content || '{}')),
|
|
849
|
+
});
|
|
850
|
+
},
|
|
851
|
+
},
|
|
852
|
+
},
|
|
853
|
+
};
|
|
854
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
855
|
+
store: {},
|
|
856
|
+
readConfig: async () => null,
|
|
857
|
+
getWorkspaceRouter: () => ({
|
|
858
|
+
sendThreadAction: async (threadId, action) => {
|
|
859
|
+
threadActions.push({ threadId, action });
|
|
860
|
+
return { runId: 'run-1' };
|
|
861
|
+
},
|
|
862
|
+
}),
|
|
863
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
864
|
+
});
|
|
865
|
+
const internals = gateway;
|
|
866
|
+
internals.runtime.set('default', {
|
|
867
|
+
workspaceId: 'default',
|
|
868
|
+
enabled: true,
|
|
869
|
+
status: 'running',
|
|
870
|
+
connected: true,
|
|
871
|
+
appId: 'app-1',
|
|
872
|
+
client,
|
|
873
|
+
});
|
|
874
|
+
await internals.handleCardActionEvent('default', {
|
|
875
|
+
schema: '2.0',
|
|
876
|
+
event: {
|
|
877
|
+
action: {
|
|
878
|
+
value: {
|
|
879
|
+
action: 'permission_response',
|
|
880
|
+
response: 'allow',
|
|
881
|
+
thread_id: 'thread-1',
|
|
882
|
+
},
|
|
883
|
+
},
|
|
884
|
+
},
|
|
885
|
+
event_context: {
|
|
886
|
+
open_message_id: 'permission-msg-nested',
|
|
887
|
+
},
|
|
888
|
+
});
|
|
889
|
+
strict_1.default.deepEqual(threadActions, [
|
|
890
|
+
{ threadId: 'thread-1', action: 'allow' },
|
|
891
|
+
]);
|
|
892
|
+
strict_1.default.equal(patchedCards[0]?.messageId, 'permission-msg-nested');
|
|
893
|
+
strict_1.default.equal(patchedCards[0]?.card?.elements?.some((element) => element.tag === 'action'), false);
|
|
766
894
|
});
|
|
767
895
|
(0, node_test_1.default)('lark permission requests fall back to text commands when card actions are disabled', async () => {
|
|
768
896
|
const createdCards = [];
|
|
@@ -821,6 +949,278 @@ const local_core_acp_store_js_1 = require("../services/local-ai-core/src/acp/loc
|
|
|
821
949
|
strict_1.default.match(createdCards[0]?.elements?.[0]?.content || '', /请直接回复/);
|
|
822
950
|
strict_1.default.equal(createdCards[0]?.elements?.some((element) => element.tag === 'action'), false);
|
|
823
951
|
});
|
|
952
|
+
(0, node_test_1.default)('lark image messages are downloaded and forwarded as generic channel image parts', async () => {
|
|
953
|
+
const sentMessages = [];
|
|
954
|
+
const pngBytes = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
955
|
+
const client = {
|
|
956
|
+
im: {
|
|
957
|
+
messageResource: {
|
|
958
|
+
get: async (request) => {
|
|
959
|
+
strict_1.default.equal(request.path.message_id, 'msg-image-1');
|
|
960
|
+
strict_1.default.equal(request.path.file_key, 'img-key-1');
|
|
961
|
+
strict_1.default.equal(request.params.type, 'image');
|
|
962
|
+
return {
|
|
963
|
+
headers: { 'content-type': 'image/png' },
|
|
964
|
+
getReadableStream: () => node_stream_1.Readable.from([pngBytes]),
|
|
965
|
+
};
|
|
966
|
+
},
|
|
967
|
+
},
|
|
968
|
+
messageReaction: {
|
|
969
|
+
create: async () => ({ data: { reaction_id: 'reaction-1' } }),
|
|
970
|
+
},
|
|
971
|
+
},
|
|
972
|
+
};
|
|
973
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
974
|
+
store: {
|
|
975
|
+
expirePendingPairings: () => { },
|
|
976
|
+
getAuthorizedUser: () => ({
|
|
977
|
+
id: 'auth-1',
|
|
978
|
+
workspace_id: 'default',
|
|
979
|
+
platform: 'lark',
|
|
980
|
+
platform_user_id: 'user-1',
|
|
981
|
+
chat_id: 'chat-1',
|
|
982
|
+
display_name: 'User',
|
|
983
|
+
thread_id: 'thread-1',
|
|
984
|
+
}),
|
|
985
|
+
getPlatformThreadBinding: () => ({
|
|
986
|
+
workspace_id: 'default',
|
|
987
|
+
platform: 'lark',
|
|
988
|
+
chat_id: 'chat-1',
|
|
989
|
+
platform_user_id: 'user-1',
|
|
990
|
+
thread_id: 'thread-1',
|
|
991
|
+
last_platform_message_id: null,
|
|
992
|
+
}),
|
|
993
|
+
getLatestRunForThread: () => null,
|
|
994
|
+
clearPlatformThreadMessageId: () => { },
|
|
995
|
+
},
|
|
996
|
+
readConfig: async () => ({
|
|
997
|
+
projects: [{
|
|
998
|
+
name: 'default',
|
|
999
|
+
root: '/tmp/project',
|
|
1000
|
+
platforms: [{
|
|
1001
|
+
type: 'lark',
|
|
1002
|
+
options: {
|
|
1003
|
+
app_id: 'app-1',
|
|
1004
|
+
app_secret: 'secret-1',
|
|
1005
|
+
},
|
|
1006
|
+
}],
|
|
1007
|
+
}],
|
|
1008
|
+
}),
|
|
1009
|
+
getWorkspaceRouter: () => ({
|
|
1010
|
+
getThreadSessionKey: (threadId) => `session:${threadId}`,
|
|
1011
|
+
sendThreadMessage: async (threadId, content) => {
|
|
1012
|
+
sentMessages.push({ threadId, content });
|
|
1013
|
+
return { runId: 'run-1' };
|
|
1014
|
+
},
|
|
1015
|
+
}),
|
|
1016
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
1017
|
+
});
|
|
1018
|
+
const internals = gateway;
|
|
1019
|
+
internals.runtime.set('default', {
|
|
1020
|
+
workspaceId: 'default',
|
|
1021
|
+
enabled: true,
|
|
1022
|
+
status: 'running',
|
|
1023
|
+
connected: true,
|
|
1024
|
+
appId: 'app-1',
|
|
1025
|
+
client,
|
|
1026
|
+
});
|
|
1027
|
+
await internals.handleMessageEvent('default', {
|
|
1028
|
+
event: {
|
|
1029
|
+
sender: {
|
|
1030
|
+
sender_id: { user_id: 'user-1' },
|
|
1031
|
+
},
|
|
1032
|
+
message: {
|
|
1033
|
+
message_id: 'msg-image-1',
|
|
1034
|
+
message_type: 'image',
|
|
1035
|
+
chat_id: 'chat-1',
|
|
1036
|
+
content: JSON.stringify({ image_key: 'img-key-1' }),
|
|
1037
|
+
},
|
|
1038
|
+
},
|
|
1039
|
+
});
|
|
1040
|
+
strict_1.default.equal(sentMessages.length, 1);
|
|
1041
|
+
strict_1.default.equal(sentMessages[0]?.threadId, 'thread-1');
|
|
1042
|
+
strict_1.default.match(sentMessages[0]?.content?.displayText, /\[User Message\]\n\[Image\]\n\[\/User Message\]/);
|
|
1043
|
+
strict_1.default.deepEqual(sentMessages[0]?.content?.contentParts?.map((part) => part.type), ['text', 'image']);
|
|
1044
|
+
strict_1.default.equal(sentMessages[0]?.content?.contentParts?.[1]?.mimeType, 'image/png');
|
|
1045
|
+
strict_1.default.equal(sentMessages[0]?.content?.contentParts?.[1]?.data, pngBytes.toString('base64'));
|
|
1046
|
+
});
|
|
1047
|
+
(0, node_test_1.default)('lark channel can upload and send a local file', async () => {
|
|
1048
|
+
const tempDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'lark-file-send-'));
|
|
1049
|
+
try {
|
|
1050
|
+
const filePath = (0, node_path_1.join)(tempDir, 'report.pdf');
|
|
1051
|
+
(0, node_fs_1.writeFileSync)(filePath, 'pdf content');
|
|
1052
|
+
const uploads = [];
|
|
1053
|
+
const messages = [];
|
|
1054
|
+
const client = {
|
|
1055
|
+
im: {
|
|
1056
|
+
file: {
|
|
1057
|
+
create: async (request) => {
|
|
1058
|
+
uploads.push(request);
|
|
1059
|
+
await new Promise((resolve, reject) => {
|
|
1060
|
+
request.data.file.on('data', () => { });
|
|
1061
|
+
request.data.file.on('error', reject);
|
|
1062
|
+
request.data.file.on('end', resolve);
|
|
1063
|
+
});
|
|
1064
|
+
return { file_key: 'file-key-1' };
|
|
1065
|
+
},
|
|
1066
|
+
},
|
|
1067
|
+
message: {
|
|
1068
|
+
create: async (request) => {
|
|
1069
|
+
messages.push(request);
|
|
1070
|
+
return { data: { message_id: 'msg-file-1' } };
|
|
1071
|
+
},
|
|
1072
|
+
},
|
|
1073
|
+
},
|
|
1074
|
+
};
|
|
1075
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
1076
|
+
store: {},
|
|
1077
|
+
readConfig: async () => null,
|
|
1078
|
+
getWorkspaceRouter: () => ({}),
|
|
1079
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
1080
|
+
});
|
|
1081
|
+
const internals = gateway;
|
|
1082
|
+
internals.runtime.set('default', {
|
|
1083
|
+
workspaceId: 'default',
|
|
1084
|
+
enabled: true,
|
|
1085
|
+
status: 'running',
|
|
1086
|
+
connected: true,
|
|
1087
|
+
appId: 'app-1',
|
|
1088
|
+
client,
|
|
1089
|
+
});
|
|
1090
|
+
const result = await gateway.sendFile('default', {
|
|
1091
|
+
path: filePath,
|
|
1092
|
+
channelId: 'oc_chat_1',
|
|
1093
|
+
});
|
|
1094
|
+
strict_1.default.equal(uploads.length, 1);
|
|
1095
|
+
strict_1.default.equal(uploads[0]?.data?.file_type, 'pdf');
|
|
1096
|
+
strict_1.default.equal(uploads[0]?.data?.file_name, 'report.pdf');
|
|
1097
|
+
strict_1.default.equal(messages.length, 1);
|
|
1098
|
+
strict_1.default.equal(messages[0]?.params?.receive_id_type, 'chat_id');
|
|
1099
|
+
strict_1.default.equal(messages[0]?.data?.receive_id, 'oc_chat_1');
|
|
1100
|
+
strict_1.default.equal(messages[0]?.data?.msg_type, 'file');
|
|
1101
|
+
strict_1.default.deepEqual(JSON.parse(messages[0]?.data?.content), { file_key: 'file-key-1' });
|
|
1102
|
+
strict_1.default.deepEqual(result, {
|
|
1103
|
+
platform: 'lark',
|
|
1104
|
+
workspaceId: 'default',
|
|
1105
|
+
channelId: 'oc_chat_1',
|
|
1106
|
+
messageId: 'msg-file-1',
|
|
1107
|
+
fileKey: 'file-key-1',
|
|
1108
|
+
fileName: 'report.pdf',
|
|
1109
|
+
fileSize: Buffer.byteLength('pdf content'),
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
finally {
|
|
1113
|
+
(0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true });
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
(0, node_test_1.default)('weixin channel can encrypt, upload, and send a local file', async () => {
|
|
1117
|
+
const tempDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'weixin-file-send-'));
|
|
1118
|
+
const originalFetch = globalThis.fetch;
|
|
1119
|
+
try {
|
|
1120
|
+
const filePath = (0, node_path_1.join)(tempDir, 'report.txt');
|
|
1121
|
+
(0, node_fs_1.writeFileSync)(filePath, 'hello weixin');
|
|
1122
|
+
const uploadUrlRequests = [];
|
|
1123
|
+
const cdnUploads = [];
|
|
1124
|
+
const sentMessages = [];
|
|
1125
|
+
globalThis.fetch = (async (url, init) => {
|
|
1126
|
+
const target = String(url);
|
|
1127
|
+
if (target.endsWith('/ilink/bot/getuploadurl')) {
|
|
1128
|
+
uploadUrlRequests.push(JSON.parse(String(init?.body || '{}')));
|
|
1129
|
+
return {
|
|
1130
|
+
ok: true,
|
|
1131
|
+
json: async () => ({ ret: 0, upload_param: 'upload-param-1' }),
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
if (target.includes('/upload?')) {
|
|
1135
|
+
const body = init?.body instanceof Uint8Array ? init.body : new Uint8Array();
|
|
1136
|
+
cdnUploads.push({ url: target, size: body.byteLength });
|
|
1137
|
+
return {
|
|
1138
|
+
ok: true,
|
|
1139
|
+
headers: {
|
|
1140
|
+
get: (name) => name.toLowerCase() === 'x-encrypted-param' ? 'download-param-1' : null,
|
|
1141
|
+
},
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
if (target.endsWith('/ilink/bot/sendmessage')) {
|
|
1145
|
+
sentMessages.push(JSON.parse(String(init?.body || '{}')));
|
|
1146
|
+
return {
|
|
1147
|
+
ok: true,
|
|
1148
|
+
json: async () => ({ ret: 0 }),
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
throw new Error(`Unexpected fetch ${target}`);
|
|
1152
|
+
});
|
|
1153
|
+
const gateway = new local_core_weixin_gateway_js_1.LocalCoreWeixinGateway({
|
|
1154
|
+
store: {
|
|
1155
|
+
getPlatformThreadBinding: () => ({
|
|
1156
|
+
workspace_id: 'default',
|
|
1157
|
+
platform: 'weixin',
|
|
1158
|
+
chat_id: 'user-1',
|
|
1159
|
+
platform_user_id: 'user-1',
|
|
1160
|
+
thread_id: 'thread-1',
|
|
1161
|
+
last_platform_message_id: 'ctx-1',
|
|
1162
|
+
}),
|
|
1163
|
+
listAuthorizedUsers: () => [],
|
|
1164
|
+
},
|
|
1165
|
+
readConfig: async () => ({
|
|
1166
|
+
projects: [{
|
|
1167
|
+
name: 'default',
|
|
1168
|
+
root: '/tmp/project',
|
|
1169
|
+
platforms: [{
|
|
1170
|
+
type: 'weixin',
|
|
1171
|
+
options: {
|
|
1172
|
+
token: 'token-1',
|
|
1173
|
+
account_id: 'account-1',
|
|
1174
|
+
base_url: 'https://weixin.example',
|
|
1175
|
+
cdn_base_url: 'https://cdn.example/c2c',
|
|
1176
|
+
},
|
|
1177
|
+
}],
|
|
1178
|
+
}],
|
|
1179
|
+
}),
|
|
1180
|
+
getWorkspaceRouter: () => ({}),
|
|
1181
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
1182
|
+
});
|
|
1183
|
+
const internals = gateway;
|
|
1184
|
+
internals.runtime.set('default', {
|
|
1185
|
+
workspaceId: 'default',
|
|
1186
|
+
enabled: true,
|
|
1187
|
+
status: 'running',
|
|
1188
|
+
connected: true,
|
|
1189
|
+
accountId: 'account-1',
|
|
1190
|
+
});
|
|
1191
|
+
const result = await gateway.sendFile('default', {
|
|
1192
|
+
path: filePath,
|
|
1193
|
+
channelId: 'user-1',
|
|
1194
|
+
participantId: 'user-1',
|
|
1195
|
+
});
|
|
1196
|
+
strict_1.default.equal(uploadUrlRequests.length, 1);
|
|
1197
|
+
strict_1.default.equal(uploadUrlRequests[0]?.media_type, 3);
|
|
1198
|
+
strict_1.default.equal(uploadUrlRequests[0]?.to_user_id, 'user-1');
|
|
1199
|
+
strict_1.default.equal(uploadUrlRequests[0]?.rawsize, Buffer.byteLength('hello weixin'));
|
|
1200
|
+
strict_1.default.equal(uploadUrlRequests[0]?.filesize, 16);
|
|
1201
|
+
strict_1.default.equal(cdnUploads.length, 1);
|
|
1202
|
+
strict_1.default.match(cdnUploads[0]?.url || '', /encrypted_query_param=upload-param-1/);
|
|
1203
|
+
strict_1.default.equal(cdnUploads[0]?.size, 16);
|
|
1204
|
+
strict_1.default.equal(sentMessages.length, 1);
|
|
1205
|
+
const message = sentMessages[0]?.msg;
|
|
1206
|
+
strict_1.default.equal(message?.to_user_id, 'user-1');
|
|
1207
|
+
strict_1.default.equal(message?.context_token, 'ctx-1');
|
|
1208
|
+
strict_1.default.equal(message?.item_list?.[0]?.type, 4);
|
|
1209
|
+
strict_1.default.equal(message?.item_list?.[0]?.file_item?.file_name, 'report.txt');
|
|
1210
|
+
strict_1.default.equal(message?.item_list?.[0]?.file_item?.len, String(Buffer.byteLength('hello weixin')));
|
|
1211
|
+
strict_1.default.equal(message?.item_list?.[0]?.file_item?.media?.encrypt_query_param, 'download-param-1');
|
|
1212
|
+
strict_1.default.equal(result.platform, 'weixin');
|
|
1213
|
+
strict_1.default.equal(result.channelId, 'user-1');
|
|
1214
|
+
strict_1.default.equal(result.fileName, 'report.txt');
|
|
1215
|
+
strict_1.default.equal(result.fileSize, Buffer.byteLength('hello weixin'));
|
|
1216
|
+
strict_1.default.match(result.messageId, /^openclaw-weixin-/);
|
|
1217
|
+
strict_1.default.ok(result.fileKey);
|
|
1218
|
+
}
|
|
1219
|
+
finally {
|
|
1220
|
+
globalThis.fetch = originalFetch;
|
|
1221
|
+
(0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true });
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
824
1224
|
(0, node_test_1.default)('lark message callbacks acknowledge before long thread runs finish', async () => {
|
|
825
1225
|
let registeredHandlers = {};
|
|
826
1226
|
let sentMessages = 0;
|
|
@@ -31,7 +31,7 @@ function plugin(id, dependsOn = []) {
|
|
|
31
31
|
strict_1.default.deepEqual(kernel.getCapabilitySnapshot(), {
|
|
32
32
|
adapters: {
|
|
33
33
|
channels: ['localcore-acp'],
|
|
34
|
-
agents: ['
|
|
34
|
+
agents: ['cursor', 'gemini', 'qoder', 'iflow', 'localcore-acp'],
|
|
35
35
|
knowledge: false,
|
|
36
36
|
knowledgeProviders: [],
|
|
37
37
|
},
|
|
@@ -43,7 +43,6 @@ function plugin(id, dependsOn = []) {
|
|
|
43
43
|
},
|
|
44
44
|
snapshot: {
|
|
45
45
|
agents: [
|
|
46
|
-
{ id: 'agent.codex', agentType: 'codex', displayName: 'codex' },
|
|
47
46
|
{ id: 'agent.cursor', agentType: 'cursor', displayName: 'cursor' },
|
|
48
47
|
{ id: 'agent.gemini', agentType: 'gemini', displayName: 'gemini' },
|
|
49
48
|
{ id: 'agent.qoder', agentType: 'qoder', displayName: 'qoder' },
|
|
@@ -115,10 +114,9 @@ function plugin(id, dependsOn = []) {
|
|
|
115
114
|
const kernel = (0, bootstrap_js_1.bootstrapLocalCoreKernel)();
|
|
116
115
|
await kernel.lifecycle.initAll();
|
|
117
116
|
const diagnostics = await kernel.diagnostics.snapshot();
|
|
118
|
-
strict_1.default.equal(diagnostics.pluginCount,
|
|
119
|
-
strict_1.default.equal(diagnostics.enabledPluginCount,
|
|
117
|
+
strict_1.default.equal(diagnostics.pluginCount, 6);
|
|
118
|
+
strict_1.default.equal(diagnostics.enabledPluginCount, 6);
|
|
120
119
|
strict_1.default.deepEqual(diagnostics.plugins.map((plugin) => plugin.pluginId).sort(), [
|
|
121
|
-
'builtin.agent-codex',
|
|
122
120
|
'builtin.agent-cursor',
|
|
123
121
|
'builtin.agent-gemini',
|
|
124
122
|
'builtin.agent-iflow',
|
|
@@ -131,7 +129,6 @@ function plugin(id, dependsOn = []) {
|
|
|
131
129
|
enabled: plugin.enabled,
|
|
132
130
|
health: plugin.health,
|
|
133
131
|
})), [
|
|
134
|
-
'builtin.agent-codex',
|
|
135
132
|
'builtin.agent-cursor',
|
|
136
133
|
'builtin.agent-gemini',
|
|
137
134
|
'builtin.agent-qoder',
|
|
@@ -151,13 +148,13 @@ function plugin(id, dependsOn = []) {
|
|
|
151
148
|
userDataPath,
|
|
152
149
|
});
|
|
153
150
|
strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.agents, [
|
|
154
|
-
'codex',
|
|
155
151
|
'cursor',
|
|
156
152
|
'gemini',
|
|
157
153
|
'qoder',
|
|
158
154
|
'iflow',
|
|
159
155
|
'localcore-acp',
|
|
160
156
|
'opencode',
|
|
157
|
+
'codex',
|
|
161
158
|
'claudecode',
|
|
162
159
|
]);
|
|
163
160
|
strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.channels, ['localcore-acp', 'lark', 'weixin']);
|
|
@@ -184,13 +181,13 @@ function plugin(id, dependsOn = []) {
|
|
|
184
181
|
enableKnowledge: false,
|
|
185
182
|
});
|
|
186
183
|
strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.agents, [
|
|
187
|
-
'codex',
|
|
188
184
|
'cursor',
|
|
189
185
|
'gemini',
|
|
190
186
|
'qoder',
|
|
191
187
|
'iflow',
|
|
192
188
|
'localcore-acp',
|
|
193
189
|
'opencode',
|
|
190
|
+
'codex',
|
|
194
191
|
'claudecode',
|
|
195
192
|
]);
|
|
196
193
|
strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.channels, ['localcore-acp', 'lark', 'weixin']);
|
|
@@ -207,6 +204,43 @@ function plugin(id, dependsOn = []) {
|
|
|
207
204
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
208
205
|
}
|
|
209
206
|
});
|
|
207
|
+
(0, node_test_1.default)('codex agent runtime routes projects through the bundled ACP adapter', async () => {
|
|
208
|
+
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-kernel-'));
|
|
209
|
+
try {
|
|
210
|
+
const runtime = (0, bootstrap_js_2.bootstrapLocalCoreRuntime)({
|
|
211
|
+
userDataPath,
|
|
212
|
+
enableKnowledge: false,
|
|
213
|
+
});
|
|
214
|
+
await runtime.state.saveRawConfigFile(`
|
|
215
|
+
[[projects]]
|
|
216
|
+
name = "codex-workspace"
|
|
217
|
+
|
|
218
|
+
[projects.agent]
|
|
219
|
+
type = "codex"
|
|
220
|
+
`);
|
|
221
|
+
const configState = await runtime.state.readConfigFile();
|
|
222
|
+
const project = configState.parsed?.projects?.find((entry) => entry.name === 'codex-workspace');
|
|
223
|
+
const codexRuntime = runtime.agentRuntimes.find((entry) => entry.agentType === 'codex');
|
|
224
|
+
const route = project ? codexRuntime?.createRoute(configState, project) : null;
|
|
225
|
+
strict_1.default.equal(route?.agentType, 'codex');
|
|
226
|
+
strict_1.default.equal(route?.config.command, process.execPath);
|
|
227
|
+
strict_1.default.match(route?.config.args[0] || '', /@zed-industries[/\\]codex-acp[/\\]bin[/\\]codex-acp\.js$/);
|
|
228
|
+
strict_1.default.deepEqual(await runtime.workspaceRouter.listWorkspaces(), [
|
|
229
|
+
{
|
|
230
|
+
id: 'codex-workspace',
|
|
231
|
+
name: 'codex-workspace',
|
|
232
|
+
agentType: 'codex',
|
|
233
|
+
platforms: [],
|
|
234
|
+
sessionsCount: 0,
|
|
235
|
+
heartbeatEnabled: false,
|
|
236
|
+
},
|
|
237
|
+
]);
|
|
238
|
+
await runtime.stop();
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
242
|
+
}
|
|
243
|
+
});
|
|
210
244
|
(0, node_test_1.default)('runtime bootstrap knowledge capabilities come from the selected provider plugin', () => {
|
|
211
245
|
const enabledUserDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-kernel-'));
|
|
212
246
|
const disabledUserDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-kernel-'));
|
|
@@ -538,7 +572,7 @@ name = "claude-workspace"
|
|
|
538
572
|
[projects.agent]
|
|
539
573
|
type = "claudecode"
|
|
540
574
|
`);
|
|
541
|
-
strict_1.default.deepEqual(runtime.agentRuntimes.map((entry) => entry.agentType), ['localcore-acp', 'opencode']);
|
|
575
|
+
strict_1.default.deepEqual(runtime.agentRuntimes.map((entry) => entry.agentType), ['localcore-acp', 'opencode', 'codex']);
|
|
542
576
|
strict_1.default.equal(runtime.kernel.getCapabilitySnapshot().snapshot.agents.some((capability) => capability.agentType === 'claudecode'), false);
|
|
543
577
|
strict_1.default.deepEqual(await runtime.workspaceRouter.listWorkspaces(), []);
|
|
544
578
|
await strict_1.default.rejects(() => runtime.workspaceRouter.listThreads('claude-workspace'), /Workspace "claude-workspace" is not configured as a Local AI Core ACP workspace/);
|