@kafca/agentdock 0.1.33 → 0.1.34
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/dist/renderer/assets/{Badge-VeSLCPPV.js → Badge-BDxYXRKv.js} +1 -1
- package/dist/renderer/assets/{Chat-DWTQeTgn.js → Chat-B-ZXd4Ld.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-C9gSQIVb.js → ChatMarkdown-Dn4XvCke.js} +1 -1
- package/dist/renderer/assets/{Config-CTA-pZNR.js → Config-DMOYyKOD.js} +1 -1
- package/dist/renderer/assets/{CronList-BngBCnFY.js → CronList-CMBhMs1J.js} +1 -1
- package/dist/renderer/assets/{Dashboard-D4pGvDpc.js → Dashboard-DApD4wOA.js} +2 -2
- package/dist/renderer/assets/{EmptyState-DMf8rzDs.js → EmptyState-CqcPky2i.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-C1Ym_cHk.js → KnowledgeDetail-DMOXK9Nz.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-DPRiR72G.js → KnowledgeHome-Dv4Ttb6N.js} +1 -1
- package/dist/renderer/assets/{Logs-CRHecmzO.js → Logs-CHrUm25Y.js} +1 -1
- package/dist/renderer/assets/{Modal-BDhhPv2l.js → Modal-Cj_0qtXr.js} +1 -1
- package/dist/renderer/assets/{Page-DdDZN7AE.js → Page-BlKjqLN4.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-DCsr3LkW.js → ProjectDetail-aMl1VGTt.js} +1 -1
- package/dist/renderer/assets/{ProjectList-Cnm-iLvg.js → ProjectList-R2YvsII0.js} +1 -1
- package/dist/renderer/assets/{Select-Dw4FCXhJ.js → Select-CrqwGrrm.js} +1 -1
- package/dist/renderer/assets/{SessionChat-O-6abK8x.js → SessionChat-CGtpyGKR.js} +1 -1
- package/dist/renderer/assets/{SessionList-5yptvVL9.js → SessionList-D8gRUc8M.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-CIM_o2HO.js → ThreadChat-BCGm6bQP.js} +1 -1
- package/dist/renderer/assets/{Workspace-D9UeUCNr.js → Workspace-DnePK6tn.js} +1 -1
- package/dist/renderer/assets/{arrow-left-CKfxNOXE.js → arrow-left-SVmCyBR4.js} +1 -1
- package/dist/renderer/assets/{book-open-CQddlENV.js → book-open-CZi1avEJ.js} +1 -1
- package/dist/renderer/assets/{check-CZYvOmIS.js → check-C76I9BFh.js} +1 -1
- package/dist/renderer/assets/{chevron-down-CVIWFoXF.js → chevron-down-C7YSxzHw.js} +1 -1
- package/dist/renderer/assets/{circle-DSfdQM7k.js → circle-_s8tmsAJ.js} +1 -1
- package/dist/renderer/assets/{desktop-B9KUgeOV.js → desktop-66ot_8sB.js} +1 -1
- package/dist/renderer/assets/{funnel-pB5NegZB.js → funnel-cDV0Q_Mr.js} +1 -1
- package/dist/renderer/assets/{heart-BT5laZ_b.js → heart-qMUQm0tf.js} +1 -1
- package/dist/renderer/assets/{index-BYyDk28K.js → index-BY88QEsS.js} +2 -2
- package/dist/renderer/assets/{index-zTUUYax3.js → index-Cr6erCLm.js} +1 -1
- package/dist/renderer/assets/{pencil-C0thxLi6.js → pencil-C3MA3apq.js} +1 -1
- package/dist/renderer/assets/{play-CmZ0kWtt.js → play-VZKHv5dN.js} +1 -1
- package/dist/renderer/assets/{plug-CeDQatBe.js → plug-Cm7l0fVk.js} +1 -1
- package/dist/renderer/assets/{plus-Di__xFOZ.js → plus-DjGK7f-K.js} +1 -1
- package/dist/renderer/assets/projects-Dcki78KB.js +1 -0
- package/dist/renderer/assets/{save-BDatCjfO.js → save-Doi-FwDR.js} +1 -1
- package/dist/renderer/assets/{search-DnTOjP0C.js → search-DHqpbK_c.js} +1 -1
- package/dist/renderer/assets/{server-Ey_iHY6m.js → server-Bmtxxlph.js} +1 -1
- package/dist/renderer/assets/{session-utils-DWaM7Rkr.js → session-utils-Z-jLtVLY.js} +1 -1
- package/dist/renderer/assets/{sessions-CYYjLD5I.js → sessions-C5TSSo_R.js} +1 -1
- package/dist/renderer/assets/{shield-check-Br8BQzcn.js → shield-check-DhZ05nhI.js} +1 -1
- package/dist/renderer/assets/{trash-2-7YD616fw.js → trash-2-DiyFflVR.js} +1 -1
- package/dist/renderer/assets/{user-BR_5jmr9.js → user-CgsIPd7T.js} +1 -1
- package/dist/renderer/assets/{wifi-off-By9QdREz.js → wifi-off-CqWbWFzp.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +3 -5
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +23 -6
- package/dist-electron/services/local-ai-core/src/cli/lac.js +7 -1
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +9 -19
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +9 -44
- package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +6 -5
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +22 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-application-service.js +84 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-route.js +35 -2
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +5 -5
- package/dist-electron/tests/electron/lac-cli.test.js +50 -0
- package/dist-electron/tests/electron/plugin-kernel.test.js +1 -0
- package/dist-electron/tests/electron/workspace-task-store.test.js +123 -0
- package/dist-electron/tests/integration/local-core-refactor.test.js +12 -3
- package/package.json +1 -1
- package/dist/renderer/assets/projects-B-pbhhtH.js +0 -1
package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-application-service.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScheduledJobApplicationService = void 0;
|
|
4
|
+
const scheduled_job_route_js_1 = require("./scheduled-job-route.js");
|
|
5
|
+
class ScheduledJobApplicationService {
|
|
6
|
+
options;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
listJobs(workspaceId) {
|
|
11
|
+
return this.options.scheduler.listJobs(workspaceId);
|
|
12
|
+
}
|
|
13
|
+
getJob(jobId) {
|
|
14
|
+
return this.options.scheduler.getJob(jobId);
|
|
15
|
+
}
|
|
16
|
+
createJob(input) {
|
|
17
|
+
return this.options.scheduler.createJob(this.resolveCreateInput(input));
|
|
18
|
+
}
|
|
19
|
+
createCronJob(input) {
|
|
20
|
+
return this.options.scheduler.createJob({
|
|
21
|
+
workspaceId: input.workspaceId,
|
|
22
|
+
platform: input.platform,
|
|
23
|
+
route: this.resolveExplicitRoute(input.platform, input.route),
|
|
24
|
+
triggerType: 'cron',
|
|
25
|
+
cronExpr: input.schedule,
|
|
26
|
+
promptTemplate: input.message,
|
|
27
|
+
description: `${input.name} · ${input.scheduleDescription}`,
|
|
28
|
+
enabled: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
updateJob(jobId, input) {
|
|
32
|
+
return this.options.scheduler.updateJob(jobId, {
|
|
33
|
+
...input,
|
|
34
|
+
...(input.route ? { route: (0, scheduled_job_route_js_1.withoutThreadRoute)(input.route) } : {}),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
deleteJob(jobId) {
|
|
38
|
+
return this.options.scheduler.deleteJob(jobId);
|
|
39
|
+
}
|
|
40
|
+
runJobNow(jobId) {
|
|
41
|
+
return this.options.scheduler.runJobNow(jobId);
|
|
42
|
+
}
|
|
43
|
+
listJobRuns(jobId) {
|
|
44
|
+
return this.options.scheduler.listJobRuns(jobId);
|
|
45
|
+
}
|
|
46
|
+
listJobsForThread(threadId) {
|
|
47
|
+
const binding = this.options.store.getPlatformThreadBindingByThreadId(threadId);
|
|
48
|
+
return this.options.scheduler
|
|
49
|
+
.listJobs()
|
|
50
|
+
.filter((job) => job.route.threadId === threadId ||
|
|
51
|
+
(binding ? (0, scheduled_job_route_js_1.scheduledJobMatchesPlatformBinding)(job, binding) : false));
|
|
52
|
+
}
|
|
53
|
+
resolveCreateInput(input) {
|
|
54
|
+
if (input.platform && input.route) {
|
|
55
|
+
return {
|
|
56
|
+
...input,
|
|
57
|
+
route: this.resolveExplicitRoute(input.platform, input.route),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const threadId = String(input.threadId || input.route?.threadId || '').trim();
|
|
61
|
+
if (threadId) {
|
|
62
|
+
const binding = this.options.store.getPlatformThreadBindingByThreadId(threadId);
|
|
63
|
+
if (binding && binding.workspace_id === input.workspaceId) {
|
|
64
|
+
return {
|
|
65
|
+
...input,
|
|
66
|
+
platform: binding.platform,
|
|
67
|
+
route: (0, scheduled_job_route_js_1.routeFromPlatformThreadBinding)(binding),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...input,
|
|
73
|
+
platform: 'local',
|
|
74
|
+
route: {
|
|
75
|
+
type: 'local.thread',
|
|
76
|
+
channelId: input.workspaceId,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
resolveExplicitRoute(platform, route) {
|
|
81
|
+
return (0, scheduled_job_route_js_1.routeWithPlatformInstance)((0, scheduled_job_route_js_1.withoutThreadRoute)(route), platform);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.ScheduledJobApplicationService = ScheduledJobApplicationService;
|
|
@@ -1,15 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.withoutThreadRoute = withoutThreadRoute;
|
|
4
|
+
exports.getChannelPlatformBase = getChannelPlatformBase;
|
|
5
|
+
exports.getChannelPlatformInstanceId = getChannelPlatformInstanceId;
|
|
6
|
+
exports.platformMatches = platformMatches;
|
|
7
|
+
exports.routeWithPlatformInstance = routeWithPlatformInstance;
|
|
8
|
+
exports.routeTypeForPlatform = routeTypeForPlatform;
|
|
9
|
+
exports.routeFromPlatformThreadBinding = routeFromPlatformThreadBinding;
|
|
4
10
|
exports.scheduledJobMatchesPlatformBinding = scheduledJobMatchesPlatformBinding;
|
|
5
11
|
exports.scheduledJobMatchesCliContext = scheduledJobMatchesCliContext;
|
|
6
12
|
function withoutThreadRoute(route) {
|
|
7
13
|
const { threadId: _threadId, ...deliveryRoute } = route;
|
|
8
14
|
return deliveryRoute;
|
|
9
15
|
}
|
|
16
|
+
function getChannelPlatformBase(platform) {
|
|
17
|
+
return String(platform || '').trim().toLowerCase().split(':', 1)[0] || '';
|
|
18
|
+
}
|
|
19
|
+
function getChannelPlatformInstanceId(platform) {
|
|
20
|
+
const normalized = String(platform || '').trim().toLowerCase();
|
|
21
|
+
const separator = normalized.indexOf(':');
|
|
22
|
+
return separator >= 0 ? normalized.slice(separator + 1) : '';
|
|
23
|
+
}
|
|
24
|
+
function platformMatches(candidate, expectedBase) {
|
|
25
|
+
return getChannelPlatformBase(candidate) === expectedBase;
|
|
26
|
+
}
|
|
27
|
+
function routeWithPlatformInstance(route, platform) {
|
|
28
|
+
const instanceId = route.instanceId || getChannelPlatformInstanceId(platform);
|
|
29
|
+
return instanceId ? { ...route, instanceId } : route;
|
|
30
|
+
}
|
|
31
|
+
function routeTypeForPlatform(platform) {
|
|
32
|
+
const base = getChannelPlatformBase(platform);
|
|
33
|
+
return base === 'lark' || base === 'weixin' ? 'channel.chat' : base;
|
|
34
|
+
}
|
|
35
|
+
function routeFromPlatformThreadBinding(binding) {
|
|
36
|
+
return {
|
|
37
|
+
type: routeTypeForPlatform(binding.platform),
|
|
38
|
+
channelId: binding.chat_id,
|
|
39
|
+
instanceId: getChannelPlatformInstanceId(binding.platform) || undefined,
|
|
40
|
+
participantId: binding.platform_user_id,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
10
43
|
function scheduledJobMatchesPlatformBinding(job, binding) {
|
|
11
44
|
return (job.workspaceId === binding.workspace_id &&
|
|
12
|
-
job.platform === binding.platform &&
|
|
45
|
+
getChannelPlatformBase(job.platform) === getChannelPlatformBase(binding.platform) &&
|
|
13
46
|
job.route.channelId === binding.chat_id &&
|
|
14
47
|
String(job.route.participantId || '') === String(binding.platform_user_id || ''));
|
|
15
48
|
}
|
|
@@ -18,7 +51,7 @@ function scheduledJobMatchesCliContext(job, context) {
|
|
|
18
51
|
return false;
|
|
19
52
|
}
|
|
20
53
|
return (job.workspaceId === context.workspaceId &&
|
|
21
|
-
job.platform === context.platform &&
|
|
54
|
+
getChannelPlatformBase(job.platform) === getChannelPlatformBase(context.platform) &&
|
|
22
55
|
job.route.channelId === context.chatId &&
|
|
23
56
|
String(job.route.participantId || '') === String(context.platformUserId || ''));
|
|
24
57
|
}
|
|
@@ -16,7 +16,7 @@ class WeixinScheduleAdapter {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
supports(job) {
|
|
19
|
-
return job.platform
|
|
19
|
+
return (0, scheduled_job_route_js_1.platformMatches)(job.platform, 'weixin') && (job.route.type === 'channel.chat' || job.route.type === 'weixin_chat');
|
|
20
20
|
}
|
|
21
21
|
async execute(context) {
|
|
22
22
|
const { job } = context;
|
|
@@ -32,7 +32,7 @@ class WeixinScheduleAdapter {
|
|
|
32
32
|
if (!channelRuntime.sendScheduledMessage) {
|
|
33
33
|
throw new Error('WeChat channel runtime does not support scheduled delivery.');
|
|
34
34
|
}
|
|
35
|
-
platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, (0, scheduled_job_route_js_1.withoutThreadRoute)(job.route), execution.replyText);
|
|
35
|
+
platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, (0, scheduled_job_route_js_1.routeWithPlatformInstance)((0, scheduled_job_route_js_1.withoutThreadRoute)(job.route), job.platform), execution.replyText);
|
|
36
36
|
if (!platformMessageId) {
|
|
37
37
|
throw new Error('WeChat gateway did not return a message id for scheduled delivery.');
|
|
38
38
|
}
|
|
@@ -49,7 +49,7 @@ class WeixinScheduleAdapter {
|
|
|
49
49
|
const route = job.route;
|
|
50
50
|
const channelId = route.channelId;
|
|
51
51
|
const participantId = route.participantId || '';
|
|
52
|
-
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId,
|
|
52
|
+
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, job.platform);
|
|
53
53
|
if (binding?.thread_id && await this.threadExists(binding.thread_id)) {
|
|
54
54
|
return binding.thread_id;
|
|
55
55
|
}
|
|
@@ -68,9 +68,9 @@ class WeixinScheduleAdapter {
|
|
|
68
68
|
created_at: now,
|
|
69
69
|
updated_at: now,
|
|
70
70
|
});
|
|
71
|
-
const authorized = this.options.store.getAuthorizedUser(job.workspaceId, participantId,
|
|
71
|
+
const authorized = this.options.store.getAuthorizedUser(job.workspaceId, participantId, job.platform);
|
|
72
72
|
if (authorized) {
|
|
73
|
-
this.options.store.updateAuthorizedUserThread(job.workspaceId, participantId, thread.id,
|
|
73
|
+
this.options.store.updateAuthorizedUserThread(job.workspaceId, participantId, thread.id, job.platform);
|
|
74
74
|
}
|
|
75
75
|
return thread.id;
|
|
76
76
|
}
|
|
@@ -214,6 +214,56 @@ function createIo() {
|
|
|
214
214
|
});
|
|
215
215
|
strict_1.default.match(read().stdout, /Sent file out\.pdf to chat-1: msg-file-1/);
|
|
216
216
|
});
|
|
217
|
+
(0, node_test_1.default)('lac channel send-file normalizes instance-qualified platform env into route instance', async () => {
|
|
218
|
+
let capturedUrl = '';
|
|
219
|
+
let capturedBody = null;
|
|
220
|
+
const server = (0, node_http_1.createServer)(async (req, res) => {
|
|
221
|
+
if (req.method === 'POST') {
|
|
222
|
+
capturedUrl = req.url || '';
|
|
223
|
+
const chunks = [];
|
|
224
|
+
for await (const chunk of req) {
|
|
225
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
226
|
+
}
|
|
227
|
+
capturedBody = Buffer.concat(chunks).toString('utf8');
|
|
228
|
+
res.setHeader('content-type', 'application/json');
|
|
229
|
+
res.end(JSON.stringify({
|
|
230
|
+
ok: true,
|
|
231
|
+
data: {
|
|
232
|
+
platform: 'lark',
|
|
233
|
+
workspaceId: '知识库',
|
|
234
|
+
channelId: 'chat-1',
|
|
235
|
+
messageIds: ['msg-file-1'],
|
|
236
|
+
attachments: [{ kind: 'file', fileName: 'out.pdf', fileSize: 123 }],
|
|
237
|
+
},
|
|
238
|
+
}));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
res.statusCode = 404;
|
|
242
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }));
|
|
243
|
+
});
|
|
244
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
245
|
+
const address = server.address();
|
|
246
|
+
(0, strict_1.default)(address && typeof address === 'object');
|
|
247
|
+
const { io } = createIo();
|
|
248
|
+
const exitCode = await (0, lac_js_1.runCli)(['channel', 'send-file', '--path', 'reports/out.pdf'], {
|
|
249
|
+
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
250
|
+
LOCAL_AI_WORKSPACE_ID: '知识库',
|
|
251
|
+
LOCAL_AI_WORKSPACE_PATH: '/workspace/project',
|
|
252
|
+
LOCAL_AI_PLATFORM: 'lark:lark-1',
|
|
253
|
+
LOCAL_AI_CHAT_ID: 'chat-1',
|
|
254
|
+
LOCAL_AI_PLATFORM_USER_ID: 'user-1',
|
|
255
|
+
}, io);
|
|
256
|
+
server.close();
|
|
257
|
+
strict_1.default.equal(exitCode, 0);
|
|
258
|
+
strict_1.default.equal(capturedUrl, '/api/local/v1/platforms/lark/%E7%9F%A5%E8%AF%86%E5%BA%93/messages');
|
|
259
|
+
(0, strict_1.default)(capturedBody);
|
|
260
|
+
strict_1.default.deepEqual(JSON.parse(capturedBody).route, {
|
|
261
|
+
type: 'channel.chat',
|
|
262
|
+
channelId: 'chat-1',
|
|
263
|
+
instanceId: 'lark-1',
|
|
264
|
+
participantId: 'user-1',
|
|
265
|
+
});
|
|
266
|
+
});
|
|
217
267
|
(0, node_test_1.default)('lac channel send-file posts allowed absolute paths through the same outbound message path', async () => {
|
|
218
268
|
let capturedBody = null;
|
|
219
269
|
const server = (0, node_http_1.createServer)(async (req, res) => {
|
|
@@ -82,6 +82,50 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
|
|
|
82
82
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
83
83
|
}
|
|
84
84
|
});
|
|
85
|
+
(0, node_test_1.default)('scheduler create from a bound thread preserves channel instance route', async () => {
|
|
86
|
+
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-instance-route-'));
|
|
87
|
+
try {
|
|
88
|
+
const runtime = (0, bootstrap_js_1.bootstrapLocalCoreRuntime)({
|
|
89
|
+
userDataPath,
|
|
90
|
+
enableKnowledge: false,
|
|
91
|
+
log: () => { },
|
|
92
|
+
});
|
|
93
|
+
const controller = new local_core_controller_js_1.LocalCoreController(userDataPath, runtime);
|
|
94
|
+
const thread = runtime.store.createThread('workspace-a', 'Lark instance thread');
|
|
95
|
+
const now = new Date().toISOString();
|
|
96
|
+
runtime.store.upsertPlatformThreadBinding({
|
|
97
|
+
workspace_id: 'workspace-a',
|
|
98
|
+
platform: 'lark:lark-1',
|
|
99
|
+
chat_id: 'chat-1',
|
|
100
|
+
platform_user_id: 'user-1',
|
|
101
|
+
thread_id: thread.id,
|
|
102
|
+
last_platform_message_id: null,
|
|
103
|
+
created_at: now,
|
|
104
|
+
updated_at: now,
|
|
105
|
+
});
|
|
106
|
+
const job = await controller.createScheduledJob({
|
|
107
|
+
workspaceId: 'workspace-a',
|
|
108
|
+
threadId: thread.id,
|
|
109
|
+
executionMode: 'side-thread',
|
|
110
|
+
triggerType: 'cron',
|
|
111
|
+
cronExpr: '30 18 * * *',
|
|
112
|
+
promptTemplate: 'ping',
|
|
113
|
+
description: 'bound lark task',
|
|
114
|
+
enabled: true,
|
|
115
|
+
});
|
|
116
|
+
strict_1.default.equal(job.platform, 'lark:lark-1');
|
|
117
|
+
strict_1.default.deepEqual(job.route, {
|
|
118
|
+
type: 'channel.chat',
|
|
119
|
+
channelId: 'chat-1',
|
|
120
|
+
instanceId: 'lark-1',
|
|
121
|
+
participantId: 'user-1',
|
|
122
|
+
});
|
|
123
|
+
await controller.close();
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
});
|
|
85
129
|
(0, node_test_1.default)('Lark scheduled same-thread execution resolves the latest channel thread and keeps channel delivery', async () => {
|
|
86
130
|
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-lark-latest-thread-'));
|
|
87
131
|
try {
|
|
@@ -170,6 +214,85 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
|
|
|
170
214
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
171
215
|
}
|
|
172
216
|
});
|
|
217
|
+
(0, node_test_1.default)('Lark scheduled execution supports instance-qualified platform keys', async () => {
|
|
218
|
+
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-lark-instance-'));
|
|
219
|
+
try {
|
|
220
|
+
const store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
|
|
221
|
+
const thread = store.createThread('workspace-a', 'Lark instance thread');
|
|
222
|
+
const now = new Date().toISOString();
|
|
223
|
+
store.upsertPlatformThreadBinding({
|
|
224
|
+
workspace_id: 'workspace-a',
|
|
225
|
+
platform: 'lark:lark-1',
|
|
226
|
+
chat_id: 'chat-1',
|
|
227
|
+
platform_user_id: 'user-1',
|
|
228
|
+
thread_id: thread.id,
|
|
229
|
+
last_platform_message_id: null,
|
|
230
|
+
created_at: now,
|
|
231
|
+
updated_at: now,
|
|
232
|
+
});
|
|
233
|
+
const job = store.createScheduledJob({
|
|
234
|
+
workspaceId: 'workspace-a',
|
|
235
|
+
platform: 'lark:lark-1',
|
|
236
|
+
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1' },
|
|
237
|
+
executionMode: 'same-thread',
|
|
238
|
+
triggerType: 'cron',
|
|
239
|
+
cronExpr: '30 18 * * *',
|
|
240
|
+
promptTemplate: 'ping',
|
|
241
|
+
description: 'bound lark task',
|
|
242
|
+
enabled: true,
|
|
243
|
+
});
|
|
244
|
+
let deliveredRoute;
|
|
245
|
+
const adapter = new lark_schedule_adapter_js_1.LarkScheduleAdapter({
|
|
246
|
+
store,
|
|
247
|
+
getWorkspaceRouter: () => ({
|
|
248
|
+
getThread: async (threadId) => ({
|
|
249
|
+
id: threadId,
|
|
250
|
+
workspaceId: 'workspace-a',
|
|
251
|
+
title: 'Thread',
|
|
252
|
+
live: false,
|
|
253
|
+
updatedAt: now,
|
|
254
|
+
createdAt: now,
|
|
255
|
+
historyCount: 1,
|
|
256
|
+
excerpt: '',
|
|
257
|
+
bridgeSessionKey: '',
|
|
258
|
+
agentType: 'localcore-acp',
|
|
259
|
+
selectedKnowledgeBaseIds: [],
|
|
260
|
+
pendingPermissionRequest: null,
|
|
261
|
+
messages: [{ id: 'message-1', role: 'assistant', kind: 'final', content: 'pong', timestamp: now }],
|
|
262
|
+
}),
|
|
263
|
+
sendThreadMessage: async (threadId, _prompt, options) => {
|
|
264
|
+
strict_1.default.equal(threadId, thread.id);
|
|
265
|
+
strict_1.default.equal(options?.runtimeEnv?.LOCAL_AI_PLATFORM, 'lark');
|
|
266
|
+
strict_1.default.equal(options?.runtimeEnv?.LOCAL_AI_PLATFORM_INSTANCE_ID, 'lark-1');
|
|
267
|
+
strict_1.default.equal(options?.runtimeEnv?.LOCAL_AI_CHAT_ID, 'chat-1');
|
|
268
|
+
store.updateRun('run-1', threadId, 'completed');
|
|
269
|
+
return { runId: 'run-1' };
|
|
270
|
+
},
|
|
271
|
+
}),
|
|
272
|
+
getChannelRuntime: () => ({
|
|
273
|
+
muteThreadBridge: () => { },
|
|
274
|
+
unmuteThreadBridge: () => { },
|
|
275
|
+
sendScheduledMessage: async (_workspaceId, route) => {
|
|
276
|
+
deliveredRoute = route;
|
|
277
|
+
return 'platform-message-1';
|
|
278
|
+
},
|
|
279
|
+
}),
|
|
280
|
+
});
|
|
281
|
+
const result = await adapter.execute({ job, triggeredAt: now });
|
|
282
|
+
strict_1.default.equal(result.threadId, thread.id);
|
|
283
|
+
strict_1.default.equal(result.platformMessageId, 'platform-message-1');
|
|
284
|
+
strict_1.default.deepEqual(deliveredRoute, {
|
|
285
|
+
type: 'channel.chat',
|
|
286
|
+
channelId: 'chat-1',
|
|
287
|
+
instanceId: 'lark-1',
|
|
288
|
+
participantId: 'user-1',
|
|
289
|
+
});
|
|
290
|
+
store.close();
|
|
291
|
+
}
|
|
292
|
+
finally {
|
|
293
|
+
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
294
|
+
}
|
|
295
|
+
});
|
|
173
296
|
(0, node_test_1.default)('ACP runtime env includes the current workspace path for file returns', async () => {
|
|
174
297
|
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'workspace-env-'));
|
|
175
298
|
try {
|
|
@@ -3512,11 +3512,12 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
|
|
|
3512
3512
|
});
|
|
3513
3513
|
(0, node_test_1.default)('scheduled conversation executor uses execution policy hooks around a thread run', async () => {
|
|
3514
3514
|
const calls = [];
|
|
3515
|
+
let runtimeEnv;
|
|
3515
3516
|
const job = {
|
|
3516
3517
|
id: 'job-1',
|
|
3517
3518
|
workspaceId: '知识库',
|
|
3518
|
-
platform: 'lark',
|
|
3519
|
-
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-1' },
|
|
3519
|
+
platform: 'lark:lark-1',
|
|
3520
|
+
route: { type: 'channel.chat', channelId: 'chat-1', instanceId: 'lark-1', participantId: 'user-1', threadId: 'thread-1' },
|
|
3520
3521
|
executionMode: 'same-thread',
|
|
3521
3522
|
triggerType: 'cron',
|
|
3522
3523
|
cronExpr: '*/2 * * * *',
|
|
@@ -3533,6 +3534,7 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
|
|
|
3533
3534
|
},
|
|
3534
3535
|
workspaceRouter: {
|
|
3535
3536
|
sendThreadMessage: async (threadId, prompt, options) => {
|
|
3537
|
+
runtimeEnv = options?.runtimeEnv;
|
|
3536
3538
|
calls.push(`send:${threadId}:${prompt}:${options?.permissionMode || ''}`);
|
|
3537
3539
|
return { runId: 'run-1' };
|
|
3538
3540
|
},
|
|
@@ -3549,7 +3551,7 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
|
|
|
3549
3551
|
kind: 'thread',
|
|
3550
3552
|
threadId: 'thread-1',
|
|
3551
3553
|
workspaceId: '知识库',
|
|
3552
|
-
platform: 'lark',
|
|
3554
|
+
platform: 'lark:lark-1',
|
|
3553
3555
|
route: job.route,
|
|
3554
3556
|
}),
|
|
3555
3557
|
beforeExecute: (target) => {
|
|
@@ -3564,6 +3566,13 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
|
|
|
3564
3566
|
'send:thread-1:ping:bypassPermissions',
|
|
3565
3567
|
'after:thread-1',
|
|
3566
3568
|
]);
|
|
3569
|
+
strict_1.default.deepEqual(runtimeEnv, {
|
|
3570
|
+
LOCAL_AI_PLATFORM: 'lark',
|
|
3571
|
+
LOCAL_AI_ROUTE_TYPE: 'channel.chat',
|
|
3572
|
+
LOCAL_AI_PLATFORM_INSTANCE_ID: 'lark-1',
|
|
3573
|
+
LOCAL_AI_CHAT_ID: 'chat-1',
|
|
3574
|
+
LOCAL_AI_PLATFORM_USER_ID: 'user-1',
|
|
3575
|
+
});
|
|
3567
3576
|
strict_1.default.equal(result.replyText, 'done');
|
|
3568
3577
|
});
|
|
3569
3578
|
(0, node_test_1.default)('local scheduler adapter runs a workspace thread without channel delivery', async () => {
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{z as t}from"./index-BYyDk28K.js";const e=()=>t.get("/projects"),r=o=>t.get(`/projects/${o}`);export{r as g,e as l};
|