@kafca/agentdock 0.1.43 → 0.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -11
- package/bin/agentdock.mjs +5 -5
- package/dist/renderer/assets/{Badge-CbG6yRSm.js → Badge-BIojwD6s.js} +1 -1
- package/dist/renderer/assets/{Chat-BvNNWGGX.js → Chat-wjBR3XEX.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-Ct-PvJB8.js → ChatMarkdown-DqszsPB_.js} +1 -1
- package/dist/renderer/assets/Config-BDCHs5A2.js +21 -0
- package/dist/renderer/assets/{CronList-Dj_3muVG.js → CronList-CEWQYTov.js} +1 -1
- package/dist/renderer/assets/Dashboard-DrWftfk3.js +26 -0
- package/dist/renderer/assets/{EmptyState-Bn2Qh14U.js → EmptyState-BqCx1oWr.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-Bsz6Ou41.js → KnowledgeDetail-BwK8Gpfa.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-Cgj4XFXn.js → KnowledgeHome-hhDTZMDO.js} +3 -3
- package/dist/renderer/assets/{Logs-Dp-NF6GN.js → Logs-C9xPEhFT.js} +1 -1
- package/dist/renderer/assets/{Modal-B6YPPBN6.js → Modal-D2U4r2V0.js} +1 -1
- package/dist/renderer/assets/{MonitorList-xEZWg460.js → MonitorList-CayKbfwJ.js} +1 -1
- package/dist/renderer/assets/{Page-Bn7RjGOS.js → Page-urf5GcT_.js} +1 -1
- package/dist/renderer/assets/ProjectDetail-B1GyAr7a.js +11 -0
- package/dist/renderer/assets/{ProjectList-BDk5_gqY.js → ProjectList-BoipQypE.js} +1 -1
- package/dist/renderer/assets/{Select-xshfMIEQ.js → Select-CAscWpy5.js} +1 -1
- package/dist/renderer/assets/{SessionChat-BkHy90z3.js → SessionChat-BAVy5221.js} +1 -1
- package/dist/renderer/assets/{SessionList-BZyXT92L.js → SessionList-BZpuMvh0.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-DUOIyXrS.js → ThreadChat-JX7m9biG.js} +1 -1
- package/dist/renderer/assets/Workspace-CFW8otjU.js +14 -0
- package/dist/renderer/assets/{arrow-left-C54ZI-AS.js → arrow-left-7HrNuS-V.js} +1 -1
- package/dist/renderer/assets/{book-open-Dl7GO0zn.js → book-open-BDoAu82s.js} +1 -1
- package/dist/renderer/assets/{check-CiqgtrOL.js → check-DGlyq4xX.js} +1 -1
- package/dist/renderer/assets/{chevron-down-DTL2OuVh.js → chevron-down-Bb_3EHq9.js} +1 -1
- package/dist/renderer/assets/{circle-DaVKfa3P.js → circle-DIpqZnYw.js} +1 -1
- package/dist/renderer/assets/desktop-Ci1fnRDR.js +1 -0
- package/dist/renderer/assets/{desktop-C6q6wBae.js → desktop-Do_UrC-o.js} +5 -5
- package/dist/renderer/assets/en-CmAr_0e6.js +1 -0
- package/dist/renderer/assets/es-Cs9x52ca.js +1 -0
- package/dist/renderer/assets/{funnel-CrmnLMJI.js → funnel-Bbf0ERLP.js} +1 -1
- package/dist/renderer/assets/{heart-BMfQI7y_.js → heart-CGqU-qfw.js} +1 -1
- package/dist/renderer/assets/{index-nreiKY1f.js → index-Df-Trovt.js} +2 -2
- package/dist/renderer/assets/{index-HPNb1zfx.js → index-DwhTjLA1.js} +36 -36
- package/dist/renderer/assets/index-RaTga2BC.css +11 -0
- package/dist/renderer/assets/ja-DtvtBRTW.js +1 -0
- package/dist/renderer/assets/{pencil-wTQ4l465.js → pencil-CHiy1MvK.js} +1 -1
- package/dist/renderer/assets/{play-BK--MXmw.js → play-CGYnmC4Q.js} +1 -1
- package/dist/renderer/assets/{plug-BIx9fjip.js → plug-Mexu4gyV.js} +1 -1
- package/dist/renderer/assets/{plus-Dn7JFWQ8.js → plus-B_Q5-Oj7.js} +1 -1
- package/dist/renderer/assets/projects-C6bbkC-O.js +1 -0
- package/dist/renderer/assets/{save-CC3zOSWb.js → save-CJ_QFPw0.js} +1 -1
- package/dist/renderer/assets/{search-CDTy9Czu.js → search-D8Dkhsyq.js} +1 -1
- package/dist/renderer/assets/{server-DtQk3t2a.js → server-Cd96R7WL.js} +1 -1
- package/dist/renderer/assets/{session-utils-4ep5D66T.js → session-utils-BNUbQBfF.js} +1 -1
- package/dist/renderer/assets/{sessions-Dor1LteH.js → sessions-BACfV8s1.js} +1 -1
- package/dist/renderer/assets/{shield-check-Cz2LpU6r.js → shield-check-Cnn-yQUA.js} +1 -1
- package/dist/renderer/assets/{trash-2-C2EmWFZV.js → trash-2-oWCxwQ9D.js} +1 -1
- package/dist/renderer/assets/{user-I8B-cs5A.js → user-BzE9BwsY.js} +1 -1
- package/dist/renderer/assets/{wifi-off-CPevTQJn.js → wifi-off-DHxnNkdY.js} +1 -1
- package/dist/renderer/assets/zh-CcJ9vBZj.js +1 -0
- package/dist/renderer/assets/zh-TW-elI72AC1.js +1 -0
- package/dist/renderer/index.html +2 -2
- package/dist-electron/electron/main.js +26 -1
- package/dist-electron/packages/core-sdk/src/index.js +28 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +111 -62
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +80 -7
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +78 -5
- package/dist-electron/services/local-ai-core/src/acp/store/external-store.js +98 -0
- package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +33 -0
- package/dist-electron/services/local-ai-core/src/acp/store/model-provider-store.js +88 -0
- package/dist-electron/services/local-ai-core/src/acp/store/schema.js +43 -0
- package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +2 -119
- package/dist-electron/services/local-ai-core/src/agents/pi/provider-materializer.js +148 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/inbound.js +114 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +117 -75
- package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +4 -2
- package/dist-electron/services/local-ai-core/src/channel/shared/thread-routing.js +34 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +151 -47
- package/dist-electron/services/local-ai-core/src/execution/agent-execution-backend.js +56 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +18 -57
- package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +255 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/catalog.js +78 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +3 -1
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +64 -9
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -2
- package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +152 -0
- package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +175 -0
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +330 -3
- package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +11 -2
- package/dist-electron/services/local-ai-core/src/runtime/provider-config-migration.js +32 -0
- package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +76 -8
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +62 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +708 -4
- package/dist-electron/services/local-ai-core/src/runtime/standalone.js +13 -3
- package/dist-electron/services/local-ai-core/src/sandbox/opensandbox-client.js +113 -0
- package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +273 -0
- package/dist-electron/services/local-ai-core/src/sandbox/sandbox-manager.js +215 -0
- package/dist-electron/services/local-ai-core/src/sandbox/sandbox-stdio-proxy.js +188 -0
- package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +3 -0
- package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +32 -0
- package/dist-electron/services/local-ai-core/src/thread/thread-slash-command-dispatcher.js +71 -0
- package/dist-electron/shared/desktop.js +85 -1
- package/dist-electron/tests/contracts/architecture-docs.test.js +83 -0
- package/dist-electron/tests/electron/plugin-kernel.test.js +225 -18
- package/dist-electron/tests/electron/runtime-detection-service.test.js +57 -5
- package/dist-electron/tests/electron/sandbox-config.test.js +541 -0
- package/dist-electron/tests/electron/workspace-task-store.test.js +257 -0
- package/dist-electron/tests/integration/channel-gateways.test.js +32 -0
- package/dist-electron/tests/integration/lark-gateway.test.js +1977 -0
- package/dist-electron/tests/integration/local-core-acp-progress.test.js +1772 -0
- package/dist-electron/tests/integration/local-core-refactor.test.js +775 -5156
- package/dist-electron/tests/integration/local-core-routes.test.js +238 -0
- package/dist-electron/tests/integration/weixin-gateway.test.js +927 -0
- package/package.json +2 -3
- package/dist/renderer/assets/Config-lQX2qVVV.js +0 -16
- package/dist/renderer/assets/Dashboard-eh_RhGYb.js +0 -26
- package/dist/renderer/assets/ProjectDetail-Cv_jIE61.js +0 -11
- package/dist/renderer/assets/Workspace-Dl80fNEC.js +0 -14
- package/dist/renderer/assets/desktop-jaAiayNB.js +0 -1
- package/dist/renderer/assets/en-D2SkCrhG.js +0 -1
- package/dist/renderer/assets/es-C8UBPhxM.js +0 -1
- package/dist/renderer/assets/index-CaQZSRbg.css +0 -11
- package/dist/renderer/assets/ja-ChF4vbBL.js +0 -1
- package/dist/renderer/assets/projects-brJZgwEJ.js +0 -1
- package/dist/renderer/assets/zh-DIcdHycM.js +0 -1
- package/dist/renderer/assets/zh-TW-BtRwreY_.js +0 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeLarkInboundMessageEvent = normalizeLarkInboundMessageEvent;
|
|
4
|
+
exports.isLarkBotMentioned = isLarkBotMentioned;
|
|
5
|
+
exports.stripLarkMentions = stripLarkMentions;
|
|
6
|
+
exports.summarizeLarkInboundPayload = summarizeLarkInboundPayload;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
function normalizeLarkInboundMessageEvent(data, options = {}) {
|
|
9
|
+
const payload = (data?.event && typeof data.event === 'object')
|
|
10
|
+
? data.event
|
|
11
|
+
: data;
|
|
12
|
+
const message = payload?.message;
|
|
13
|
+
const sender = payload?.sender;
|
|
14
|
+
if (!message || !sender) {
|
|
15
|
+
return { ok: false, reason: 'missing-message-or-sender', detail: JSON.stringify(Object.keys(data || {})) };
|
|
16
|
+
}
|
|
17
|
+
let parsedContent = {};
|
|
18
|
+
try {
|
|
19
|
+
parsedContent = JSON.parse(String(message.content || '{}'));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
parsedContent = {};
|
|
23
|
+
}
|
|
24
|
+
const messageType = String(message.message_type || '').trim().toLowerCase();
|
|
25
|
+
const chatType = String(message.chat_type || '').trim().toLowerCase();
|
|
26
|
+
const mentions = Array.isArray(message.mentions) ? message.mentions : [];
|
|
27
|
+
const botOpenId = String(options.botOpenId || '').trim();
|
|
28
|
+
if (chatType === 'group' && !options.groupReplyAll && botOpenId && !isLarkBotMentioned(mentions, botOpenId)) {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
reason: 'group-message-without-bot-mention',
|
|
32
|
+
detail: `chat=${String(message.chat_id || '')} message=${String(message.message_id || '')}`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const text = stripLarkMentions(String(parsedContent.text || '').trim(), mentions, botOpenId);
|
|
36
|
+
const platformUserId = String(sender.sender_id?.user_id || sender.sender_id?.open_id || '').trim();
|
|
37
|
+
const chatId = String(message.chat_id || platformUserId).trim();
|
|
38
|
+
if (!platformUserId || !chatId) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
reason: 'missing-sender-or-chat',
|
|
42
|
+
detail: `senderKeys=${JSON.stringify(Object.keys(sender?.sender_id || {}))} chat=${String(message.chat_id || '')}`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
message: {
|
|
48
|
+
payload,
|
|
49
|
+
message,
|
|
50
|
+
sender,
|
|
51
|
+
parsedContent,
|
|
52
|
+
messageType,
|
|
53
|
+
chatType,
|
|
54
|
+
mentions,
|
|
55
|
+
text,
|
|
56
|
+
platformUserId,
|
|
57
|
+
chatId,
|
|
58
|
+
displayName: String(sender.sender_id?.user_id ||
|
|
59
|
+
sender.sender_id?.open_id ||
|
|
60
|
+
`Lark ${platformUserId.slice(-6)}`),
|
|
61
|
+
messageId: String(message.message_id || (0, node_crypto_1.randomUUID)()),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function isLarkBotMentioned(mentions, botOpenId) {
|
|
66
|
+
if (!botOpenId) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return mentions.some((mention) => {
|
|
70
|
+
const item = mention && typeof mention === 'object' ? mention : {};
|
|
71
|
+
return getMentionOpenId(item) === botOpenId;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function stripLarkMentions(text, mentions, botOpenId) {
|
|
75
|
+
let next = String(text || '');
|
|
76
|
+
for (const mention of mentions) {
|
|
77
|
+
const item = mention && typeof mention === 'object' ? mention : {};
|
|
78
|
+
const key = String(item.key || '').trim();
|
|
79
|
+
if (!key) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const openId = getMentionOpenId(item);
|
|
83
|
+
const name = String(item.name || item.display_name || item.displayName || '').trim();
|
|
84
|
+
if (botOpenId && openId === botOpenId) {
|
|
85
|
+
next = next.split(key).join('');
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
next = next.split(key).join(name ? `@${name}` : '');
|
|
89
|
+
}
|
|
90
|
+
return next.trim();
|
|
91
|
+
}
|
|
92
|
+
function summarizeLarkInboundPayload(payload) {
|
|
93
|
+
const eventPayload = (payload?.event && typeof payload.event === 'object')
|
|
94
|
+
? payload.event
|
|
95
|
+
: payload;
|
|
96
|
+
const message = eventPayload?.message || {};
|
|
97
|
+
const sender = eventPayload?.sender || {};
|
|
98
|
+
const senderId = sender?.sender_id || {};
|
|
99
|
+
const content = typeof message.content === 'string' ? message.content : '';
|
|
100
|
+
return [
|
|
101
|
+
`message=${String(message.message_id || '') || 'missing'}`,
|
|
102
|
+
`type=${String(message.message_type || '') || 'missing'}`,
|
|
103
|
+
`chat=${String(message.chat_id || '') || 'missing'}`,
|
|
104
|
+
`chatType=${String(message.chat_type || '') || 'missing'}`,
|
|
105
|
+
`sender=${String(senderId.user_id || senderId.open_id || '') || 'missing'}`,
|
|
106
|
+
`mentions=${Array.isArray(message.mentions) ? message.mentions.length : 0}`,
|
|
107
|
+
`contentBytes=${Buffer.byteLength(content, 'utf8')}`,
|
|
108
|
+
`keys=${JSON.stringify(Object.keys(eventPayload || {}))}`,
|
|
109
|
+
].join(' ');
|
|
110
|
+
}
|
|
111
|
+
function getMentionOpenId(item) {
|
|
112
|
+
const id = item.id || item.user_id || item.userId || {};
|
|
113
|
+
return String(id.open_id || id.openId || item.open_id || item.openId || '').trim();
|
|
114
|
+
}
|
|
@@ -38,16 +38,19 @@ const node_events_1 = require("node:events");
|
|
|
38
38
|
const node_crypto_1 = require("node:crypto");
|
|
39
39
|
const node_fs_1 = require("node:fs");
|
|
40
40
|
const node_path_1 = require("node:path");
|
|
41
|
+
const local_core_errors_js_1 = require("../../kernel/local-core-errors.js");
|
|
41
42
|
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
42
43
|
const content_js_1 = require("../shared/content.js");
|
|
43
44
|
const file_utils_js_1 = require("../shared/file-utils.js");
|
|
44
45
|
const session_command_runtime_js_1 = require("../shared/session-command-runtime.js");
|
|
46
|
+
const thread_routing_js_1 = require("../shared/thread-routing.js");
|
|
45
47
|
const cards_js_1 = require("./cards.js");
|
|
46
48
|
const config_js_1 = require("./config.js");
|
|
47
49
|
const registration_js_1 = require("./registration.js");
|
|
48
50
|
const messages_js_1 = require("./rendering/messages.js");
|
|
51
|
+
const inbound_js_1 = require("./inbound.js");
|
|
49
52
|
const runtime_state_js_1 = require("./runtime-state.js");
|
|
50
|
-
const
|
|
53
|
+
const thread_slash_command_dispatcher_js_1 = require("../../thread/thread-slash-command-dispatcher.js");
|
|
51
54
|
const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
|
|
52
55
|
const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
|
|
53
56
|
const LARK_FINAL_PATCH_INTERVAL_MS = 900;
|
|
@@ -71,15 +74,29 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
71
74
|
constructor(options) {
|
|
72
75
|
super();
|
|
73
76
|
this.options = options;
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
const slashCommands = new thread_slash_command_dispatcher_js_1.ThreadSlashCommandDispatcher({
|
|
78
|
+
session: {
|
|
79
|
+
listThreads: (workspaceId) => this.options.getWorkspaceRouter().listThreads(workspaceId),
|
|
80
|
+
getThread: (threadId) => this.options.getWorkspaceRouter().getThread(threadId),
|
|
81
|
+
createThread: (workspaceId, title) => this.options.getWorkspaceRouter().createThread(workspaceId, title),
|
|
82
|
+
renameThread: (threadId, title) => this.options.getWorkspaceRouter().renameThread(threadId, title),
|
|
83
|
+
deleteThread: (threadId) => this.options.getWorkspaceRouter().deleteThread(threadId),
|
|
84
|
+
},
|
|
85
|
+
thread: {
|
|
86
|
+
getThreadRow: (threadId) => this.options.store.getThreadRow(threadId),
|
|
87
|
+
updateThreadAgentMode: (threadId, mode) => this.options.store.updateThreadAgentMode(threadId, mode),
|
|
88
|
+
updateThreadAgentType: (threadId, agentType) => this.options.store.updateThreadAgentType(threadId, agentType),
|
|
89
|
+
getLatestRunForThread: (threadId) => this.options.store.getLatestRunForThread(threadId),
|
|
90
|
+
createAuditEvent: (input) => this.options.store.createAuditEvent(input),
|
|
91
|
+
getAgentTypes: () => this.options.getWorkspaceRouter().getAgentTypes(),
|
|
92
|
+
setThreadMode: (threadId, mode) => this.options.getWorkspaceRouter().setThreadMode(threadId, mode),
|
|
93
|
+
closeThreadSession: (threadId) => this.options.getWorkspaceRouter().closeThreadSession(threadId),
|
|
94
|
+
interruptRun: (runId) => this.options.getWorkspaceRouter().interruptRun(runId),
|
|
95
|
+
log: this.options.log,
|
|
96
|
+
},
|
|
80
97
|
});
|
|
81
98
|
this.sessionCommandRuntime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
|
|
82
|
-
|
|
99
|
+
dispatcher: slashCommands,
|
|
83
100
|
store: this.options.store,
|
|
84
101
|
getThreadSessionKey: (threadId) => this.options.getWorkspaceRouter().getThreadSessionKey(threadId),
|
|
85
102
|
setThreadRoute: (sessionKey, route) => {
|
|
@@ -124,6 +141,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
124
141
|
appId: binding.appId,
|
|
125
142
|
autoApprove: binding.autoApprove,
|
|
126
143
|
cardActionsEnabled: binding.cardActionsEnabled,
|
|
144
|
+
groupReplyAll: binding.groupReplyAll,
|
|
145
|
+
botOpenId: binding.botOpenId,
|
|
127
146
|
});
|
|
128
147
|
}
|
|
129
148
|
continue;
|
|
@@ -378,6 +397,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
378
397
|
status: binding?.status || 'disabled',
|
|
379
398
|
appId: binding?.appId || '',
|
|
380
399
|
lastError: binding?.lastError,
|
|
400
|
+
lastErrorInfo: binding?.lastErrorInfo,
|
|
401
|
+
lastErrorAt: binding?.lastErrorAt,
|
|
381
402
|
connectedAt: binding?.connectedAt,
|
|
382
403
|
pendingPairings: pairings.length,
|
|
383
404
|
authorizedUsers: users.length,
|
|
@@ -659,25 +680,17 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
659
680
|
return { paired: false };
|
|
660
681
|
}
|
|
661
682
|
const router = this.options.getWorkspaceRouter();
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
platform_user_id: input.platformUserId,
|
|
674
|
-
thread_id: threadId,
|
|
675
|
-
last_platform_message_id: null,
|
|
676
|
-
created_at: now,
|
|
677
|
-
updated_at: now,
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
const sessionKey = this.options.getWorkspaceRouter().getThreadSessionKey(threadId);
|
|
683
|
+
let { threadId } = await (0, thread_routing_js_1.resolveChannelThreadRoute)({
|
|
684
|
+
store: this.options.store,
|
|
685
|
+
router,
|
|
686
|
+
workspaceId: input.workspaceId,
|
|
687
|
+
platformKey,
|
|
688
|
+
chatId: input.chatId,
|
|
689
|
+
platformUserId: input.platformUserId,
|
|
690
|
+
displayName: input.displayName,
|
|
691
|
+
fallbackTitlePrefix: 'Lark',
|
|
692
|
+
authorized,
|
|
693
|
+
});
|
|
681
694
|
const normalizedText = String(input.text || '').trim().toLowerCase();
|
|
682
695
|
const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny')
|
|
683
696
|
? this.findAwaitingPermissionThreadId(input.workspaceId, input.chatId, input.platformUserId)
|
|
@@ -702,6 +715,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
702
715
|
currentThreadId: threadId,
|
|
703
716
|
text: input.text,
|
|
704
717
|
defaultTitle: `${input.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`,
|
|
718
|
+
defaultAgentType: slashCommand ? await this.resolveDefaultAgentType(input.workspaceId, threadId) : '',
|
|
705
719
|
chatId: input.chatId,
|
|
706
720
|
platformUserId: input.platformUserId,
|
|
707
721
|
platformKey,
|
|
@@ -789,6 +803,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
789
803
|
appId: binding.appId,
|
|
790
804
|
autoApprove: binding.autoApprove,
|
|
791
805
|
cardActionsEnabled: binding.cardActionsEnabled,
|
|
806
|
+
groupReplyAll: binding.groupReplyAll,
|
|
807
|
+
botOpenId: binding.botOpenId,
|
|
792
808
|
};
|
|
793
809
|
this.runtime.set(key, status);
|
|
794
810
|
this.notifyRuntimeStateChanged();
|
|
@@ -801,6 +817,14 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
801
817
|
appType: mod.AppType.SelfBuild,
|
|
802
818
|
domain: mod.Domain.Feishu,
|
|
803
819
|
});
|
|
820
|
+
try {
|
|
821
|
+
status.botOpenId = await this.fetchBotOpenId(status);
|
|
822
|
+
binding.botOpenId = status.botOpenId;
|
|
823
|
+
this.options.log?.(`localcore-lark bot identified for ${binding.workspaceId}/${binding.instanceId}: ${status.botOpenId}`);
|
|
824
|
+
}
|
|
825
|
+
catch (error) {
|
|
826
|
+
this.options.log?.(`localcore-lark bot identity lookup failed for ${binding.workspaceId}/${binding.instanceId}; group mention filtering may be limited: ${error instanceof Error ? error.message : String(error)}`);
|
|
827
|
+
}
|
|
804
828
|
status.eventDispatcher = new mod.EventDispatcher({
|
|
805
829
|
encryptKey: binding.encryptKey || '',
|
|
806
830
|
verificationToken: binding.verificationToken || '',
|
|
@@ -835,13 +859,20 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
835
859
|
status.status = 'running';
|
|
836
860
|
status.connected = true;
|
|
837
861
|
status.connectedAt = new Date().toISOString();
|
|
838
|
-
status
|
|
862
|
+
this.clearRuntimeError(status);
|
|
839
863
|
this.options.log?.(`localcore-lark ws ready for ${binding.workspaceId}`);
|
|
840
864
|
}
|
|
841
865
|
catch (error) {
|
|
842
866
|
status.status = 'error';
|
|
843
867
|
status.connected = false;
|
|
844
|
-
|
|
868
|
+
const errorInfo = (0, local_core_errors_js_1.toLocalCoreErrorInfo)(error instanceof local_core_errors_js_1.LocalCoreError
|
|
869
|
+
? error
|
|
870
|
+
: new local_core_errors_js_1.LocalCoreError('channel_auth_failed', error instanceof Error ? error.message : String(error), {
|
|
871
|
+
userMessage: 'Lark is not connected.',
|
|
872
|
+
suggestedAction: 'Check app credentials and restart the Lark gateway.',
|
|
873
|
+
details: { workspaceId: binding.workspaceId, instanceId: binding.instanceId },
|
|
874
|
+
}), 'channel_auth_failed');
|
|
875
|
+
this.setRuntimeError(status, errorInfo);
|
|
845
876
|
this.options.log?.(`localcore-lark start failed for ${binding.workspaceId}: ${status.lastError}`);
|
|
846
877
|
}
|
|
847
878
|
this.notifyRuntimeStateChanged();
|
|
@@ -875,6 +906,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
875
906
|
appId: state.appId,
|
|
876
907
|
autoApprove: state.autoApprove,
|
|
877
908
|
cardActionsEnabled: state.cardActionsEnabled,
|
|
909
|
+
groupReplyAll: state.groupReplyAll,
|
|
910
|
+
botOpenId: state.botOpenId,
|
|
878
911
|
});
|
|
879
912
|
this.notifyRuntimeStateChanged();
|
|
880
913
|
}
|
|
@@ -886,30 +919,44 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
886
919
|
},
|
|
887
920
|
});
|
|
888
921
|
}
|
|
922
|
+
clearRuntimeError(state) {
|
|
923
|
+
state.lastError = undefined;
|
|
924
|
+
state.lastErrorInfo = undefined;
|
|
925
|
+
state.lastErrorAt = undefined;
|
|
926
|
+
}
|
|
927
|
+
setRuntimeError(state, errorInfo) {
|
|
928
|
+
state.lastError = errorInfo.message;
|
|
929
|
+
state.lastErrorInfo = errorInfo;
|
|
930
|
+
state.lastErrorAt = new Date().toISOString();
|
|
931
|
+
this.options.eventBus.emit({
|
|
932
|
+
type: 'localcore.error',
|
|
933
|
+
payload: {
|
|
934
|
+
scope: 'channel.lark',
|
|
935
|
+
errorInfo,
|
|
936
|
+
context: {
|
|
937
|
+
workspaceId: state.workspaceId,
|
|
938
|
+
instanceId: state.instanceId,
|
|
939
|
+
platform: 'lark',
|
|
940
|
+
},
|
|
941
|
+
},
|
|
942
|
+
});
|
|
943
|
+
}
|
|
889
944
|
async handleMessageEvent(workspaceId, instanceIdOrData, platformKeyOrData, maybeData) {
|
|
890
945
|
const legacyCall = typeof instanceIdOrData === 'object';
|
|
891
946
|
const instanceId = legacyCall ? 'default' : instanceIdOrData;
|
|
892
947
|
const platformKey = legacyCall ? 'lark' : String(platformKeyOrData || (0, config_js_1.channelPlatformKey)('lark', instanceId));
|
|
893
948
|
const data = (legacyCall ? instanceIdOrData : maybeData) || {};
|
|
894
|
-
const
|
|
895
|
-
|
|
896
|
-
:
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
this.options.log?.(`localcore-lark handling message event for ${workspaceId}: ${
|
|
900
|
-
if (!
|
|
901
|
-
this.options.log?.(`localcore-lark ignored event
|
|
949
|
+
const runtimeState = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
950
|
+
const normalized = (0, inbound_js_1.normalizeLarkInboundMessageEvent)(data, {
|
|
951
|
+
botOpenId: runtimeState?.botOpenId,
|
|
952
|
+
groupReplyAll: runtimeState?.groupReplyAll,
|
|
953
|
+
});
|
|
954
|
+
this.options.log?.(`localcore-lark handling message event for ${workspaceId}: ${(0, inbound_js_1.summarizeLarkInboundPayload)(data)}`);
|
|
955
|
+
if (!normalized.ok) {
|
|
956
|
+
this.options.log?.(`localcore-lark ignored message event for ${workspaceId}: reason=${normalized.reason}${normalized.detail ? ` ${normalized.detail}` : ''}`);
|
|
902
957
|
return;
|
|
903
958
|
}
|
|
904
|
-
|
|
905
|
-
try {
|
|
906
|
-
parsedContent = JSON.parse(String(message.content || '{}'));
|
|
907
|
-
}
|
|
908
|
-
catch {
|
|
909
|
-
parsedContent = {};
|
|
910
|
-
}
|
|
911
|
-
const messageType = String(message.message_type || '').trim().toLowerCase();
|
|
912
|
-
const text = String(parsedContent.text || '').trim();
|
|
959
|
+
const { message, parsedContent, messageType, chatType, mentions, text, platformUserId, chatId, displayName, messageId, } = normalized.message;
|
|
913
960
|
const contentParts = [];
|
|
914
961
|
if (text) {
|
|
915
962
|
contentParts.push({ type: 'text', text });
|
|
@@ -945,24 +992,16 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
945
992
|
return;
|
|
946
993
|
}
|
|
947
994
|
const displayText = text || this.summarizeInboundContentParts(contentParts);
|
|
948
|
-
|
|
949
|
-
const chatId = String(message.chat_id || platformUserId).trim();
|
|
950
|
-
if (!platformUserId || !chatId) {
|
|
951
|
-
this.options.log?.(`localcore-lark ignored message without sender/chat for ${workspaceId}: senderKeys=${JSON.stringify(Object.keys(sender?.sender_id || {}))} chat=${String(message.chat_id || '')}`);
|
|
952
|
-
return;
|
|
953
|
-
}
|
|
954
|
-
this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} type=${messageType || 'unknown'} text=${JSON.stringify(displayText.slice(0, 120))}`);
|
|
995
|
+
this.options.log?.(`localcore-lark inbound message for ${workspaceId}: chat=${chatId} user=${platformUserId} chatType=${chatType || 'unknown'} mentions=${mentions.length} type=${messageType || 'unknown'} text=${JSON.stringify(displayText.slice(0, 120))}`);
|
|
955
996
|
await this.handleInboundMessage({
|
|
956
997
|
workspaceId,
|
|
957
998
|
instanceId,
|
|
958
999
|
platformKey,
|
|
959
1000
|
platformUserId,
|
|
960
1001
|
chatId,
|
|
961
|
-
displayName
|
|
962
|
-
payload?.sender?.sender_id?.open_id ||
|
|
963
|
-
`Lark ${platformUserId.slice(-6)}`),
|
|
1002
|
+
displayName,
|
|
964
1003
|
text: displayText,
|
|
965
|
-
messageId
|
|
1004
|
+
messageId,
|
|
966
1005
|
contentParts,
|
|
967
1006
|
});
|
|
968
1007
|
}
|
|
@@ -1109,24 +1148,19 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1109
1148
|
}
|
|
1110
1149
|
}
|
|
1111
1150
|
summarizeLarkEvent(data) {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
const
|
|
1120
|
-
const
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
`chat=${String(message.chat_id || '') || 'missing'}`,
|
|
1126
|
-
`sender=${String(senderId.user_id || senderId.open_id || '') || 'missing'}`,
|
|
1127
|
-
`contentBytes=${Buffer.byteLength(content, 'utf8')}`,
|
|
1128
|
-
`keys=${JSON.stringify(Object.keys(payload || {}))}`,
|
|
1129
|
-
].join(' ');
|
|
1151
|
+
return (0, inbound_js_1.summarizeLarkInboundPayload)(data);
|
|
1152
|
+
}
|
|
1153
|
+
async fetchBotOpenId(state) {
|
|
1154
|
+
const response = await state.client.request({
|
|
1155
|
+
url: '/open-apis/bot/v3/info',
|
|
1156
|
+
method: 'GET',
|
|
1157
|
+
});
|
|
1158
|
+
const bot = response?.bot || response?.data?.bot;
|
|
1159
|
+
const openId = String(bot?.open_id || bot?.openId || '').trim();
|
|
1160
|
+
if (!openId) {
|
|
1161
|
+
throw new Error('Lark bot info response did not include bot.open_id');
|
|
1162
|
+
}
|
|
1163
|
+
return openId;
|
|
1130
1164
|
}
|
|
1131
1165
|
summarizeWsArgs(args) {
|
|
1132
1166
|
if (args.length === 0) {
|
|
@@ -1321,6 +1355,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1321
1355
|
currentThreadId: sessionAction.threadId,
|
|
1322
1356
|
text: sessionAction.command,
|
|
1323
1357
|
defaultTitle: `Lark ${new Date().toLocaleTimeString()}`,
|
|
1358
|
+
defaultAgentType: await this.resolveDefaultAgentType(workspaceId, sessionAction.threadId),
|
|
1324
1359
|
chatId: route.chatId,
|
|
1325
1360
|
platformUserId: route.platformUserId,
|
|
1326
1361
|
platformKey: route.platformKey,
|
|
@@ -1357,6 +1392,13 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1357
1392
|
threadId: binding.thread_id,
|
|
1358
1393
|
};
|
|
1359
1394
|
}
|
|
1395
|
+
async resolveDefaultAgentType(workspaceId, threadId) {
|
|
1396
|
+
const router = this.options.getWorkspaceRouter();
|
|
1397
|
+
if (typeof router.getWorkspaceDefaultAgentType === 'function') {
|
|
1398
|
+
return router.getWorkspaceDefaultAgentType(workspaceId);
|
|
1399
|
+
}
|
|
1400
|
+
return this.options.store.getThreadRow(threadId)?.agent_type || 'codex';
|
|
1401
|
+
}
|
|
1360
1402
|
async markPermissionCardActionHandled(workspaceId, instanceId, rootPayload, payload, value, response, threadId) {
|
|
1361
1403
|
const state = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
1362
1404
|
if (!state?.client) {
|
|
@@ -7,10 +7,12 @@ class ChannelSessionCommandRuntime {
|
|
|
7
7
|
this.options = options;
|
|
8
8
|
}
|
|
9
9
|
async execute(input) {
|
|
10
|
-
const result = await this.options.
|
|
10
|
+
const result = await this.options.dispatcher.execute({
|
|
11
11
|
workspaceId: input.workspaceId,
|
|
12
|
-
|
|
12
|
+
threadId: input.currentThreadId,
|
|
13
|
+
content: input.text,
|
|
13
14
|
defaultTitle: input.defaultTitle,
|
|
15
|
+
defaultAgentType: input.defaultAgentType,
|
|
14
16
|
});
|
|
15
17
|
if (!result.handled) {
|
|
16
18
|
return { handled: false, threadId: input.currentThreadId };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveChannelThreadRoute = resolveChannelThreadRoute;
|
|
4
|
+
async function resolveChannelThreadRoute(input) {
|
|
5
|
+
const threadBinding = input.store.getPlatformThreadBinding(input.workspaceId, input.chatId, input.platformUserId, input.platformKey);
|
|
6
|
+
let threadId = threadBinding?.thread_id || (input.authorized.chat_id === input.chatId ? input.authorized.thread_id : '') || '';
|
|
7
|
+
let createdThread = false;
|
|
8
|
+
if (!threadId) {
|
|
9
|
+
const thread = await input.router.createThread(input.workspaceId, input.displayName || `${input.fallbackTitlePrefix} ${input.chatId}`);
|
|
10
|
+
threadId = thread.id;
|
|
11
|
+
createdThread = true;
|
|
12
|
+
input.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, threadId, input.platformKey);
|
|
13
|
+
}
|
|
14
|
+
let createdBinding = false;
|
|
15
|
+
if (!threadBinding) {
|
|
16
|
+
const now = new Date().toISOString();
|
|
17
|
+
input.store.upsertPlatformThreadBinding({
|
|
18
|
+
workspace_id: input.workspaceId,
|
|
19
|
+
platform: input.platformKey,
|
|
20
|
+
chat_id: input.chatId,
|
|
21
|
+
platform_user_id: input.platformUserId,
|
|
22
|
+
thread_id: threadId,
|
|
23
|
+
last_platform_message_id: null,
|
|
24
|
+
created_at: now,
|
|
25
|
+
updated_at: now,
|
|
26
|
+
});
|
|
27
|
+
createdBinding = true;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
threadId,
|
|
31
|
+
createdThread,
|
|
32
|
+
createdBinding,
|
|
33
|
+
};
|
|
34
|
+
}
|