@polpo-ai/core 0.15.44 → 0.15.46

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.
Files changed (94) hide show
  1. package/README.md +11 -2
  2. package/dist/__tests__/guardrail-engine.test.js +41 -1
  3. package/dist/__tests__/guardrail-engine.test.js.map +1 -1
  4. package/dist/__tests__/task-runner-guardrail-events.test.d.ts +2 -0
  5. package/dist/__tests__/task-runner-guardrail-events.test.d.ts.map +1 -0
  6. package/dist/__tests__/task-runner-guardrail-events.test.js +130 -0
  7. package/dist/__tests__/task-runner-guardrail-events.test.js.map +1 -0
  8. package/dist/adapter.d.ts +5 -1
  9. package/dist/adapter.d.ts.map +1 -1
  10. package/dist/events.d.ts +7 -0
  11. package/dist/events.d.ts.map +1 -1
  12. package/dist/guardrails/index.d.ts +1 -1
  13. package/dist/guardrails/index.d.ts.map +1 -1
  14. package/dist/guardrails/index.js +1 -1
  15. package/dist/guardrails/index.js.map +1 -1
  16. package/dist/guardrails/tool-middleware.d.ts +9 -0
  17. package/dist/guardrails/tool-middleware.d.ts.map +1 -1
  18. package/dist/guardrails/tool-middleware.js +31 -1
  19. package/dist/guardrails/tool-middleware.js.map +1 -1
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/mission-executor.d.ts +8 -2
  25. package/dist/mission-executor.d.ts.map +1 -1
  26. package/dist/mission-executor.js.map +1 -1
  27. package/dist/orchestrator-engine.d.ts +4 -0
  28. package/dist/orchestrator-engine.d.ts.map +1 -1
  29. package/dist/orchestrator-engine.js.map +1 -1
  30. package/dist/scheduling/dispatcher.d.ts +45 -0
  31. package/dist/scheduling/dispatcher.d.ts.map +1 -0
  32. package/dist/scheduling/dispatcher.js +201 -0
  33. package/dist/scheduling/dispatcher.js.map +1 -0
  34. package/dist/scheduling/dispatcher.test.d.ts +2 -0
  35. package/dist/scheduling/dispatcher.test.d.ts.map +1 -0
  36. package/dist/scheduling/dispatcher.test.js +378 -0
  37. package/dist/scheduling/dispatcher.test.js.map +1 -0
  38. package/dist/scheduling/driver.d.ts +15 -0
  39. package/dist/scheduling/driver.d.ts.map +1 -0
  40. package/dist/scheduling/driver.js +2 -0
  41. package/dist/scheduling/driver.js.map +1 -0
  42. package/dist/scheduling/index.d.ts +9 -0
  43. package/dist/scheduling/index.d.ts.map +1 -0
  44. package/dist/scheduling/index.js +8 -0
  45. package/dist/scheduling/index.js.map +1 -0
  46. package/dist/scheduling/occurrence.d.ts +17 -0
  47. package/dist/scheduling/occurrence.d.ts.map +1 -0
  48. package/dist/scheduling/occurrence.js +164 -0
  49. package/dist/scheduling/occurrence.js.map +1 -0
  50. package/dist/scheduling/occurrence.test.d.ts +2 -0
  51. package/dist/scheduling/occurrence.test.d.ts.map +1 -0
  52. package/dist/scheduling/occurrence.test.js +148 -0
  53. package/dist/scheduling/occurrence.test.js.map +1 -0
  54. package/dist/scheduling/state-machine.d.ts +10 -0
  55. package/dist/scheduling/state-machine.d.ts.map +1 -0
  56. package/dist/scheduling/state-machine.js +36 -0
  57. package/dist/scheduling/state-machine.js.map +1 -0
  58. package/dist/scheduling/state-machine.test.d.ts +2 -0
  59. package/dist/scheduling/state-machine.test.d.ts.map +1 -0
  60. package/dist/scheduling/state-machine.test.js +77 -0
  61. package/dist/scheduling/state-machine.test.js.map +1 -0
  62. package/dist/scheduling/store.d.ts +100 -0
  63. package/dist/scheduling/store.d.ts.map +1 -0
  64. package/dist/scheduling/store.js +635 -0
  65. package/dist/scheduling/store.js.map +1 -0
  66. package/dist/scheduling/store.test.d.ts +2 -0
  67. package/dist/scheduling/store.test.d.ts.map +1 -0
  68. package/dist/scheduling/store.test.js +462 -0
  69. package/dist/scheduling/store.test.js.map +1 -0
  70. package/dist/scheduling/types.d.ts +195 -0
  71. package/dist/scheduling/types.d.ts.map +1 -0
  72. package/dist/scheduling/types.js +2 -0
  73. package/dist/scheduling/types.js.map +1 -0
  74. package/dist/scheduling/validation.d.ts +28 -0
  75. package/dist/scheduling/validation.d.ts.map +1 -0
  76. package/dist/scheduling/validation.js +614 -0
  77. package/dist/scheduling/validation.js.map +1 -0
  78. package/dist/scheduling/validation.test.d.ts +2 -0
  79. package/dist/scheduling/validation.test.d.ts.map +1 -0
  80. package/dist/scheduling/validation.test.js +576 -0
  81. package/dist/scheduling/validation.test.js.map +1 -0
  82. package/dist/task-runner.d.ts +1 -0
  83. package/dist/task-runner.d.ts.map +1 -1
  84. package/dist/task-runner.js +38 -0
  85. package/dist/task-runner.js.map +1 -1
  86. package/dist/types/agent.d.ts +8 -0
  87. package/dist/types/agent.d.ts.map +1 -1
  88. package/dist/types/agent.js.map +1 -1
  89. package/dist/types/config.d.ts +5 -0
  90. package/dist/types/config.d.ts.map +1 -1
  91. package/dist/types/config.js.map +1 -1
  92. package/dist/types/mission.d.ts +13 -3
  93. package/dist/types/mission.d.ts.map +1 -1
  94. package/package.json +6 -1
