@jsonstudio/llms 0.6.1739 → 0.6.1890
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/conversion/compat/actions/deepseek-web-request.d.ts +3 -0
- package/dist/conversion/compat/actions/deepseek-web-request.js +350 -0
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +3 -0
- package/dist/conversion/compat/actions/deepseek-web-response.js +886 -0
- package/dist/conversion/compat/actions/gemini-cli-request.js +3 -1
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +18 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +166 -2
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +169 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +6 -0
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +12 -0
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +4 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +365 -144
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +9 -0
- package/dist/conversion/hub/policy/policy-engine.d.ts +2 -0
- package/dist/conversion/hub/policy/policy-engine.js +8 -0
- package/dist/conversion/hub/process/chat-process.js +466 -16
- package/dist/conversion/hub/response/provider-response.js +0 -35
- package/dist/conversion/responses/responses-openai-bridge.d.ts +2 -0
- package/dist/conversion/responses/responses-openai-bridge.js +166 -8
- package/dist/conversion/shared/anthropic-message-utils.js +10 -1
- package/dist/conversion/shared/protocol-field-allowlists.d.ts +2 -2
- package/dist/conversion/shared/protocol-field-allowlists.js +4 -0
- package/dist/conversion/shared/tool-governor.js +102 -0
- package/dist/guidance/index.js +17 -0
- package/dist/router/virtual-router/bootstrap.js +46 -1
- package/dist/router/virtual-router/classifier.js +59 -4
- package/dist/router/virtual-router/engine/health/index.js +6 -6
- package/dist/router/virtual-router/engine/routing-state/store.js +16 -3
- package/dist/router/virtual-router/engine-logging.js +62 -24
- package/dist/router/virtual-router/engine-selection/route-utils.js +20 -20
- package/dist/router/virtual-router/engine-selection/tier-selection.js +2 -2
- package/dist/router/virtual-router/engine.d.ts +3 -1
- package/dist/router/virtual-router/engine.js +359 -39
- package/dist/router/virtual-router/features.js +2 -1
- package/dist/router/virtual-router/pre-command-file-resolver.d.ts +2 -0
- package/dist/router/virtual-router/pre-command-file-resolver.js +90 -0
- package/dist/router/virtual-router/provider-registry.js +3 -1
- package/dist/router/virtual-router/routing-instructions.d.ts +15 -1
- package/dist/router/virtual-router/routing-instructions.js +110 -151
- package/dist/router/virtual-router/routing-pre-command-actions.d.ts +3 -0
- package/dist/router/virtual-router/routing-pre-command-actions.js +26 -0
- package/dist/router/virtual-router/routing-pre-command-parser.d.ts +2 -0
- package/dist/router/virtual-router/routing-pre-command-parser.js +85 -0
- package/dist/router/virtual-router/routing-pre-command-state-codec.d.ts +3 -0
- package/dist/router/virtual-router/routing-pre-command-state-codec.js +24 -0
- package/dist/router/virtual-router/routing-stop-message-actions.d.ts +2 -0
- package/dist/router/virtual-router/routing-stop-message-actions.js +96 -0
- package/dist/router/virtual-router/routing-stop-message-parser.d.ts +3 -0
- package/dist/router/virtual-router/routing-stop-message-parser.js +142 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +4 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.js +85 -0
- package/dist/router/virtual-router/sticky-session-store.js +206 -57
- package/dist/router/virtual-router/stop-message-stage-template-files.d.ts +12 -0
- package/dist/router/virtual-router/stop-message-stage-template-files.js +67 -0
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
- package/dist/router/virtual-router/stop-message-state-sync.js +5 -0
- package/dist/router/virtual-router/token-file-scanner.d.ts +9 -0
- package/dist/router/virtual-router/token-file-scanner.js +64 -3
- package/dist/router/virtual-router/tool-signals.d.ts +5 -0
- package/dist/router/virtual-router/tool-signals.js +42 -3
- package/dist/router/virtual-router/types.d.ts +19 -1
- package/dist/router/virtual-router/types.js +1 -0
- package/dist/servertool/clock/config.d.ts +1 -1
- package/dist/servertool/clock/config.js +27 -4
- package/dist/servertool/clock/state.js +41 -2
- package/dist/servertool/clock/task-store.d.ts +2 -2
- package/dist/servertool/clock/task-store.js +1 -1
- package/dist/servertool/clock/tasks.d.ts +3 -1
- package/dist/servertool/clock/tasks.js +209 -18
- package/dist/servertool/clock/types.d.ts +17 -0
- package/dist/servertool/continue-execution/log.d.ts +3 -0
- package/dist/servertool/continue-execution/log.js +13 -0
- package/dist/servertool/engine.js +414 -68
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +6 -6
- package/dist/servertool/handlers/clock-auto.js +54 -71
- package/dist/servertool/handlers/clock.js +121 -6
- package/dist/servertool/handlers/continue-execution.d.ts +1 -0
- package/dist/servertool/handlers/continue-execution.js +91 -0
- package/dist/servertool/handlers/followup-request-builder.js +13 -0
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -1
- package/dist/servertool/handlers/iflow-model-error-retry.js +1 -1
- package/dist/servertool/handlers/recursive-detection-guard.js +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +386 -257
- package/dist/servertool/handlers/stop-message-stage-policy.d.ts +43 -0
- package/dist/servertool/handlers/stop-message-stage-policy.js +684 -0
- package/dist/servertool/handlers/vision.js +1 -1
- package/dist/servertool/log/progress-file.d.ts +14 -0
- package/dist/servertool/log/progress-file.js +88 -0
- package/dist/servertool/pre-command-hooks.d.ts +17 -0
- package/dist/servertool/pre-command-hooks.js +491 -0
- package/dist/servertool/registry.d.ts +23 -6
- package/dist/servertool/registry.js +66 -1
- package/dist/servertool/server-side-tools.d.ts +1 -0
- package/dist/servertool/server-side-tools.js +216 -14
- package/dist/servertool/stop-gateway-context.d.ts +14 -0
- package/dist/servertool/stop-gateway-context.js +167 -0
- package/dist/servertool/stop-message-compare-context.d.ts +24 -0
- package/dist/servertool/stop-message-compare-context.js +133 -0
- package/dist/servertool/types.d.ts +12 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +36 -1
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +3 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +3 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +118 -1
- package/dist/tools/apply-patch/args-normalizer/default-actions.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import crypto from 'node:crypto';
|
|
4
|
-
import { ensureDir, readSessionDirEnv, resolveClockStateFile } from './paths.js';
|
|
4
|
+
import { ensureDir, readSessionDirEnv, resolveClockDir, resolveClockStateFile } from './paths.js';
|
|
5
5
|
import { cleanExpiredTasks, nowMs } from './state.js';
|
|
6
6
|
import { writeJsonFileAtomic } from './io.js';
|
|
7
7
|
import { clearClockSession, loadClockSessionState } from './session-store.js';
|
|
@@ -26,6 +26,64 @@ function buildTaskId() {
|
|
|
26
26
|
return `task_${Math.random().toString(16).slice(2)}_${Date.now()}`;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
function normalizeRecurrence(raw) {
|
|
30
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const record = raw;
|
|
34
|
+
const rawKind = typeof record.kind === 'string' ? record.kind.trim().toLowerCase() : '';
|
|
35
|
+
const kind = rawKind === 'daily' || rawKind === 'weekly' || rawKind === 'interval'
|
|
36
|
+
? rawKind
|
|
37
|
+
: undefined;
|
|
38
|
+
const maxRunsRaw = Number(record.maxRuns);
|
|
39
|
+
const maxRuns = Number.isFinite(maxRunsRaw) ? Math.floor(maxRunsRaw) : NaN;
|
|
40
|
+
if (!kind || !Number.isFinite(maxRuns) || maxRuns <= 0) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
if (kind === 'interval') {
|
|
44
|
+
const everyRaw = Number(record.everyMinutes);
|
|
45
|
+
const everyMinutes = Number.isFinite(everyRaw) ? Math.floor(everyRaw) : NaN;
|
|
46
|
+
if (!Number.isFinite(everyMinutes) || everyMinutes <= 0) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return { kind, maxRuns, everyMinutes };
|
|
50
|
+
}
|
|
51
|
+
return { kind, maxRuns };
|
|
52
|
+
}
|
|
53
|
+
function resolveRecurringStepMs(recurrence) {
|
|
54
|
+
if (recurrence.kind === 'daily') {
|
|
55
|
+
return 24 * 60 * 60_000;
|
|
56
|
+
}
|
|
57
|
+
if (recurrence.kind === 'weekly') {
|
|
58
|
+
return 7 * 24 * 60 * 60_000;
|
|
59
|
+
}
|
|
60
|
+
if (recurrence.kind === 'interval') {
|
|
61
|
+
const minutes = Number(recurrence.everyMinutes);
|
|
62
|
+
if (!Number.isFinite(minutes) || minutes <= 0) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return Math.floor(minutes) * 60_000;
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
function computeNextRecurringDueAtMs(currentDueAtMs, recurrence, atMs) {
|
|
70
|
+
if (!Number.isFinite(currentDueAtMs)) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const stepMs = resolveRecurringStepMs(recurrence);
|
|
74
|
+
if (!stepMs || stepMs <= 0) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
let next = Math.floor(currentDueAtMs) + stepMs;
|
|
78
|
+
const ceiling = Math.max(atMs, Math.floor(currentDueAtMs)) + stepMs * 100_000;
|
|
79
|
+
while (next <= atMs && next < ceiling) {
|
|
80
|
+
next += stepMs;
|
|
81
|
+
}
|
|
82
|
+
if (!Number.isFinite(next) || next <= atMs) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return Math.floor(next);
|
|
86
|
+
}
|
|
29
87
|
export function parseDueAtMs(value) {
|
|
30
88
|
if (typeof value !== 'string')
|
|
31
89
|
return null;
|
|
@@ -37,6 +95,22 @@ export function parseDueAtMs(value) {
|
|
|
37
95
|
return null;
|
|
38
96
|
return ms;
|
|
39
97
|
}
|
|
98
|
+
export async function listClockSessionIds() {
|
|
99
|
+
const sessionDir = readSessionDirEnv();
|
|
100
|
+
if (!sessionDir) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
const clockDir = resolveClockDir(sessionDir);
|
|
104
|
+
const entries = await fs.readdir(clockDir, { withFileTypes: true }).catch(() => []);
|
|
105
|
+
const sessionIds = entries
|
|
106
|
+
.filter((entry) => entry && typeof entry.name === 'string' && entry.name.endsWith('.json'))
|
|
107
|
+
.filter((entry) => entry.name !== 'ntp-state.json')
|
|
108
|
+
.filter((entry) => (typeof entry.isFile === 'function' ? entry.isFile() : true))
|
|
109
|
+
.map((entry) => entry.name.slice(0, -'.json'.length).trim())
|
|
110
|
+
.filter(Boolean)
|
|
111
|
+
.sort((a, b) => a.localeCompare(b));
|
|
112
|
+
return sessionIds;
|
|
113
|
+
}
|
|
40
114
|
export async function listClockTasks(sessionId, config) {
|
|
41
115
|
const state = await loadClockSessionState(sessionId, config);
|
|
42
116
|
return state.tasks.slice();
|
|
@@ -61,6 +135,10 @@ export async function scheduleClockTasks(sessionId, items, config) {
|
|
|
61
135
|
if (!text || !Number.isFinite(dueAtMs)) {
|
|
62
136
|
continue;
|
|
63
137
|
}
|
|
138
|
+
const recurrence = normalizeRecurrence(item.recurrence);
|
|
139
|
+
if (item.recurrence && !recurrence) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
64
142
|
const taskId = buildTaskId();
|
|
65
143
|
scheduled.push({
|
|
66
144
|
taskId,
|
|
@@ -72,6 +150,7 @@ export async function scheduleClockTasks(sessionId, items, config) {
|
|
|
72
150
|
...(item.tool ? { tool: item.tool } : {}),
|
|
73
151
|
...(item.arguments ? { arguments: item.arguments } : {}),
|
|
74
152
|
...(item.notBeforeRequestId ? { notBeforeRequestId: item.notBeforeRequestId } : {}),
|
|
153
|
+
...(recurrence ? { recurrence } : {}),
|
|
75
154
|
deliveryCount: 0
|
|
76
155
|
});
|
|
77
156
|
}
|
|
@@ -90,6 +169,78 @@ export async function scheduleClockTasks(sessionId, items, config) {
|
|
|
90
169
|
}
|
|
91
170
|
return scheduled;
|
|
92
171
|
}
|
|
172
|
+
export async function updateClockTask(sessionId, taskId, patch, config) {
|
|
173
|
+
const sessionDir = readSessionDirEnv();
|
|
174
|
+
if (!sessionDir) {
|
|
175
|
+
throw new Error('clock: missing ROUTECODEX_SESSION_DIR');
|
|
176
|
+
}
|
|
177
|
+
const filePath = resolveClockStateFile(sessionDir, sessionId);
|
|
178
|
+
if (!filePath) {
|
|
179
|
+
throw new Error('clock: invalid sessionId');
|
|
180
|
+
}
|
|
181
|
+
await ensureDir(path.dirname(filePath));
|
|
182
|
+
const at = nowMs();
|
|
183
|
+
const state = await loadClockSessionState(sessionId, config);
|
|
184
|
+
const cleaned = cleanExpiredTasks(state.tasks, config, at);
|
|
185
|
+
const index = cleaned.findIndex((item) => item.taskId === taskId);
|
|
186
|
+
if (index < 0) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const current = cleaned[index];
|
|
190
|
+
const nextTask = {
|
|
191
|
+
...current,
|
|
192
|
+
updatedAtMs: at
|
|
193
|
+
};
|
|
194
|
+
if (typeof patch.dueAtMs === 'number' && Number.isFinite(patch.dueAtMs)) {
|
|
195
|
+
nextTask.dueAtMs = Math.floor(patch.dueAtMs);
|
|
196
|
+
delete nextTask.deliveredAtMs;
|
|
197
|
+
}
|
|
198
|
+
if (typeof patch.task === 'string' && patch.task.trim()) {
|
|
199
|
+
nextTask.task = patch.task.trim();
|
|
200
|
+
}
|
|
201
|
+
if (patch.tool === null) {
|
|
202
|
+
delete nextTask.tool;
|
|
203
|
+
}
|
|
204
|
+
else if (typeof patch.tool === 'string' && patch.tool.trim()) {
|
|
205
|
+
nextTask.tool = patch.tool.trim();
|
|
206
|
+
}
|
|
207
|
+
if (patch.arguments === null) {
|
|
208
|
+
delete nextTask.arguments;
|
|
209
|
+
}
|
|
210
|
+
else if (patch.arguments && typeof patch.arguments === 'object' && !Array.isArray(patch.arguments)) {
|
|
211
|
+
nextTask.arguments = patch.arguments;
|
|
212
|
+
}
|
|
213
|
+
if (patch.notBeforeRequestId === null) {
|
|
214
|
+
delete nextTask.notBeforeRequestId;
|
|
215
|
+
}
|
|
216
|
+
else if (typeof patch.notBeforeRequestId === 'string' && patch.notBeforeRequestId.trim()) {
|
|
217
|
+
nextTask.notBeforeRequestId = patch.notBeforeRequestId.trim();
|
|
218
|
+
}
|
|
219
|
+
if (patch.recurrence === null) {
|
|
220
|
+
delete nextTask.recurrence;
|
|
221
|
+
}
|
|
222
|
+
else if (patch.recurrence) {
|
|
223
|
+
const recurrence = normalizeRecurrence(patch.recurrence);
|
|
224
|
+
if (!recurrence) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
nextTask.recurrence = recurrence;
|
|
228
|
+
delete nextTask.deliveredAtMs;
|
|
229
|
+
}
|
|
230
|
+
if (patch.resetDelivery) {
|
|
231
|
+
nextTask.deliveryCount = 0;
|
|
232
|
+
delete nextTask.deliveredAtMs;
|
|
233
|
+
}
|
|
234
|
+
cleaned[index] = nextTask;
|
|
235
|
+
const next = { version: 1, sessionId, tasks: cleaned, updatedAtMs: at };
|
|
236
|
+
if (!next.tasks.length) {
|
|
237
|
+
await fs.rm(filePath, { force: true });
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
await writeJsonFileAtomic(filePath, next);
|
|
241
|
+
}
|
|
242
|
+
return nextTask;
|
|
243
|
+
}
|
|
93
244
|
export async function cancelClockTask(sessionId, taskId, config) {
|
|
94
245
|
const sessionDir = readSessionDirEnv();
|
|
95
246
|
if (!sessionDir) {
|
|
@@ -119,12 +270,23 @@ export async function clearClockTasks(sessionId, config) {
|
|
|
119
270
|
await clearClockSession(sessionId);
|
|
120
271
|
return items.length;
|
|
121
272
|
}
|
|
273
|
+
function isRecurringTaskPending(task) {
|
|
274
|
+
const recurrence = normalizeRecurrence(task.recurrence);
|
|
275
|
+
if (!recurrence) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
const deliveryCount = typeof task.deliveryCount === 'number' && Number.isFinite(task.deliveryCount)
|
|
279
|
+
? Math.max(0, Math.floor(task.deliveryCount))
|
|
280
|
+
: 0;
|
|
281
|
+
return deliveryCount < recurrence.maxRuns;
|
|
282
|
+
}
|
|
122
283
|
export function selectDueUndeliveredTasks(tasks, config, atMs) {
|
|
123
284
|
const due = [];
|
|
124
285
|
for (const task of tasks) {
|
|
125
286
|
if (!task || typeof task !== 'object')
|
|
126
287
|
continue;
|
|
127
|
-
|
|
288
|
+
const recurringPending = isRecurringTaskPending(task);
|
|
289
|
+
if (!recurringPending && task.deliveredAtMs !== undefined)
|
|
128
290
|
continue;
|
|
129
291
|
if (typeof task.notBeforeRequestId === 'string' && task.notBeforeRequestId.trim().length) {
|
|
130
292
|
// notBeforeRequestId is evaluated by reserveDueTasksForRequest, which passes requestId.
|
|
@@ -134,7 +296,7 @@ export function selectDueUndeliveredTasks(tasks, config, atMs) {
|
|
|
134
296
|
continue;
|
|
135
297
|
if (atMs < task.dueAtMs - config.dueWindowMs)
|
|
136
298
|
continue;
|
|
137
|
-
if (atMs > task.dueAtMs + config.retentionMs)
|
|
299
|
+
if (!recurringPending && atMs > task.dueAtMs + config.retentionMs)
|
|
138
300
|
continue;
|
|
139
301
|
due.push(task);
|
|
140
302
|
}
|
|
@@ -146,7 +308,8 @@ export function findNextUndeliveredDueAtMs(tasks, atMs) {
|
|
|
146
308
|
for (const task of tasks) {
|
|
147
309
|
if (!task || typeof task !== 'object')
|
|
148
310
|
continue;
|
|
149
|
-
|
|
311
|
+
const recurringPending = isRecurringTaskPending(task);
|
|
312
|
+
if (!recurringPending && task.deliveredAtMs !== undefined)
|
|
150
313
|
continue;
|
|
151
314
|
if (!Number.isFinite(task.dueAtMs))
|
|
152
315
|
continue;
|
|
@@ -176,8 +339,6 @@ export async function reserveDueTasksForRequest(args) {
|
|
|
176
339
|
if (!guarded) {
|
|
177
340
|
return true;
|
|
178
341
|
}
|
|
179
|
-
// Avoid same-request triggers, including internal followups that suffix the requestId
|
|
180
|
-
// (e.g. ":clock_followup"), to prevent request-local dead loops.
|
|
181
342
|
return !isSameRequestChain(guarded, requestId);
|
|
182
343
|
})
|
|
183
344
|
: dueAll;
|
|
@@ -196,7 +357,11 @@ export async function reserveDueTasksForRequest(args) {
|
|
|
196
357
|
const dueAtIso = new Date(t.dueAtMs).toISOString();
|
|
197
358
|
const toolLabel = t.tool ? ` tool=${t.tool}` : '';
|
|
198
359
|
const argsLabel = t.arguments ? ` args=${safeJson(t.arguments)}` : '';
|
|
199
|
-
|
|
360
|
+
const recurrence = normalizeRecurrence(t.recurrence);
|
|
361
|
+
const recurrenceLabel = recurrence
|
|
362
|
+
? ` recurrence=${recurrence.kind}${recurrence.kind === 'interval' ? `(${recurrence.everyMinutes}m)` : ''} maxRuns=${recurrence.maxRuns} run=${Math.max(0, t.deliveryCount)}/${recurrence.maxRuns}`
|
|
363
|
+
: '';
|
|
364
|
+
return `[scheduled task:${safeQuoted(t.task)}${toolLabel}${argsLabel}${recurrenceLabel} dueAt=${dueAtIso}]`;
|
|
200
365
|
})
|
|
201
366
|
.join('\n');
|
|
202
367
|
return { reservation, injectText };
|
|
@@ -215,21 +380,47 @@ export async function commitClockReservation(reservation, config) {
|
|
|
215
380
|
const cleaned = cleanExpiredTasks(state.tasks, config, at);
|
|
216
381
|
const reservedSet = new Set(reservation.taskIds);
|
|
217
382
|
let touched = false;
|
|
218
|
-
const nextTasks =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return t;
|
|
383
|
+
const nextTasks = [];
|
|
384
|
+
for (const task of cleaned) {
|
|
385
|
+
if (!reservedSet.has(task.taskId)) {
|
|
386
|
+
nextTasks.push(task);
|
|
387
|
+
continue;
|
|
224
388
|
}
|
|
225
389
|
touched = true;
|
|
226
|
-
|
|
227
|
-
|
|
390
|
+
const currentCount = typeof task.deliveryCount === 'number' && Number.isFinite(task.deliveryCount)
|
|
391
|
+
? Math.max(0, Math.floor(task.deliveryCount))
|
|
392
|
+
: 0;
|
|
393
|
+
const nextCount = currentCount + 1;
|
|
394
|
+
const recurrence = normalizeRecurrence(task.recurrence);
|
|
395
|
+
if (recurrence) {
|
|
396
|
+
if (nextCount >= recurrence.maxRuns) {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
const nextDueAtMs = computeNextRecurringDueAtMs(task.dueAtMs, recurrence, at);
|
|
400
|
+
if (!Number.isFinite(nextDueAtMs)) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
nextTasks.push({
|
|
404
|
+
...task,
|
|
405
|
+
dueAtMs: nextDueAtMs,
|
|
406
|
+
deliveryCount: nextCount,
|
|
407
|
+
updatedAtMs: at,
|
|
408
|
+
recurrence,
|
|
409
|
+
deliveredAtMs: undefined
|
|
410
|
+
});
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (task.deliveredAtMs !== undefined) {
|
|
414
|
+
nextTasks.push(task);
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
nextTasks.push({
|
|
418
|
+
...task,
|
|
228
419
|
deliveredAtMs: at,
|
|
229
|
-
deliveryCount:
|
|
420
|
+
deliveryCount: nextCount,
|
|
230
421
|
updatedAtMs: at
|
|
231
|
-
};
|
|
232
|
-
}
|
|
422
|
+
});
|
|
423
|
+
}
|
|
233
424
|
if (!touched) {
|
|
234
425
|
return;
|
|
235
426
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export type ClockRecurrenceKind = 'daily' | 'weekly' | 'interval';
|
|
2
|
+
export type ClockTaskRecurrence = {
|
|
3
|
+
kind: ClockRecurrenceKind;
|
|
4
|
+
maxRuns: number;
|
|
5
|
+
everyMinutes?: number;
|
|
6
|
+
};
|
|
1
7
|
export type ClockTask = {
|
|
2
8
|
taskId: string;
|
|
3
9
|
sessionId: string;
|
|
@@ -10,6 +16,7 @@ export type ClockTask = {
|
|
|
10
16
|
deliveredAtMs?: number;
|
|
11
17
|
deliveryCount: number;
|
|
12
18
|
notBeforeRequestId?: string;
|
|
19
|
+
recurrence?: ClockTaskRecurrence;
|
|
13
20
|
};
|
|
14
21
|
export type ClockSessionState = {
|
|
15
22
|
version: 1;
|
|
@@ -45,6 +52,16 @@ export type ClockScheduleItem = {
|
|
|
45
52
|
tool?: string;
|
|
46
53
|
arguments?: Record<string, unknown>;
|
|
47
54
|
notBeforeRequestId?: string;
|
|
55
|
+
recurrence?: ClockTaskRecurrence;
|
|
56
|
+
};
|
|
57
|
+
export type ClockTaskUpdatePatch = {
|
|
58
|
+
dueAtMs?: number;
|
|
59
|
+
task?: string;
|
|
60
|
+
tool?: string | null;
|
|
61
|
+
arguments?: Record<string, unknown> | null;
|
|
62
|
+
notBeforeRequestId?: string | null;
|
|
63
|
+
recurrence?: ClockTaskRecurrence | null;
|
|
64
|
+
resetDelivery?: boolean;
|
|
48
65
|
};
|
|
49
66
|
export type ClockNtpState = {
|
|
50
67
|
version: 1;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const CONTINUE_EXECUTION_LOG_GOLD = '\x1b[38;5;220m';
|
|
2
|
+
export const CONTINUE_EXECUTION_LOG_RESET = '\x1b[0m';
|
|
3
|
+
export function logContinueExecution(message, extra) {
|
|
4
|
+
try {
|
|
5
|
+
// eslint-disable-next-line no-console
|
|
6
|
+
console.log(`${CONTINUE_EXECUTION_LOG_GOLD}[servertool][continue_execution] ${message}` +
|
|
7
|
+
(extra ? ` ${JSON.stringify(extra)}` : '') +
|
|
8
|
+
CONTINUE_EXECUTION_LOG_RESET);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
// best-effort logging
|
|
12
|
+
}
|
|
13
|
+
}
|