@kafca/agentdock 0.1.57 → 0.1.58
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-CDTbmw1h.js → Badge-BfY1VaHS.js} +1 -1
- package/dist/renderer/assets/{Card-DayUo35w.js → Card-DWA_Tww_.js} +1 -1
- package/dist/renderer/assets/{Config-ByGMQuzR.js → Config-nHj3g1U5.js} +1 -1
- package/dist/renderer/assets/{CronList-XqHdVlgu.js → CronList-BwkA_I7v.js} +1 -1
- package/dist/renderer/assets/{Dashboard-CZj-oANw.js → Dashboard-D0_A7k02.js} +2 -2
- package/dist/renderer/assets/{EmptyState-EFMkOjZO.js → EmptyState-zatDjLj_.js} +1 -1
- package/dist/renderer/assets/{HighlightedMarkdown-DyvF3DHK.js → HighlightedMarkdown-CsM5n70d.js} +1 -1
- package/dist/renderer/assets/{Input-DxoWVc9d.js → Input-R1XdFK1K.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-CbUb2tG7.js → KnowledgeDetail-Co5sxeGd.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-BWV1gz4f.js → KnowledgeHome-DwziPw5m.js} +1 -1
- package/dist/renderer/assets/{Logs-DqnanQTc.js → Logs-NwZUtR_G.js} +1 -1
- package/dist/renderer/assets/{Modal-yY7TzR0x.js → Modal-CrcIwIFL.js} +1 -1
- package/dist/renderer/assets/{MonitorList-CIjGQkFs.js → MonitorList-CS1uLS5A.js} +1 -1
- package/dist/renderer/assets/{Page-vwHNUdoj.js → Page-Dp0obeSw.js} +1 -1
- package/dist/renderer/assets/{Select-CmbK36pN.js → Select-6mVQaf84.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-4OceMgM4.js → ThreadChat-BFzbn3L6.js} +3 -3
- package/dist/renderer/assets/{Workspace-DplPJOjJ.js → Workspace-DCmo8BMm.js} +1 -1
- package/dist/renderer/assets/{arrow-left-C8HfBt2K.js → arrow-left-9rjg_Hp4.js} +1 -1
- package/dist/renderer/assets/{book-open-BCdZWncQ.js → book-open-Bu8GCHnG.js} +1 -1
- package/dist/renderer/assets/{channels-hgO3cAIx.js → channels-BxVbG-6j.js} +1 -1
- package/dist/renderer/assets/{chevron-down-BPk77tqY.js → chevron-down-BE8uQmWM.js} +1 -1
- package/dist/renderer/assets/{index-BlA4xPdd.js → index-B7TeF6Es.js} +1 -1
- package/dist/renderer/assets/{index-wYpjqVqC.js → index-BkI9POxj.js} +2 -2
- package/dist/renderer/assets/{knowledge-7pl06KuH.js → knowledge-Kl19SqGS.js} +1 -1
- package/dist/renderer/assets/{pencil-CB1SWZ9A.js → pencil-CPB7SK1m.js} +1 -1
- package/dist/renderer/assets/{play-BvsoXUrM.js → play-DGAO4OCu.js} +1 -1
- package/dist/renderer/assets/{plus-CokBDnaL.js → plus-Bt26z-4q.js} +1 -1
- package/dist/renderer/assets/{save-D-w4kATO.js → save-Une7GMxT.js} +1 -1
- package/dist/renderer/assets/{search-Cnsn6i4Q.js → search-DE0agJjJ.js} +1 -1
- package/dist/renderer/assets/{shield-check-Cjja2Gh6.js → shield-check-De7xaXZh.js} +1 -1
- package/dist/renderer/assets/{threads-BCm6j4eI.js → threads-BnsNL5ei.js} +1 -1
- package/dist/renderer/assets/{trash-2-CIxz9qYY.js → trash-2-6iGF59Ac.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +6 -47
- package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +2 -5
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +6 -53
- package/dist-electron/services/local-ai-core/src/channel/lark/outbound-transport.js +25 -37
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +5 -20
- package/dist-electron/services/local-ai-core/src/channel/shared/base-channel-gateway.js +37 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/bridge-event-helpers.js +23 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/channel-keys.js +6 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +2 -2
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +6 -44
- package/dist-electron/services/local-ai-core/src/channel/weixin/runtime-state.js +4 -11
- package/dist-electron/services/local-ai-core/src/channel/weixin/text-utils.js +0 -8
- package/dist-electron/services/local-ai-core/src/cli/lac.js +3 -5
- package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +8 -0
- package/dist-electron/services/local-ai-core/src/sandbox/opensandbox-client.js +3 -2
- package/dist-electron/services/local-ai-core/src/scheduler/base-channel-schedule-adapter.js +77 -0
- package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +13 -79
- package/dist-electron/services/local-ai-core/src/scheduler/local-schedule-adapter.js +2 -10
- package/dist-electron/services/local-ai-core/src/scheduler/run-polling.js +19 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +3 -37
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-route.js +20 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +15 -28
- package/dist-electron/services/local-ai-core/src/scheduler/thread-resolution.js +12 -0
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +13 -79
- package/dist-electron/tests/integration/local-core-refactor.test.js +15 -8
- package/package.json +1 -1
- package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +0 -13
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +0 -13
package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js
CHANGED
|
@@ -16,6 +16,7 @@ const thread_routing_js_1 = require("../shared/thread-routing.js");
|
|
|
16
16
|
const base_channel_gateway_js_1 = require("../shared/base-channel-gateway.js");
|
|
17
17
|
const inbound_authorization_js_1 = require("../shared/inbound-authorization.js");
|
|
18
18
|
const channel_keys_js_1 = require("../shared/channel-keys.js");
|
|
19
|
+
const local_core_slash_commands_js_1 = require("../../acp/local-core-slash-commands.js");
|
|
19
20
|
const config_js_1 = require("./config.js");
|
|
20
21
|
const transport_js_1 = require("./transport.js");
|
|
21
22
|
const runtime_state_js_1 = require("./runtime-state.js");
|
|
@@ -201,10 +202,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
|
|
|
201
202
|
&& event.type !== 'status') {
|
|
202
203
|
return;
|
|
203
204
|
}
|
|
204
|
-
const
|
|
205
|
-
const current = previous
|
|
206
|
-
.catch(() => undefined)
|
|
207
|
-
.then(async () => {
|
|
205
|
+
const current = this.scheduleOutboundChain(sessionKey, async () => {
|
|
208
206
|
const binding = this.options.store.getPlatformThreadBinding(route.workspaceId, route.chatId, route.platformUserId, routePlatformKey);
|
|
209
207
|
if (!binding)
|
|
210
208
|
return;
|
|
@@ -246,19 +244,13 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
|
|
|
246
244
|
this.options.log?.(`localcore-weixin sent message for sessionKey=${sessionKey} type=${event.type} sent=${turn.sentCount}/${binding.last_platform_message_id ? WEIXIN_CONTEXT_SEND_LIMIT : 'unlimited'}`);
|
|
247
245
|
}
|
|
248
246
|
catch (error) {
|
|
249
|
-
this.options.log?.(`localcore-weixin send failed for sessionKey=${sessionKey}: ${(0,
|
|
250
|
-
}
|
|
251
|
-
})
|
|
252
|
-
.finally(() => {
|
|
253
|
-
if (this.outboundEventChains.get(sessionKey) === current) {
|
|
254
|
-
this.outboundEventChains.delete(sessionKey);
|
|
247
|
+
this.options.log?.(`localcore-weixin send failed for sessionKey=${sessionKey}: ${(0, local_core_errors_js_1.formatSafeError)(error)}`);
|
|
255
248
|
}
|
|
256
249
|
});
|
|
257
|
-
this.outboundEventChains.set(sessionKey, current);
|
|
258
250
|
await current;
|
|
259
251
|
}
|
|
260
252
|
registerScheduledThreadBridge(input) {
|
|
261
|
-
const instanceId = input.route.instanceId ||
|
|
253
|
+
const instanceId = input.route.instanceId || (0, channel_keys_js_1.extractChannelInstanceId)(input.platform, 'weixin') || 'default';
|
|
262
254
|
const platformKey = (0, channel_keys_js_1.channelPlatformKey)('weixin', instanceId);
|
|
263
255
|
const route = {
|
|
264
256
|
workspaceId: input.workspaceId,
|
|
@@ -413,7 +405,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
|
|
|
413
405
|
authorized,
|
|
414
406
|
});
|
|
415
407
|
const normalizedText = String(msg.text || '').trim().toLowerCase();
|
|
416
|
-
const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny') ? this.findAwaitingPermissionThreadId(msg.workspaceId, msg.chatId, msg.platformUserId, msg.platformKey) : '';
|
|
408
|
+
const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny') ? this.findAwaitingPermissionThreadId(msg.workspaceId, msg.chatId, msg.platformUserId, msg.platformKey || 'weixin') : '';
|
|
417
409
|
if (permissionThreadId && permissionThreadId !== threadId) {
|
|
418
410
|
threadId = permissionThreadId;
|
|
419
411
|
}
|
|
@@ -427,7 +419,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
|
|
|
427
419
|
threadId,
|
|
428
420
|
});
|
|
429
421
|
// Handle slash commands
|
|
430
|
-
const slashCommand =
|
|
422
|
+
const slashCommand = (0, local_core_slash_commands_js_1.parseSlashCommand)(msg.text);
|
|
431
423
|
const sessionCommand = await this.executeSessionCommand({
|
|
432
424
|
workspaceId: msg.workspaceId,
|
|
433
425
|
currentThreadId: threadId,
|
|
@@ -453,13 +445,6 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
|
|
|
453
445
|
await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(msg.text, msg.contentParts));
|
|
454
446
|
return;
|
|
455
447
|
}
|
|
456
|
-
async resolveDefaultAgentType(workspaceId, threadId) {
|
|
457
|
-
const router = this.options.getWorkspaceRouter();
|
|
458
|
-
if (typeof router.getWorkspaceDefaultAgentType === 'function') {
|
|
459
|
-
return router.getWorkspaceDefaultAgentType(workspaceId);
|
|
460
|
-
}
|
|
461
|
-
return this.options.store.getThreadRow(threadId)?.agent_type || 'codex';
|
|
462
|
-
}
|
|
463
448
|
// ==================== Private: Bindings ====================
|
|
464
449
|
// ==================== Private: Workspace Lifecycle ====================
|
|
465
450
|
async startWorkspace(binding) {
|
|
@@ -723,28 +708,5 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
|
|
|
723
708
|
this.processedInboundMessages.set(key, now + PROCESSED_MESSAGE_TTL_MS);
|
|
724
709
|
return false;
|
|
725
710
|
}
|
|
726
|
-
findAwaitingPermissionThreadId(workspaceId, chatId, platformUserId, platformKey = 'weixin') {
|
|
727
|
-
for (const [sessionKey, route] of this.threadRouting.entries()) {
|
|
728
|
-
if (route.workspaceId !== workspaceId || route.platformKey !== platformKey || route.chatId !== chatId || route.platformUserId !== platformUserId)
|
|
729
|
-
continue;
|
|
730
|
-
const turn = this.outboundTurns.get(sessionKey);
|
|
731
|
-
if (turn?.awaitingPermission && route.threadId)
|
|
732
|
-
return route.threadId;
|
|
733
|
-
}
|
|
734
|
-
return '';
|
|
735
|
-
}
|
|
736
|
-
parseSlashCommand(text) {
|
|
737
|
-
const normalized = String(text || '').trim();
|
|
738
|
-
if (!normalized.startsWith('/'))
|
|
739
|
-
return null;
|
|
740
|
-
const [name = '', ...args] = normalized.slice(1).split(/\s+/);
|
|
741
|
-
if (!name)
|
|
742
|
-
return null;
|
|
743
|
-
return { name: name.trim().toLowerCase(), args };
|
|
744
|
-
}
|
|
745
711
|
}
|
|
746
712
|
exports.LocalCoreWeixinGateway = LocalCoreWeixinGateway;
|
|
747
|
-
function getWeixinInstanceId(platform) {
|
|
748
|
-
const normalized = String(platform || '').trim();
|
|
749
|
-
return normalized.startsWith('weixin:') ? normalized.slice('weixin:'.length).trim() : '';
|
|
750
|
-
}
|
|
@@ -5,6 +5,7 @@ exports.getOrCreateWeixinTurnState = getOrCreateWeixinTurnState;
|
|
|
5
5
|
exports.consumeWeixinBridgeEvent = consumeWeixinBridgeEvent;
|
|
6
6
|
exports.renderWeixinTurnText = renderWeixinTurnText;
|
|
7
7
|
exports.isTerminalWeixinBridgeMessage = isTerminalWeixinBridgeMessage;
|
|
8
|
+
const bridge_event_helpers_js_1 = require("../shared/bridge-event-helpers.js");
|
|
8
9
|
function renderBridgeContent(event) {
|
|
9
10
|
const toolCall = event.toolCall;
|
|
10
11
|
if (!toolCall) {
|
|
@@ -16,16 +17,8 @@ function renderBridgeContent(event) {
|
|
|
16
17
|
return '';
|
|
17
18
|
return [name, status].filter(Boolean).join(' - ');
|
|
18
19
|
}
|
|
19
|
-
function bridgeEventKind(event) {
|
|
20
|
-
return event.bridgeKind || (event.type === 'status' ? 'status' : 'assistant');
|
|
21
|
-
}
|
|
22
20
|
function pushUnique(target, value) {
|
|
23
|
-
|
|
24
|
-
if (!normalized || target[target.length - 1] === normalized)
|
|
25
|
-
return;
|
|
26
|
-
target.push(normalized);
|
|
27
|
-
if (target.length > 8)
|
|
28
|
-
target.splice(0, target.length - 8);
|
|
21
|
+
(0, bridge_event_helpers_js_1.pushUniqueLine)(target, value, 8);
|
|
29
22
|
}
|
|
30
23
|
function flushPendingThought(turn) {
|
|
31
24
|
const text = String(turn.pendingThoughtText || '').trim();
|
|
@@ -61,7 +54,7 @@ function getOrCreateWeixinTurnState(turns, sessionKey) {
|
|
|
61
54
|
}
|
|
62
55
|
function consumeWeixinBridgeEvent(turn, event) {
|
|
63
56
|
const content = renderBridgeContent(event);
|
|
64
|
-
const bridgeKind =
|
|
57
|
+
const bridgeKind = (0, bridge_event_helpers_js_1.resolveBridgeEventKind)(event);
|
|
65
58
|
if (event.type === 'typing_start') {
|
|
66
59
|
Object.assign(turn, {
|
|
67
60
|
processing: true,
|
|
@@ -149,7 +142,7 @@ function isTerminalWeixinBridgeMessage(event, rendered) {
|
|
|
149
142
|
return true;
|
|
150
143
|
if (event.type !== 'reply')
|
|
151
144
|
return false;
|
|
152
|
-
const kind =
|
|
145
|
+
const kind = (0, bridge_event_helpers_js_1.resolveBridgeEventKind)(event);
|
|
153
146
|
if (kind === 'tool' || kind === 'thought' || kind === 'plan' || kind === 'status')
|
|
154
147
|
return false;
|
|
155
148
|
return Boolean(rendered.trim());
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.stripWeixinHtml = stripWeixinHtml;
|
|
4
|
-
exports.formatWeixinError = formatWeixinError;
|
|
5
4
|
exports.waitForWeixinRetry = waitForWeixinRetry;
|
|
6
5
|
exports.utf8ByteLength = utf8ByteLength;
|
|
7
6
|
exports.splitTextByUtf8Bytes = splitTextByUtf8Bytes;
|
|
@@ -21,13 +20,6 @@ function stripWeixinHtml(html) {
|
|
|
21
20
|
.replace(/'/g, "'")
|
|
22
21
|
.replace(/ /g, ' ');
|
|
23
22
|
}
|
|
24
|
-
function formatWeixinError(error) {
|
|
25
|
-
if (error instanceof Error) {
|
|
26
|
-
const cause = error.cause;
|
|
27
|
-
return cause !== undefined ? `${error.message}: ${String(cause)}` : error.message;
|
|
28
|
-
}
|
|
29
|
-
return String(error);
|
|
30
|
-
}
|
|
31
23
|
function waitForWeixinRetry(ms, signal) {
|
|
32
24
|
return new Promise((resolve, reject) => {
|
|
33
25
|
const timer = setTimeout(resolve, ms);
|
|
@@ -10,6 +10,7 @@ const job_id_js_1 = require("../scheduler/job-id.js");
|
|
|
10
10
|
const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
|
|
11
11
|
const monitor_id_js_1 = require("../automation/monitor-id.js");
|
|
12
12
|
const monitor_cli_parsers_js_1 = require("./monitor-cli-parsers.js");
|
|
13
|
+
const local_core_errors_js_1 = require("../kernel/local-core-errors.js");
|
|
13
14
|
const DEFAULT_BASE_URL = 'http://127.0.0.1:9831/api/local/v1';
|
|
14
15
|
async function runCli(argv, env = node_process_1.default.env, io = node_process_1.default) {
|
|
15
16
|
try {
|
|
@@ -69,7 +70,7 @@ async function runCli(argv, env = node_process_1.default.env, io = node_process_
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
catch (error) {
|
|
72
|
-
io.stderr.write(`${
|
|
73
|
+
io.stderr.write(`${(0, local_core_errors_js_1.formatSafeError)(error)}\n`);
|
|
73
74
|
return 1;
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -324,7 +325,7 @@ async function request(baseUrl, method, path, body) {
|
|
|
324
325
|
});
|
|
325
326
|
}
|
|
326
327
|
catch (error) {
|
|
327
|
-
throw new Error(`Local AI Core is unavailable at ${baseUrl}: ${
|
|
328
|
+
throw new Error(`Local AI Core is unavailable at ${baseUrl}: ${(0, local_core_errors_js_1.formatSafeError)(error)}`);
|
|
328
329
|
}
|
|
329
330
|
const payload = await response.json();
|
|
330
331
|
if (!response.ok || !payload.ok) {
|
|
@@ -517,9 +518,6 @@ function monitorMatchesCliContext(monitor, context) {
|
|
|
517
518
|
updatedAt: monitor.updatedAt,
|
|
518
519
|
}, context);
|
|
519
520
|
}
|
|
520
|
-
function formatError(error) {
|
|
521
|
-
return error instanceof Error ? error.message : String(error);
|
|
522
|
-
}
|
|
523
521
|
void (async () => {
|
|
524
522
|
if (require.main !== module) {
|
|
525
523
|
return;
|
|
@@ -4,6 +4,7 @@ exports.LocalCoreErrorReporter = exports.LocalCoreError = void 0;
|
|
|
4
4
|
exports.toLocalCoreErrorInfo = toLocalCoreErrorInfo;
|
|
5
5
|
exports.formatUserError = formatUserError;
|
|
6
6
|
exports.formatLogError = formatLogError;
|
|
7
|
+
exports.formatSafeError = formatSafeError;
|
|
7
8
|
exports.errorInfoToHttpBody = errorInfoToHttpBody;
|
|
8
9
|
const DEFAULTS = {
|
|
9
10
|
runtime_not_found: {
|
|
@@ -175,6 +176,13 @@ function formatLogError(info) {
|
|
|
175
176
|
const message = typeof info.message === 'string' ? info.message : safeStringify(info.message);
|
|
176
177
|
return `${info.code}: ${message}${suffix}`;
|
|
177
178
|
}
|
|
179
|
+
function formatSafeError(error) {
|
|
180
|
+
if (error instanceof Error) {
|
|
181
|
+
const cause = error.cause;
|
|
182
|
+
return cause !== undefined ? `${error.message}: ${cause instanceof Error ? cause.message : coerceErrorMessage(cause)}` : error.message;
|
|
183
|
+
}
|
|
184
|
+
return coerceErrorMessage(error);
|
|
185
|
+
}
|
|
178
186
|
function errorInfoToHttpBody(info) {
|
|
179
187
|
return {
|
|
180
188
|
ok: false,
|
|
@@ -82,8 +82,9 @@ class OpenSandboxClient {
|
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
catch (error) {
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
const message = (0, local_core_errors_js_1.formatSafeError)(error);
|
|
86
|
+
throw new local_core_errors_js_1.LocalCoreError('sandbox_unavailable', `OpenSandbox request failed: ${message}`, {
|
|
87
|
+
cause: message,
|
|
87
88
|
details: { method, path, serverUrl: this.options.serverUrl },
|
|
88
89
|
});
|
|
89
90
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseChannelScheduleAdapter = void 0;
|
|
4
|
+
const scheduled_conversation_executor_js_1 = require("./scheduled-conversation-executor.js");
|
|
5
|
+
const scheduled_job_route_js_1 = require("./scheduled-job-route.js");
|
|
6
|
+
const thread_resolution_js_1 = require("./thread-resolution.js");
|
|
7
|
+
class BaseChannelScheduleAdapter {
|
|
8
|
+
options;
|
|
9
|
+
executor;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.options = options;
|
|
12
|
+
this.executor = new scheduled_conversation_executor_js_1.ScheduledConversationExecutor({
|
|
13
|
+
store: options.store,
|
|
14
|
+
getWorkspaceRouter: options.getWorkspaceRouter,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
supports(job) {
|
|
18
|
+
return (0, scheduled_job_route_js_1.platformMatches)(job.platform, this.platformBase) && this.supportedRouteTypes.includes(job.route.type);
|
|
19
|
+
}
|
|
20
|
+
async execute(context) {
|
|
21
|
+
const { job } = context;
|
|
22
|
+
const executionPolicy = this.createPolicy(job, {
|
|
23
|
+
store: this.options.store,
|
|
24
|
+
workspaceRouter: this.options.getWorkspaceRouter(),
|
|
25
|
+
getChannelRuntime: this.options.getChannelRuntime,
|
|
26
|
+
}, (nextJob) => this.resolveThread(nextJob), (nextJob) => this.preferredAgentFor(nextJob));
|
|
27
|
+
const execution = await this.executor.execute(job, job.promptTemplate, executionPolicy);
|
|
28
|
+
return {
|
|
29
|
+
threadId: execution.threadId,
|
|
30
|
+
runId: execution.runId,
|
|
31
|
+
replyText: execution.replyText,
|
|
32
|
+
deliveryMode: 'bridge-stream',
|
|
33
|
+
deliveryStatus: 'succeeded',
|
|
34
|
+
lastBridgeEventAt: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async resolveThread(job) {
|
|
38
|
+
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
39
|
+
const route = job.route;
|
|
40
|
+
const channelId = route.channelId;
|
|
41
|
+
const participantId = route.participantId || '';
|
|
42
|
+
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, job.platform);
|
|
43
|
+
if (binding?.thread_id && await (0, thread_resolution_js_1.threadExists)(workspaceRouter, binding.thread_id)) {
|
|
44
|
+
return binding.thread_id;
|
|
45
|
+
}
|
|
46
|
+
if (route.threadId && await (0, thread_resolution_js_1.threadExists)(workspaceRouter, route.threadId)) {
|
|
47
|
+
return route.threadId;
|
|
48
|
+
}
|
|
49
|
+
const thread = await workspaceRouter.createThread(job.workspaceId, job.description || `Scheduled ${job.platform} task`);
|
|
50
|
+
const now = new Date().toISOString();
|
|
51
|
+
this.options.store.upsertPlatformThreadBinding({
|
|
52
|
+
workspace_id: job.workspaceId,
|
|
53
|
+
platform: job.platform,
|
|
54
|
+
chat_id: channelId,
|
|
55
|
+
platform_user_id: participantId,
|
|
56
|
+
thread_id: thread.id,
|
|
57
|
+
last_platform_message_id: null,
|
|
58
|
+
created_at: now,
|
|
59
|
+
updated_at: now,
|
|
60
|
+
});
|
|
61
|
+
const authorized = this.options.store.getAuthorizedUser(job.workspaceId, participantId, job.platform);
|
|
62
|
+
if (authorized) {
|
|
63
|
+
this.options.store.updateAuthorizedUserThread(job.workspaceId, participantId, thread.id, job.platform);
|
|
64
|
+
}
|
|
65
|
+
return thread.id;
|
|
66
|
+
}
|
|
67
|
+
preferredAgentFor(job) {
|
|
68
|
+
const route = job.route;
|
|
69
|
+
const channelId = route.channelId;
|
|
70
|
+
if (!channelId)
|
|
71
|
+
return '';
|
|
72
|
+
const participantId = route.participantId || '';
|
|
73
|
+
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, job.platform);
|
|
74
|
+
return binding?.preferred_agent_type || '';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.BaseChannelScheduleAdapter = BaseChannelScheduleAdapter;
|
|
@@ -1,87 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LarkScheduleAdapter = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
executor;
|
|
4
|
+
const channel_execution_policy_js_1 = require("./channel-execution-policy.js");
|
|
5
|
+
const base_channel_schedule_adapter_js_1 = require("./base-channel-schedule-adapter.js");
|
|
6
|
+
class LarkScheduleAdapter extends base_channel_schedule_adapter_js_1.BaseChannelScheduleAdapter {
|
|
7
|
+
platformBase = 'lark';
|
|
8
|
+
supportedRouteTypes = ['channel.chat', 'lark_chat'];
|
|
10
9
|
deliveryTargets = ['lark'];
|
|
11
|
-
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
createPolicy(job, options, resolveSameThread, preferredAgentType) {
|
|
11
|
+
const label = this.platformBase.charAt(0).toUpperCase() + this.platformBase.slice(1);
|
|
12
|
+
return (0, channel_execution_policy_js_1.createChannelExecutionPolicy)(job, options, {
|
|
13
|
+
platformBase: this.platformBase,
|
|
14
|
+
resolveSameThread,
|
|
15
|
+
sideThreadTitle: (nextJob) => `[Scheduled:${label}] ${nextJob.description || nextJob.id}`,
|
|
16
|
+
legacySideThreadTitles: (nextJob) => [`[Scheduled] ${nextJob.description || nextJob.id}`],
|
|
17
|
+
preferredAgentType,
|
|
16
18
|
});
|
|
17
19
|
}
|
|
18
|
-
supports(job) {
|
|
19
|
-
return (0, scheduled_job_route_js_1.platformMatches)(job.platform, 'lark') && (job.route.type === 'channel.chat' || job.route.type === 'lark_chat');
|
|
20
|
-
}
|
|
21
|
-
async execute(context) {
|
|
22
|
-
const { job } = context;
|
|
23
|
-
const executionPolicy = (0, lark_execution_policies_js_1.createLarkExecutionPolicy)(job, {
|
|
24
|
-
store: this.options.store,
|
|
25
|
-
workspaceRouter: this.options.getWorkspaceRouter(),
|
|
26
|
-
getChannelRuntime: this.options.getChannelRuntime,
|
|
27
|
-
}, (nextJob) => this.resolveThread(nextJob), (nextJob) => this.preferredAgentFor(nextJob));
|
|
28
|
-
const execution = await this.executor.execute(job, job.promptTemplate, executionPolicy);
|
|
29
|
-
return {
|
|
30
|
-
threadId: execution.threadId,
|
|
31
|
-
runId: execution.runId,
|
|
32
|
-
replyText: execution.replyText,
|
|
33
|
-
deliveryMode: 'bridge-stream',
|
|
34
|
-
deliveryStatus: 'succeeded',
|
|
35
|
-
lastBridgeEventAt: new Date().toISOString(),
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
async resolveThread(job) {
|
|
39
|
-
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
40
|
-
const route = job.route;
|
|
41
|
-
const channelId = route.channelId;
|
|
42
|
-
const participantId = route.participantId || '';
|
|
43
|
-
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, job.platform);
|
|
44
|
-
if (binding?.thread_id && await this.threadExists(binding.thread_id)) {
|
|
45
|
-
return binding.thread_id;
|
|
46
|
-
}
|
|
47
|
-
if (route.threadId && await this.threadExists(route.threadId)) {
|
|
48
|
-
return route.threadId;
|
|
49
|
-
}
|
|
50
|
-
const thread = await workspaceRouter.createThread(job.workspaceId, job.description || `Scheduled ${job.platform} task`);
|
|
51
|
-
const now = new Date().toISOString();
|
|
52
|
-
this.options.store.upsertPlatformThreadBinding({
|
|
53
|
-
workspace_id: job.workspaceId,
|
|
54
|
-
platform: job.platform,
|
|
55
|
-
chat_id: channelId,
|
|
56
|
-
platform_user_id: participantId,
|
|
57
|
-
thread_id: thread.id,
|
|
58
|
-
last_platform_message_id: null,
|
|
59
|
-
created_at: now,
|
|
60
|
-
updated_at: now,
|
|
61
|
-
});
|
|
62
|
-
const authorized = this.options.store.getAuthorizedUser(job.workspaceId, participantId, job.platform);
|
|
63
|
-
if (authorized) {
|
|
64
|
-
this.options.store.updateAuthorizedUserThread(job.workspaceId, participantId, thread.id, job.platform);
|
|
65
|
-
}
|
|
66
|
-
return thread.id;
|
|
67
|
-
}
|
|
68
|
-
async threadExists(threadId) {
|
|
69
|
-
try {
|
|
70
|
-
await this.options.getWorkspaceRouter().getThread(threadId);
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
preferredAgentFor(job) {
|
|
78
|
-
const route = job.route;
|
|
79
|
-
const channelId = route.channelId;
|
|
80
|
-
if (!channelId)
|
|
81
|
-
return '';
|
|
82
|
-
const participantId = route.participantId || '';
|
|
83
|
-
const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, job.platform);
|
|
84
|
-
return binding?.preferred_agent_type || '';
|
|
85
|
-
}
|
|
86
20
|
}
|
|
87
21
|
exports.LarkScheduleAdapter = LarkScheduleAdapter;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LocalScheduleAdapter = void 0;
|
|
4
4
|
const scheduled_conversation_executor_js_1 = require("./scheduled-conversation-executor.js");
|
|
5
|
+
const thread_resolution_js_1 = require("./thread-resolution.js");
|
|
5
6
|
class LocalScheduleAdapter {
|
|
6
7
|
options;
|
|
7
8
|
executor;
|
|
@@ -40,7 +41,7 @@ class LocalScheduleAdapter {
|
|
|
40
41
|
}
|
|
41
42
|
async resolveThread(job) {
|
|
42
43
|
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
43
|
-
if (job.route.threadId && await
|
|
44
|
+
if (job.route.threadId && await (0, thread_resolution_js_1.threadExists)(workspaceRouter, job.route.threadId)) {
|
|
44
45
|
return job.route.threadId;
|
|
45
46
|
}
|
|
46
47
|
const title = `[Scheduled] ${job.description || job.id}`;
|
|
@@ -52,14 +53,5 @@ class LocalScheduleAdapter {
|
|
|
52
53
|
const created = await workspaceRouter.createThread(job.workspaceId, title);
|
|
53
54
|
return created.id;
|
|
54
55
|
}
|
|
55
|
-
async threadExists(threadId) {
|
|
56
|
-
try {
|
|
57
|
-
await this.options.getWorkspaceRouter().getThread(threadId);
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
56
|
}
|
|
65
57
|
exports.LocalScheduleAdapter = LocalScheduleAdapter;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.waitForRunCompletion = waitForRunCompletion;
|
|
4
|
+
const TERMINAL_RUN_STATES = new Set(['completed', 'failed', 'interrupted']);
|
|
5
|
+
const RUN_POLL_INTERVAL_MS = 300;
|
|
6
|
+
async function waitForRunCompletion(store, runId, timeoutMs, label) {
|
|
7
|
+
const startedAt = Date.now();
|
|
8
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
9
|
+
const run = store.getRun(runId);
|
|
10
|
+
if (run && TERMINAL_RUN_STATES.has(run.status)) {
|
|
11
|
+
if (run.status !== 'completed') {
|
|
12
|
+
throw new Error(`${label} run finished with status ${run.status}`);
|
|
13
|
+
}
|
|
14
|
+
return run;
|
|
15
|
+
}
|
|
16
|
+
await new Promise((resolve) => setTimeout(resolve, RUN_POLL_INTERVAL_MS));
|
|
17
|
+
}
|
|
18
|
+
throw new Error(`Timed out waiting for ${label.toLowerCase()} run ${runId}`);
|
|
19
|
+
}
|
package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ScheduledConversationExecutor = void 0;
|
|
4
4
|
const scheduled_job_route_js_1 = require("./scheduled-job-route.js");
|
|
5
|
-
const
|
|
5
|
+
const run_polling_js_1 = require("./run-polling.js");
|
|
6
6
|
const SCHEDULED_RUN_PERMISSION_MODE = 'bypassPermissions';
|
|
7
7
|
class ScheduledConversationExecutor {
|
|
8
8
|
options;
|
|
@@ -16,9 +16,9 @@ class ScheduledConversationExecutor {
|
|
|
16
16
|
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
17
17
|
const sendResult = await workspaceRouter.sendThreadMessage(target.threadId, prompt, {
|
|
18
18
|
permissionMode: SCHEDULED_RUN_PERMISSION_MODE,
|
|
19
|
-
runtimeEnv:
|
|
19
|
+
runtimeEnv: (0, scheduled_job_route_js_1.buildPlatformRuntimeEnv)(target.platform, target.route),
|
|
20
20
|
});
|
|
21
|
-
await this.
|
|
21
|
+
await (0, run_polling_js_1.waitForRunCompletion)(this.options.store, sendResult.runId, timeoutMs, 'Scheduled');
|
|
22
22
|
const thread = await workspaceRouter.getThread(target.threadId);
|
|
23
23
|
const replyText = [...thread.messages]
|
|
24
24
|
.reverse()
|
|
@@ -34,39 +34,5 @@ class ScheduledConversationExecutor {
|
|
|
34
34
|
await policy.afterExecute?.(target, job);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
buildScheduledRuntimeEnv(target) {
|
|
38
|
-
const route = target.route;
|
|
39
|
-
const basePlatform = (0, scheduled_job_route_js_1.getChannelPlatformBase)(target.platform);
|
|
40
|
-
const env = {};
|
|
41
|
-
if (basePlatform && basePlatform !== 'local') {
|
|
42
|
-
env.LOCAL_AI_PLATFORM = basePlatform;
|
|
43
|
-
env.LOCAL_AI_ROUTE_TYPE = (0, scheduled_job_route_js_1.routeTypeForPlatform)(target.platform);
|
|
44
|
-
}
|
|
45
|
-
const instanceId = route.instanceId || (0, scheduled_job_route_js_1.getChannelPlatformInstanceId)(target.platform);
|
|
46
|
-
if (instanceId) {
|
|
47
|
-
env.LOCAL_AI_PLATFORM_INSTANCE_ID = instanceId;
|
|
48
|
-
}
|
|
49
|
-
if (route.channelId) {
|
|
50
|
-
env.LOCAL_AI_CHAT_ID = route.channelId;
|
|
51
|
-
}
|
|
52
|
-
if (route.participantId) {
|
|
53
|
-
env.LOCAL_AI_PLATFORM_USER_ID = route.participantId;
|
|
54
|
-
}
|
|
55
|
-
return env;
|
|
56
|
-
}
|
|
57
|
-
async waitForRun(runId, timeoutMs) {
|
|
58
|
-
const startedAt = Date.now();
|
|
59
|
-
while (Date.now() - startedAt < timeoutMs) {
|
|
60
|
-
const run = this.options.store.getRun(runId);
|
|
61
|
-
if (run && TERMINAL_RUN_STATES.has(run.status)) {
|
|
62
|
-
if (run.status !== 'completed') {
|
|
63
|
-
throw new Error(`Scheduled run finished with status ${run.status}`);
|
|
64
|
-
}
|
|
65
|
-
return run;
|
|
66
|
-
}
|
|
67
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
68
|
-
}
|
|
69
|
-
throw new Error(`Timed out waiting for scheduled run ${runId}`);
|
|
70
|
-
}
|
|
71
37
|
}
|
|
72
38
|
exports.ScheduledConversationExecutor = ScheduledConversationExecutor;
|
|
@@ -6,6 +6,7 @@ exports.getChannelPlatformInstanceId = getChannelPlatformInstanceId;
|
|
|
6
6
|
exports.platformMatches = platformMatches;
|
|
7
7
|
exports.routeWithPlatformInstance = routeWithPlatformInstance;
|
|
8
8
|
exports.routeTypeForPlatform = routeTypeForPlatform;
|
|
9
|
+
exports.buildPlatformRuntimeEnv = buildPlatformRuntimeEnv;
|
|
9
10
|
exports.routeFromPlatformThreadBinding = routeFromPlatformThreadBinding;
|
|
10
11
|
exports.scheduledJobMatchesPlatformBinding = scheduledJobMatchesPlatformBinding;
|
|
11
12
|
exports.scheduledJobMatchesCliContext = scheduledJobMatchesCliContext;
|
|
@@ -32,6 +33,25 @@ function routeTypeForPlatform(platform) {
|
|
|
32
33
|
const base = getChannelPlatformBase(platform);
|
|
33
34
|
return base === 'lark' || base === 'weixin' ? 'channel.chat' : base;
|
|
34
35
|
}
|
|
36
|
+
function buildPlatformRuntimeEnv(platform, route) {
|
|
37
|
+
const basePlatform = getChannelPlatformBase(platform);
|
|
38
|
+
const env = {};
|
|
39
|
+
if (basePlatform && basePlatform !== 'local') {
|
|
40
|
+
env.LOCAL_AI_PLATFORM = basePlatform;
|
|
41
|
+
env.LOCAL_AI_ROUTE_TYPE = routeTypeForPlatform(platform);
|
|
42
|
+
}
|
|
43
|
+
const instanceId = route.instanceId || getChannelPlatformInstanceId(platform);
|
|
44
|
+
if (instanceId) {
|
|
45
|
+
env.LOCAL_AI_PLATFORM_INSTANCE_ID = instanceId;
|
|
46
|
+
}
|
|
47
|
+
if (route.channelId) {
|
|
48
|
+
env.LOCAL_AI_CHAT_ID = route.channelId;
|
|
49
|
+
}
|
|
50
|
+
if (route.participantId) {
|
|
51
|
+
env.LOCAL_AI_PLATFORM_USER_ID = route.participantId;
|
|
52
|
+
}
|
|
53
|
+
return env;
|
|
54
|
+
}
|
|
35
55
|
function routeFromPlatformThreadBinding(binding) {
|
|
36
56
|
return {
|
|
37
57
|
type: routeTypeForPlatform(binding.platform),
|
|
@@ -16,10 +16,18 @@ class SchedulerService extends node_events_1.EventEmitter {
|
|
|
16
16
|
this.options = options;
|
|
17
17
|
this.runLifecycle = new scheduler_run_lifecycle_js_1.SchedulerRunLifecycle({
|
|
18
18
|
store: options.store,
|
|
19
|
-
emitRun: (run) => this.
|
|
20
|
-
emitJob: (job) => this.
|
|
19
|
+
emitRun: (run) => this.emitRun(run),
|
|
20
|
+
emitJob: (job) => this.emitJob(job),
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
emitJob(job) {
|
|
24
|
+
this.emit('job', job);
|
|
25
|
+
this.options.eventBus.emit({ type: 'scheduler.job.updated', payload: job });
|
|
26
|
+
}
|
|
27
|
+
emitRun(run) {
|
|
28
|
+
this.emit('run', run);
|
|
29
|
+
this.options.eventBus.emit({ type: 'scheduler.run.updated', payload: run });
|
|
30
|
+
}
|
|
23
31
|
async start() {
|
|
24
32
|
await this.tick();
|
|
25
33
|
this.timer = setInterval(() => {
|
|
@@ -41,14 +49,12 @@ class SchedulerService extends node_events_1.EventEmitter {
|
|
|
41
49
|
}
|
|
42
50
|
createJob(input) {
|
|
43
51
|
const job = this.options.store.createScheduledJob(input);
|
|
44
|
-
this.
|
|
45
|
-
this.options.eventBus.emit({ type: 'scheduler.job.updated', payload: job });
|
|
52
|
+
this.emitJob(job);
|
|
46
53
|
return job;
|
|
47
54
|
}
|
|
48
55
|
updateJob(jobId, input) {
|
|
49
56
|
const job = this.options.store.updateScheduledJob(this.resolveRequiredJobId(jobId), input);
|
|
50
|
-
this.
|
|
51
|
-
this.options.eventBus.emit({ type: 'scheduler.job.updated', payload: job });
|
|
57
|
+
this.emitJob(job);
|
|
52
58
|
return job;
|
|
53
59
|
}
|
|
54
60
|
deleteJob(jobId) {
|
|
@@ -115,39 +121,21 @@ class SchedulerService extends node_events_1.EventEmitter {
|
|
|
115
121
|
}
|
|
116
122
|
async executeJob(job, triggeredAt, manual) {
|
|
117
123
|
if (this.runningJobs.has(job.id)) {
|
|
118
|
-
|
|
119
|
-
this.options.eventBus.emit({ type: 'scheduler.run.updated', payload: skipped });
|
|
120
|
-
return skipped;
|
|
124
|
+
return this.runLifecycle.markSkipped(job, triggeredAt, 'Skipped because the previous run is still active.');
|
|
121
125
|
}
|
|
122
126
|
this.runningJobs.add(job.id);
|
|
123
127
|
const run = this.runLifecycle.markQueued(job, triggeredAt);
|
|
124
|
-
this.options.eventBus.emit({ type: 'scheduler.run.updated', payload: run });
|
|
125
128
|
try {
|
|
126
129
|
const executor = this.options.executors.find((candidate) => candidate.supports(job));
|
|
127
130
|
if (!executor) {
|
|
128
131
|
throw new Error(`No scheduler executor is available for delivery target "${job.platform}"`);
|
|
129
132
|
}
|
|
130
133
|
this.runLifecycle.markRunning(run.id);
|
|
131
|
-
const running = this.options.store.getScheduledJobRun(run.id);
|
|
132
|
-
if (running) {
|
|
133
|
-
this.options.eventBus.emit({ type: 'scheduler.run.updated', payload: running });
|
|
134
|
-
}
|
|
135
134
|
const result = await executor.execute({ job, triggeredAt });
|
|
136
|
-
|
|
137
|
-
this.options.eventBus.emit({ type: 'scheduler.run.updated', payload: succeeded });
|
|
138
|
-
const nextJob = this.options.store.getScheduledJob(job.id);
|
|
139
|
-
if (nextJob) {
|
|
140
|
-
this.options.eventBus.emit({ type: 'scheduler.job.updated', payload: nextJob });
|
|
141
|
-
}
|
|
142
|
-
return succeeded;
|
|
135
|
+
return this.runLifecycle.markSucceeded(job, run.id, result, !manual && job.triggerType === 'once');
|
|
143
136
|
}
|
|
144
137
|
catch (error) {
|
|
145
138
|
const failed = this.runLifecycle.markFailed(job.id, run.id, error instanceof Error ? error.message : String(error));
|
|
146
|
-
this.options.eventBus.emit({ type: 'scheduler.run.updated', payload: failed });
|
|
147
|
-
const nextJob = this.options.store.getScheduledJob(job.id);
|
|
148
|
-
if (nextJob) {
|
|
149
|
-
this.options.eventBus.emit({ type: 'scheduler.job.updated', payload: nextJob });
|
|
150
|
-
}
|
|
151
139
|
this.options.log?.(`scheduler job failed ${job.id}: ${failed.error || 'unknown error'}`);
|
|
152
140
|
this.maybeAutoDisableAfterFailure(job.id);
|
|
153
141
|
return failed;
|
|
@@ -173,8 +161,7 @@ class SchedulerService extends node_events_1.EventEmitter {
|
|
|
173
161
|
this.options.store.updateScheduledJobStatus(jobId, { enabled: false });
|
|
174
162
|
const disabled = this.options.store.getScheduledJob(jobId);
|
|
175
163
|
if (disabled) {
|
|
176
|
-
this.
|
|
177
|
-
this.options.eventBus.emit({ type: 'scheduler.job.updated', payload: disabled });
|
|
164
|
+
this.emitJob(disabled);
|
|
178
165
|
}
|
|
179
166
|
this.options.log?.(`scheduler auto-disabled job ${jobId} after ${consecutiveFailures} consecutive failures`);
|
|
180
167
|
}
|