@@ -0,0 +1,576 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { SCHEDULE_LIMITS, normalizeCreateScheduleInput, normalizeCronExpression, normalizeScheduleInvocation, normalizeScheduleTiming, normalizeUpdateScheduleInput, translateLegacyMissionSchedule, } from "./index.js";
3
+ const NOW = new Date("2026-07-28T10:00:00.000Z");
4
+ describe("schedule timing validation", () => {
5
+ it("normalizes safe five-field cron expressions and IANA timezones", () => {
6
+ expect(normalizeScheduleTiming({
7
+ kind: "cron",
8
+ expression: " */15 9-17 * * 1-5 ",
9
+ timezone: " Europe/Rome ",
10
+ }, { now: NOW })).toEqual({
11
+ kind: "cron",
12
+ expression: "*/15 9-17 * * 1-5",
13
+ timezone: "Europe/Rome",
14
+ });
15
+ });
16
+ it.each([
17
+ ["too few fields", "* * * *"],
18
+ ["too many fields", "* * * * * *"],
19
+ ["zero step", "*/0 * * * *"],
20
+ ["negative step", "*/-1 * * * *"],
21
+ ["out-of-range minute", "60 * * * *"],
22
+ ["out-of-range hour", "0 24 * * *"],
23
+ ["reversed range", "10-2 * * * *"],
24
+ ["empty list item", "1,,2 * * * *"],
25
+ ["unsupported shortcut", "@daily"],
26
+ ["unsupported modifier", "0 9 L * *"],
27
+ ["non-numeric token", "zero 9 * * *"],
28
+ ])("rejects %s", (_name, expression) => {
29
+ expect(() => normalizeCronExpression(expression)).toThrow(/cron/i);
30
+ });
31
+ it("normalizes Sunday 7 without changing the accepted expression", () => {
32
+ expect(normalizeCronExpression("0 9 * * 7")).toBe("0 9 * * 7");
33
+ });
34
+ it("rejects invalid and unknown timing fields", () => {
35
+ expect(() => normalizeScheduleTiming({
36
+ kind: "cron",
37
+ expression: "0 9 * * *",
38
+ timezone: "Mars/Olympus",
39
+ }, { now: NOW })).toThrow(/timezone/i);
40
+ expect(() => normalizeScheduleTiming({
41
+ kind: "calendar",
42
+ expression: "daily",
43
+ timezone: "UTC",
44
+ }, { now: NOW })).toThrow(/kind/i);
45
+ expect(() => normalizeScheduleTiming({
46
+ kind: "cron",
47
+ expression: "0 9 * * *",
48
+ timezone: "UTC",
49
+ futureOption: true,
50
+ }, { now: NOW })).toThrow(/futureOption/);
51
+ });
52
+ it("normalizes a future one-time occurrence to UTC", () => {
53
+ expect(normalizeScheduleTiming({
54
+ kind: "once",
55
+ at: "2026-07-28T14:30:00+02:00",
56
+ timezone: "Europe/Rome",
57
+ }, { now: NOW })).toEqual({
58
+ kind: "once",
59
+ at: "2026-07-28T12:30:00.000Z",
60
+ timezone: "Europe/Rome",
61
+ });
62
+ });
63
+ it.each([
64
+ "2026-07-28T09:59:59.999Z",
65
+ "2026-07-28T10:00:00.000Z",
66
+ ])("rejects a one-time occurrence that is not in the future: %s", (at) => {
67
+ expect(() => normalizeScheduleTiming({
68
+ kind: "once",
69
+ at,
70
+ timezone: "UTC",
71
+ }, { now: NOW })).toThrow(/future/i);
72
+ });
73
+ it("requires an unambiguous absolute timestamp for one-time schedules", () => {
74
+ expect(() => normalizeScheduleTiming({
75
+ kind: "once",
76
+ at: "2026-10-25T02:30:00",
77
+ timezone: "Europe/Rome",
78
+ }, { now: NOW })).toThrow(/offset/i);
79
+ });
80
+ });
81
+ describe("schedule invocation validation", () => {
82
+ it("normalizes an agent invocation with explicit runtime options", () => {
83
+ expect(normalizeScheduleInvocation({
84
+ surface: "agent",
85
+ agentName: " assistant ",
86
+ input: { prompt: " Run the report " },
87
+ session: {
88
+ mode: "reuse",
89
+ sessionId: " session-1 ",
90
+ userId: " external-user-1 ",
91
+ },
92
+ execution: {
93
+ loop: " review ",
94
+ model: " openai/gpt-5 ",
95
+ sandbox: { isolation: "fresh" },
96
+ guardrails: { mode: " strict " },
97
+ metadata: { source: "nightly" },
98
+ },
99
+ })).toEqual({
100
+ surface: "agent",
101
+ agentName: "assistant",
102
+ input: { prompt: "Run the report" },
103
+ session: {
104
+ mode: "reuse",
105
+ sessionId: "session-1",
106
+ userId: "external-user-1",
107
+ },
108
+ execution: {
109
+ loop: "review",
110
+ model: "openai/gpt-5",
111
+ sandbox: { isolation: "fresh" },
112
+ guardrails: { mode: "strict" },
113
+ metadata: { source: "nightly" },
114
+ },
115
+ });
116
+ });
117
+ it("accepts a bounded message input and clones it", () => {
118
+ const invocation = {
119
+ surface: "agent",
120
+ agentName: "assistant",
121
+ input: {
122
+ messages: [
123
+ { role: "system", content: "Be concise" },
124
+ { role: "user", content: "Create the report" },
125
+ ],
126
+ },
127
+ session: { mode: "new", userId: "user-1" },
128
+ };
129
+ const normalized = normalizeScheduleInvocation(invocation);
130
+ expect(normalized).toEqual(invocation);
131
+ expect(normalized).not.toBe(invocation);
132
+ expect(normalized.surface).toBe("agent");
133
+ if (normalized.surface !== "agent") {
134
+ throw new Error("Expected an agent invocation");
135
+ }
136
+ expect(normalized.input).not.toBe(invocation.input);
137
+ });
138
+ it.each([
139
+ {
140
+ name: "agent without input",
141
+ value: { surface: "agent", agentName: "assistant", input: {} },
142
+ error: /prompt or messages/i,
143
+ },
144
+ {
145
+ name: "agent with ambiguous input",
146
+ value: {
147
+ surface: "agent",
148
+ agentName: "assistant",
149
+ input: {
150
+ prompt: "hello",
151
+ messages: [{ role: "user", content: "hello" }],
152
+ },
153
+ },
154
+ error: /not both/i,
155
+ },
156
+ {
157
+ name: "new session carrying an id",
158
+ value: {
159
+ surface: "agent",
160
+ agentName: "assistant",
161
+ input: { prompt: "hello" },
162
+ session: { mode: "new", sessionId: "existing" },
163
+ },
164
+ error: /new session/i,
165
+ },
166
+ {
167
+ name: "reused session without an id",
168
+ value: {
169
+ surface: "agent",
170
+ agentName: "assistant",
171
+ input: { prompt: "hello" },
172
+ session: { mode: "reuse" },
173
+ },
174
+ error: /sessionId/i,
175
+ },
176
+ {
177
+ name: "unknown message role",
178
+ value: {
179
+ surface: "agent",
180
+ agentName: "assistant",
181
+ input: { messages: [{ role: "developer", content: "hidden" }] },
182
+ },
183
+ error: /role/i,
184
+ },
185
+ ])("rejects $name", ({ value, error }) => {
186
+ expect(() => normalizeScheduleInvocation(value)).toThrow(error);
187
+ });
188
+ it("normalizes a durable task invocation", () => {
189
+ expect(normalizeScheduleInvocation({
190
+ surface: "task",
191
+ agentName: "researcher",
192
+ title: " Daily research ",
193
+ prompt: " Find relevant updates ",
194
+ userId: " user-1 ",
195
+ metadata: { team: "product" },
196
+ execution: { sandbox: { isolation: "reuse" } },
197
+ })).toEqual({
198
+ surface: "task",
199
+ agentName: "researcher",
200
+ title: "Daily research",
201
+ prompt: "Find relevant updates",
202
+ userId: "user-1",
203
+ metadata: { team: "product" },
204
+ execution: { sandbox: { isolation: "reuse" } },
205
+ });
206
+ });
207
+ it("enforces distinct channel send and agent-reply contracts", () => {
208
+ expect(normalizeScheduleInvocation({
209
+ surface: "channel",
210
+ channelId: " telegram-primary ",
211
+ routeId: " route-1 ",
212
+ externalThreadId: " thread-1 ",
213
+ mode: "send",
214
+ text: " Scheduled update ",
215
+ metadata: { campaign: "launch" },
216
+ })).toEqual({
217
+ surface: "channel",
218
+ channelId: "telegram-primary",
219
+ routeId: "route-1",
220
+ externalThreadId: "thread-1",
221
+ mode: "send",
222
+ text: "Scheduled update",
223
+ metadata: { campaign: "launch" },
224
+ });
225
+ expect(normalizeScheduleInvocation({
226
+ surface: "channel",
227
+ channelId: "telegram-primary",
228
+ mode: "agent_reply",
229
+ agentName: "assistant",
230
+ prompt: "Summarize the day",
231
+ execution: { model: "openai/gpt-5" },
232
+ })).toMatchObject({
233
+ mode: "agent_reply",
234
+ agentName: "assistant",
235
+ prompt: "Summarize the day",
236
+ });
237
+ });
238
+ it.each([
239
+ {
240
+ value: {
241
+ surface: "channel",
242
+ channelId: "telegram",
243
+ mode: "send",
244
+ prompt: "wrong",
245
+ },
246
+ error: /prompt|text/i,
247
+ },
248
+ {
249
+ value: {
250
+ surface: "channel",
251
+ channelId: "telegram",
252
+ mode: "send",
253
+ text: "hello",
254
+ execution: { model: "openai/gpt-5" },
255
+ },
256
+ error: /execution/i,
257
+ },
258
+ {
259
+ value: {
260
+ surface: "channel",
261
+ channelId: "telegram",
262
+ mode: "agent_reply",
263
+ agentName: "assistant",
264
+ prompt: "hello",
265
+ text: "ambiguous",
266
+ },
267
+ error: /text/i,
268
+ },
269
+ {
270
+ value: {
271
+ surface: "channel",
272
+ channelId: "telegram",
273
+ mode: "agent_reply",
274
+ prompt: "missing agent",
275
+ },
276
+ error: /agentName/i,
277
+ },
278
+ ])("rejects invalid channel mode payloads", ({ value, error }) => {
279
+ expect(() => normalizeScheduleInvocation(value)).toThrow(error);
280
+ });
281
+ it("normalizes webhook and legacy mission invocations", () => {
282
+ expect(normalizeScheduleInvocation({
283
+ surface: "webhook",
284
+ webhookId: " release-hook ",
285
+ payload: { deployment: 42 },
286
+ })).toEqual({
287
+ surface: "webhook",
288
+ webhookId: "release-hook",
289
+ payload: { deployment: 42 },
290
+ });
291
+ expect(normalizeScheduleInvocation({
292
+ surface: "legacy_mission",
293
+ missionId: " mission-1 ",
294
+ })).toEqual({
295
+ surface: "legacy_mission",
296
+ missionId: "mission-1",
297
+ });
298
+ });
299
+ it("rejects unsupported surfaces, fields, and execution options", () => {
300
+ expect(() => normalizeScheduleInvocation({
301
+ surface: "loop",
302
+ loop: "review",
303
+ })).toThrow(/surface/i);
304
+ expect(() => normalizeScheduleInvocation({
305
+ surface: "webhook",
306
+ webhookId: "hook",
307
+ execution: { model: "openai/gpt-5" },
308
+ })).toThrow(/execution/);
309
+ expect(() => normalizeScheduleInvocation({
310
+ surface: "task",
311
+ agentName: "assistant",
312
+ title: "task",
313
+ prompt: "run",
314
+ priority: "future",
315
+ })).toThrow(/priority/);
316
+ expect(() => normalizeScheduleInvocation({
317
+ surface: "agent",
318
+ agentName: "assistant",
319
+ input: { prompt: "run" },
320
+ execution: { temperature: 0.2 },
321
+ })).toThrow(/temperature/);
322
+ });
323
+ });
324
+ describe("schedule definition validation", () => {
325
+ it("normalizes defaults without retaining unknown input", () => {
326
+ const normalized = normalizeCreateScheduleInput({
327
+ id: " schedule-1 ",
328
+ name: " Daily summary ",
329
+ description: " Summarize activity ",
330
+ timing: {
331
+ kind: "cron",
332
+ expression: "0 9 * * 1-5",
333
+ timezone: "Europe/Rome",
334
+ },
335
+ invocation: {
336
+ surface: "agent",
337
+ agentName: "assistant",
338
+ input: { prompt: "Summarize yesterday" },
339
+ },
340
+ }, { now: NOW });
341
+ expect(normalized).toEqual({
342
+ id: "schedule-1",
343
+ name: "Daily summary",
344
+ description: "Summarize activity",
345
+ timing: {
346
+ kind: "cron",
347
+ expression: "0 9 * * 1-5",
348
+ timezone: "Europe/Rome",
349
+ },
350
+ invocation: {
351
+ surface: "agent",
352
+ agentName: "assistant",
353
+ input: { prompt: "Summarize yesterday" },
354
+ },
355
+ status: "active",
356
+ policy: {
357
+ catchUp: "skip",
358
+ misfireGraceSeconds: 300,
359
+ maxConcurrency: 1,
360
+ },
361
+ metadata: {},
362
+ });
363
+ });
364
+ it("normalizes explicit policy and paused creation", () => {
365
+ expect(normalizeCreateScheduleInput({
366
+ name: "One time",
367
+ timing: {
368
+ kind: "once",
369
+ at: "2026-07-29T10:00:00Z",
370
+ timezone: "UTC",
371
+ },
372
+ invocation: {
373
+ surface: "webhook",
374
+ webhookId: "hook-1",
375
+ },
376
+ status: "paused",
377
+ policy: {
378
+ catchUp: "latest",
379
+ misfireGraceSeconds: 0,
380
+ maxConcurrency: 12,
381
+ },
382
+ metadata: { owner: "ops" },
383
+ }, { now: NOW })).toMatchObject({
384
+ status: "paused",
385
+ policy: {
386
+ catchUp: "latest",
387
+ misfireGraceSeconds: 0,
388
+ maxConcurrency: 12,
389
+ },
390
+ });
391
+ });
392
+ it.each([
393
+ [{ catchUp: "all" }, /catchUp/i],
394
+ [{ misfireGraceSeconds: -1 }, /misfireGraceSeconds/i],
395
+ [{ misfireGraceSeconds: 1.5 }, /misfireGraceSeconds/i],
396
+ [{ maxConcurrency: 0 }, /maxConcurrency/i],
397
+ [{ maxConcurrency: SCHEDULE_LIMITS.maxConcurrency + 1 }, /maxConcurrency/i],
398
+ [{ futurePolicy: true }, /futurePolicy/i],
399
+ ])("rejects an invalid policy", (policy, error) => {
400
+ expect(() => normalizeCreateScheduleInput({
401
+ timing: {
402
+ kind: "cron",
403
+ expression: "0 9 * * *",
404
+ timezone: "UTC",
405
+ },
406
+ invocation: {
407
+ surface: "legacy_mission",
408
+ missionId: "mission-1",
409
+ },
410
+ policy,
411
+ }, { now: NOW })).toThrow(error);
412
+ });
413
+ it("rejects terminal creation states and unknown definition fields", () => {
414
+ const base = {
415
+ timing: {
416
+ kind: "cron",
417
+ expression: "0 9 * * *",
418
+ timezone: "UTC",
419
+ },
420
+ invocation: {
421
+ surface: "legacy_mission",
422
+ missionId: "mission-1",
423
+ },
424
+ };
425
+ expect(() => normalizeCreateScheduleInput({
426
+ ...base,
427
+ status: "deleted",
428
+ }, { now: NOW })).toThrow(/status/i);
429
+ expect(() => normalizeCreateScheduleInput({
430
+ ...base,
431
+ credentials: { token: "secret" },
432
+ }, { now: NOW })).toThrow(/credentials/);
433
+ });
434
+ it("rejects cyclic, polluted, non-finite, and oversized metadata", () => {
435
+ const cyclic = {};
436
+ cyclic.self = cyclic;
437
+ const polluted = JSON.parse('{"__proto__":{"admin":true}}');
438
+ const base = {
439
+ timing: {
440
+ kind: "cron",
441
+ expression: "0 9 * * *",
442
+ timezone: "UTC",
443
+ },
444
+ invocation: {
445
+ surface: "legacy_mission",
446
+ missionId: "mission-1",
447
+ },
448
+ };
449
+ for (const metadata of [
450
+ cyclic,
451
+ polluted,
452
+ { invalid: Number.POSITIVE_INFINITY },
453
+ { invalid: () => "unsafe" },
454
+ { text: "x".repeat(SCHEDULE_LIMITS.metadataBytes + 1) },
455
+ ]) {
456
+ expect(() => normalizeCreateScheduleInput({
457
+ ...base,
458
+ metadata,
459
+ }, { now: NOW })).toThrow(/metadata/i);
460
+ }
461
+ });
462
+ it("normalizes update patches and rejects empty or immutable changes", () => {
463
+ expect(normalizeUpdateScheduleInput({
464
+ description: null,
465
+ status: "paused",
466
+ policy: { maxConcurrency: 2 },
467
+ metadata: { owner: "ops" },
468
+ }, { now: NOW })).toEqual({
469
+ description: null,
470
+ status: "paused",
471
+ policy: { maxConcurrency: 2 },
472
+ metadata: { owner: "ops" },
473
+ });
474
+ expect(() => normalizeUpdateScheduleInput({}, { now: NOW })).toThrow(/at least one/i);
475
+ expect(() => normalizeUpdateScheduleInput({
476
+ id: "new-id",
477
+ }, { now: NOW })).toThrow(/id/);
478
+ expect(() => normalizeUpdateScheduleInput({
479
+ status: "deleted",
480
+ }, { now: NOW })).toThrow(/status/i);
481
+ });
482
+ });
483
+ describe("legacy mission schedule translation", () => {
484
+ it("translates a recurring mission cron request with compatibility metadata", () => {
485
+ expect(translateLegacyMissionSchedule({
486
+ missionId: " mission-1 ",
487
+ expression: " 0 9 * * 1-5 ",
488
+ recurring: true,
489
+ endDate: "2026-08-30T12:00:00+02:00",
490
+ }, { now: NOW, timezone: "Europe/Rome" })).toEqual({
491
+ name: "Mission mission-1 schedule",
492
+ timing: {
493
+ kind: "cron",
494
+ expression: "0 9 * * 1-5",
495
+ timezone: "Europe/Rome",
496
+ },
497
+ invocation: {
498
+ surface: "legacy_mission",
499
+ missionId: "mission-1",
500
+ },
501
+ status: "active",
502
+ policy: {
503
+ catchUp: "skip",
504
+ misfireGraceSeconds: 300,
505
+ maxConcurrency: 1,
506
+ },
507
+ metadata: {
508
+ compatibility: {
509
+ source: "mission-v1",
510
+ recurring: true,
511
+ endDate: "2026-08-30T10:00:00.000Z",
512
+ deprecated: true,
513
+ },
514
+ },
515
+ });
516
+ });
517
+ it("translates an ISO one-time mission request", () => {
518
+ expect(translateLegacyMissionSchedule({
519
+ missionId: "mission-1",
520
+ expression: "2026-07-29T10:00:00Z",
521
+ recurring: false,
522
+ }, { now: NOW })).toMatchObject({
523
+ timing: {
524
+ kind: "once",
525
+ at: "2026-07-29T10:00:00.000Z",
526
+ timezone: "UTC",
527
+ },
528
+ invocation: {
529
+ surface: "legacy_mission",
530
+ missionId: "mission-1",
531
+ },
532
+ metadata: {
533
+ compatibility: {
534
+ source: "mission-v1",
535
+ recurring: false,
536
+ deprecated: true,
537
+ },
538
+ },
539
+ });
540
+ });
541
+ it("preserves legacy one-shot cron intent explicitly", () => {
542
+ expect(translateLegacyMissionSchedule({
543
+ missionId: "mission-1",
544
+ expression: "0 9 * * *",
545
+ recurring: false,
546
+ }, { now: NOW })).toMatchObject({
547
+ timing: {
548
+ kind: "cron",
549
+ expression: "0 9 * * *",
550
+ },
551
+ metadata: {
552
+ compatibility: {
553
+ source: "mission-v1",
554
+ recurring: false,
555
+ maxOccurrences: 1,
556
+ deprecated: true,
557
+ },
558
+ },
559
+ });
560
+ });
561
+ it("rejects invalid legacy requests instead of guessing", () => {
562
+ expect(() => translateLegacyMissionSchedule({
563
+ missionId: "",
564
+ expression: "tomorrow",
565
+ }, { now: NOW })).toThrow(/missionId/i);
566
+ expect(() => translateLegacyMissionSchedule({
567
+ missionId: "mission-1",
568
+ expression: "tomorrow",
569
+ }, { now: NOW })).toThrow(/expression/i);
570
+ expect(() => translateLegacyMissionSchedule({
571
+ missionId: "mission-1",
572
+ expression: "2026-07-27T10:00:00Z",
573
+ }, { now: NOW })).toThrow(/future/i);
574
+ });
575
+ });
576
+ //# sourceMappingURL=validation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.test.js","sourceRoot":"","sources":["../../src/scheduling/validation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,uBAAuB,EACvB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,YAAY,CAAC;AAEpB,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;AAEjD,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,uBAAuB,CAAC;YAC7B,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,yBAAyB;YACrC,QAAQ,EAAE,eAAe;SAC1B,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACxB,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,mBAAmB;YAC/B,QAAQ,EAAE,aAAa;SACxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,gBAAgB,EAAE,SAAS,CAAC;QAC7B,CAAC,iBAAiB,EAAE,aAAa,CAAC;QAClC,CAAC,WAAW,EAAE,aAAa,CAAC;QAC5B,CAAC,eAAe,EAAE,cAAc,CAAC;QACjC,CAAC,qBAAqB,EAAE,YAAY,CAAC;QACrC,CAAC,mBAAmB,EAAE,YAAY,CAAC;QACnC,CAAC,gBAAgB,EAAE,cAAc,CAAC;QAClC,CAAC,iBAAiB,EAAE,cAAc,CAAC;QACnC,CAAC,sBAAsB,EAAE,QAAQ,CAAC;QAClC,CAAC,sBAAsB,EAAE,WAAW,CAAC;QACrC,CAAC,mBAAmB,EAAE,cAAc,CAAC;KACtC,CAAC,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;QACrC,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;YACnC,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,WAAW;YACvB,QAAQ,EAAE,cAAc;SACzB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEvC,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;YACnC,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE,OAAO;YACnB,QAAQ,EAAE,KAAK;SAChB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAEnC,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;YACnC,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,WAAW;YACvB,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,IAAI;SACnB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,uBAAuB,CAAC;YAC7B,IAAI,EAAE,MAAM;YACZ,EAAE,EAAE,2BAA2B;YAC/B,QAAQ,EAAE,aAAa;SACxB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACxB,IAAI,EAAE,MAAM;YACZ,EAAE,EAAE,0BAA0B;YAC9B,QAAQ,EAAE,aAAa;SACxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,0BAA0B;QAC1B,0BAA0B;KAC3B,CAAC,CAAC,6DAA6D,EAAE,CAAC,EAAE,EAAE,EAAE;QACvE,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;YACnC,IAAI,EAAE,MAAM;YACZ,EAAE;YACF,QAAQ,EAAE,KAAK;SAChB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;YACnC,IAAI,EAAE,MAAM;YACZ,EAAE,EAAE,qBAAqB;YACzB,QAAQ,EAAE,aAAa;SACxB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,2BAA2B,CAAC;YACjC,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,aAAa;YACxB,KAAK,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACrC,OAAO,EAAE;gBACP,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,aAAa;gBACxB,MAAM,EAAE,mBAAmB;aAC5B;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,gBAAgB;gBACvB,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;gBAC/B,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;gBAChC,QAAQ,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;aAChC;SACF,CAAC,CAAC,CAAC,OAAO,CAAC;YACV,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,WAAW;YACtB,KAAK,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE;YACnC,OAAO,EAAE;gBACP,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,WAAW;gBACtB,MAAM,EAAE,iBAAiB;aAC1B;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,cAAc;gBACrB,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;gBAC/B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC9B,QAAQ,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;aAChC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,UAAU,GAAG;YACjB,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,WAAW;YACtB,KAAK,EAAE;gBACL,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;oBACzC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE;iBAC/C;aACF;YACD,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE;SAClC,CAAC;QAEX,MAAM,UAAU,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACvC,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN;YACE,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE;YAC9D,KAAK,EAAE,qBAAqB;SAC7B;QACD;YACE,IAAI,EAAE,4BAA4B;YAClC,KAAK,EAAE;gBACL,OAAO,EAAE,OAAO;gBAChB,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE;oBACL,MAAM,EAAE,OAAO;oBACf,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;iBAC/C;aACF;YACD,KAAK,EAAE,WAAW;SACnB;QACD;YACE,IAAI,EAAE,4BAA4B;YAClC,KAAK,EAAE;gBACL,OAAO,EAAE,OAAO;gBAChB,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;gBAC1B,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE;aAChD;YACD,KAAK,EAAE,cAAc;SACtB;QACD;YACE,IAAI,EAAE,8BAA8B;YACpC,KAAK,EAAE;gBACL,OAAO,EAAE,OAAO;gBAChB,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;gBAC1B,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;aAC3B;YACD,KAAK,EAAE,YAAY;SACpB;QACD;YACE,IAAI,EAAE,sBAAsB;YAC5B,KAAK,EAAE;gBACL,OAAO,EAAE,OAAO;gBAChB,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE;aAChE;YACD,KAAK,EAAE,OAAO;SACf;KACF,CAAC,CAAC,eAAe,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACvC,MAAM,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,2BAA2B,CAAC;YACjC,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,YAAY;YACvB,KAAK,EAAE,kBAAkB;YACzB,MAAM,EAAE,yBAAyB;YACjC,MAAM,EAAE,UAAU;YAClB,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YAC7B,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;SAC/C,CAAC,CAAC,CAAC,OAAO,CAAC;YACV,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,YAAY;YACvB,KAAK,EAAE,gBAAgB;YACvB,MAAM,EAAE,uBAAuB;YAC/B,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YAC7B,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;SAC/C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,2BAA2B,CAAC;YACjC,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,oBAAoB;YAC/B,OAAO,EAAE,WAAW;YACpB,gBAAgB,EAAE,YAAY;YAC9B,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,oBAAoB;YAC1B,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;SACjC,CAAC,CAAC,CAAC,OAAO,CAAC;YACV,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,kBAAkB;YAC7B,OAAO,EAAE,SAAS;YAClB,gBAAgB,EAAE,UAAU;YAC5B,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,kBAAkB;YACxB,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;SACjC,CAAC,CAAC;QAEH,MAAM,CAAC,2BAA2B,CAAC;YACjC,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,kBAAkB;YAC7B,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,WAAW;YACtB,MAAM,EAAE,mBAAmB;YAC3B,SAAS,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE;SACrC,CAAC,CAAC,CAAC,aAAa,CAAC;YAChB,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,WAAW;YACtB,MAAM,EAAE,mBAAmB;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,UAAU;gBACrB,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,OAAO;aAChB;YACD,KAAK,EAAE,cAAc;SACtB;QACD;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,UAAU;gBACrB,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE;aACrC;YACD,KAAK,EAAE,YAAY;SACpB;QACD;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,UAAU;gBACrB,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,WAAW;gBACtB,MAAM,EAAE,OAAO;gBACf,IAAI,EAAE,WAAW;aAClB;YACD,KAAK,EAAE,OAAO;SACf;QACD;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,UAAU;gBACrB,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,eAAe;aACxB;YACD,KAAK,EAAE,YAAY;SACpB;KACF,CAAC,CAAC,uCAAuC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QAC/D,MAAM,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,2BAA2B,CAAC;YACjC,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,gBAAgB;YAC3B,OAAO,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;SAC5B,CAAC,CAAC,CAAC,OAAO,CAAC;YACV,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,cAAc;YACzB,OAAO,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;SAC5B,CAAC,CAAC;QAEH,MAAM,CAAC,2BAA2B,CAAC;YACjC,OAAO,EAAE,gBAAgB;YACzB,SAAS,EAAE,aAAa;SACzB,CAAC,CAAC,CAAC,OAAO,CAAC;YACV,OAAO,EAAE,gBAAgB;YACzB,SAAS,EAAE,WAAW;SACvB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC;YACvC,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAExB,MAAM,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC;YACvC,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,MAAM;YACjB,SAAS,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE;SACrC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEzB,MAAM,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC;YACvC,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,WAAW;YACtB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAExB,MAAM,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC;YACvC,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,WAAW;YACtB,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;YACxB,SAAS,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE;SAChC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,UAAU,GAAG,4BAA4B,CAAC;YAC9C,EAAE,EAAE,cAAc;YAClB,IAAI,EAAE,iBAAiB;YACvB,WAAW,EAAE,sBAAsB;YACnC,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,aAAa;gBACzB,QAAQ,EAAE,aAAa;aACxB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,OAAO;gBAChB,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE,EAAE,MAAM,EAAE,qBAAqB,EAAE;aACzC;SACF,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAEjB,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;YACzB,EAAE,EAAE,YAAY;YAChB,IAAI,EAAE,eAAe;YACrB,WAAW,EAAE,oBAAoB;YACjC,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,aAAa;gBACzB,QAAQ,EAAE,aAAa;aACxB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,OAAO;gBAChB,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE,EAAE,MAAM,EAAE,qBAAqB,EAAE;aACzC;YACD,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE;gBACN,OAAO,EAAE,MAAM;gBACf,mBAAmB,EAAE,GAAG;gBACxB,cAAc,EAAE,CAAC;aAClB;YACD,QAAQ,EAAE,EAAE;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,4BAA4B,CAAC;YAClC,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,EAAE,EAAE,sBAAsB;gBAC1B,QAAQ,EAAE,KAAK;aAChB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,QAAQ;aACpB;YACD,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE;gBACN,OAAO,EAAE,QAAQ;gBACjB,mBAAmB,EAAE,CAAC;gBACtB,cAAc,EAAE,EAAE;aACnB;YACD,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SAC3B,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;YAC9B,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE;gBACN,OAAO,EAAE,QAAQ;gBACjB,mBAAmB,EAAE,CAAC;gBACtB,cAAc,EAAE,EAAE;aACnB;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,UAAU,CAAC;QAChC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,sBAAsB,CAAC;QACrD,CAAC,EAAE,mBAAmB,EAAE,GAAG,EAAE,EAAE,sBAAsB,CAAC;QACtD,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE,iBAAiB,CAAC;QAC1C,CAAC,EAAE,cAAc,EAAE,eAAe,CAAC,cAAc,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC;QAC3E,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,eAAe,CAAC;KAC1C,CAAC,CAAC,2BAA2B,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAChD,MAAM,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC;YACxC,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,WAAW;gBACvB,QAAQ,EAAE,KAAK;aAChB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,gBAAgB;gBACzB,SAAS,EAAE,WAAW;aACvB;YACD,MAAM;SACP,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,IAAI,GAAG;YACX,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,WAAW;gBACvB,QAAQ,EAAE,KAAK;aAChB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,gBAAgB;gBACzB,SAAS,EAAE,WAAW;aACvB;SACF,CAAC;QAEF,MAAM,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC;YACxC,GAAG,IAAI;YACP,MAAM,EAAE,SAAS;SAClB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAErC,MAAM,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC;YACxC,GAAG,IAAI;YACP,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;SACjC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC;QACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG;YACX,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,WAAW;gBACvB,QAAQ,EAAE,KAAK;aAChB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,gBAAgB;gBACzB,SAAS,EAAE,WAAW;aACvB;SACF,CAAC;QAEF,KAAK,MAAM,QAAQ,IAAI;YACrB,MAAM;YACN,QAAQ;YACR,EAAE,OAAO,EAAE,MAAM,CAAC,iBAAiB,EAAE;YACrC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE;YAC3B,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,aAAa,GAAG,CAAC,CAAC,EAAE;SACxD,EAAE,CAAC;YACF,MAAM,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC;gBACxC,GAAG,IAAI;gBACP,QAAQ;aACT,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,4BAA4B,CAAC;YAClC,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE;YAC7B,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SAC3B,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACxB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE;YAC7B,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SAC3B,CAAC,CAAC;QAEH,MAAM,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACtF,MAAM,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC;YACxC,EAAE,EAAE,QAAQ;SACb,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC;YACxC,MAAM,EAAE,SAAS;SAClB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,CAAC,8BAA8B,CAAC;YACpC,SAAS,EAAE,aAAa;YACxB,UAAU,EAAE,eAAe;YAC3B,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,2BAA2B;SACrC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACjD,IAAI,EAAE,4BAA4B;YAClC,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,aAAa;gBACzB,QAAQ,EAAE,aAAa;aACxB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,gBAAgB;gBACzB,SAAS,EAAE,WAAW;aACvB;YACD,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE;gBACN,OAAO,EAAE,MAAM;gBACf,mBAAmB,EAAE,GAAG;gBACxB,cAAc,EAAE,CAAC;aAClB;YACD,QAAQ,EAAE;gBACR,aAAa,EAAE;oBACb,MAAM,EAAE,YAAY;oBACpB,SAAS,EAAE,IAAI;oBACf,OAAO,EAAE,0BAA0B;oBACnC,UAAU,EAAE,IAAI;iBACjB;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,8BAA8B,CAAC;YACpC,SAAS,EAAE,WAAW;YACtB,UAAU,EAAE,sBAAsB;YAClC,SAAS,EAAE,KAAK;SACjB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;YAC9B,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,EAAE,EAAE,0BAA0B;gBAC9B,QAAQ,EAAE,KAAK;aAChB;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,gBAAgB;gBACzB,SAAS,EAAE,WAAW;aACvB;YACD,QAAQ,EAAE;gBACR,aAAa,EAAE;oBACb,MAAM,EAAE,YAAY;oBACpB,SAAS,EAAE,KAAK;oBAChB,UAAU,EAAE,IAAI;iBACjB;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,8BAA8B,CAAC;YACpC,SAAS,EAAE,WAAW;YACtB,UAAU,EAAE,WAAW;YACvB,SAAS,EAAE,KAAK;SACjB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;YAC9B,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,WAAW;aACxB;YACD,QAAQ,EAAE;gBACR,aAAa,EAAE;oBACb,MAAM,EAAE,YAAY;oBACpB,SAAS,EAAE,KAAK;oBAChB,cAAc,EAAE,CAAC;oBACjB,UAAU,EAAE,IAAI;iBACjB;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,GAAG,EAAE,CAAC,8BAA8B,CAAC;YAC1C,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,UAAU;SACvB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAExC,MAAM,CAAC,GAAG,EAAE,CAAC,8BAA8B,CAAC;YAC1C,SAAS,EAAE,WAAW;YACtB,UAAU,EAAE,UAAU;SACvB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAEzC,MAAM,CAAC,GAAG,EAAE,CAAC,8BAA8B,CAAC;YAC1C,SAAS,EAAE,WAAW;YACtB,UAAU,EAAE,sBAAsB;SACnC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -32,6 +32,7 @@ export declare class TaskRunner {
32
32
  * The callback is typically the assessment pipeline (handleResult).
33
33
  */
34
34
  collectResults(onResult: (taskId: string, result: TaskResult) => Promise<void> | void): Promise<void>;
35
+ private emitGuardrailEvents;
35
36
  /**
36
37
  * Read the JSONL activity log for a killed run and produce a human-readable
37
38
  * diagnosis of what the agent was doing when it timed out.
@@ -1 +1 @@
1
- {"version":3,"file":"task-runner.d.ts","sourceRoot":"","sources":["../src/task-runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAC;AAoBjE;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAAiB,CAAC;AAsC3D;;GAEG;AACH,qBAAa,UAAU;IAeT,OAAO,CAAC,GAAG;IAdvB,OAAO,CAAC,WAAW,CAAqB;IACxC,gFAAgF;IAChF,OAAO,CAAC,YAAY,CAA6B;IACjD,iFAAiF;IACjF,OAAO,CAAC,UAAU,CAAkC;IACpD;;;;;;OAMG;IACH,OAAO,CAAC,aAAa,CAAsC;gBAEvC,GAAG,EAAE,mBAAmB;YAE9B,yBAAyB;IAgBvC;;;OAGG;IACG,cAAc,CAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GACrE,OAAO,CAAC,IAAI,CAAC;IAmDhB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAyF7B;;;;OAIG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAsD1C;qFACiF;IAC3E,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyDhD;;;OAGG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IA8E7C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIpC,4EAA4E;YAC9D,eAAe;IA+BvB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA4R7C,OAAO,CAAC,iBAAiB;CAK1B"}
1
+ {"version":3,"file":"task-runner.d.ts","sourceRoot":"","sources":["../src/task-runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAC;AAqBjE;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAAiB,CAAC;AAsC3D;;GAEG;AACH,qBAAa,UAAU;IAeT,OAAO,CAAC,GAAG;IAdvB,OAAO,CAAC,WAAW,CAAqB;IACxC,gFAAgF;IAChF,OAAO,CAAC,YAAY,CAA6B;IACjD,iFAAiF;IACjF,OAAO,CAAC,UAAU,CAAkC;IACpD;;;;;;OAMG;IACH,OAAO,CAAC,aAAa,CAAsC;gBAEvC,GAAG,EAAE,mBAAmB;YAE9B,yBAAyB;IAgBvC;;;OAGG;IACG,cAAc,CAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GACrE,OAAO,CAAC,IAAI,CAAC;YAoDF,mBAAmB;IAqCjC;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAyF7B;;;;OAIG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAsD1C;qFACiF;IAC3E,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyDhD;;;OAGG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IA8E7C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIpC,4EAA4E;YAC9D,eAAe;IA+BvB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA4R7C,OAAO,CAAC,iBAAiB;CAK1B"}
@@ -86,6 +86,7 @@ export class TaskRunner {
86
86
  async collectResults(onResult) {
87
87
  const terminalRuns = await this.ctx.runStore.getTerminalRuns();
88
88
  for (const run of terminalRuns) {
89
+ await this.emitGuardrailEvents(run);
89
90
  // Persist sessionId on the task before acknowledging the run.
90
91
  const sid = run.sessionId ?? run.activity.sessionId;
91
92
  if (sid) {
@@ -138,6 +139,43 @@ export class TaskRunner {
138
139
  this.staleWarned.delete(run.taskId);
139
140
  }
140
141
  }
142
+ async emitGuardrailEvents(run) {
143
+ const byId = new Map();
144
+ const sid = run.sessionId ?? run.activity.sessionId;
145
+ if (sid) {
146
+ try {
147
+ const entries = await this.ctx.logStore.getSessionEntries(sid);
148
+ for (const entry of entries) {
149
+ if (entry.event !== "transcript:guardrail_decision")
150
+ continue;
151
+ const data = entry.data;
152
+ const event = data?.event;
153
+ if (!event)
154
+ continue;
155
+ const id = event?.decision?.id;
156
+ if (data?.type === "guardrail_decision" && typeof id === "string") {
157
+ byId.set(id, event);
158
+ }
159
+ }
160
+ }
161
+ catch {
162
+ // Activity is the bounded fallback when transcript storage is down.
163
+ }
164
+ }
165
+ for (const event of run.activity.guardrailDecisions ?? []) {
166
+ const id = event?.decision?.id;
167
+ if (typeof id === "string" && !byId.has(id))
168
+ byId.set(id, event);
169
+ }
170
+ for (const event of byId.values()) {
171
+ this.ctx.emitter.emit("runtime:guardrail", {
172
+ runId: run.id,
173
+ taskId: run.taskId,
174
+ agentName: run.agentName,
175
+ event,
176
+ });
177
+ }
178
+ }
141
179
  /**
142
180
  * Read the JSONL activity log for a killed run and produce a human-readable
143
181
  * diagnosis of what the agent was doing when it timed out.