ag-ui-validate 0.3.0 → 0.4.0

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 (73) hide show
  1. package/README.md +25 -26
  2. package/dist/{catalog-DqTI4VLt.js → catalog-3e6INLCp.js} +120 -2
  3. package/dist/catalog-3e6INLCp.js.map +1 -0
  4. package/dist/{catalog-AB5vuZ8j.cjs → catalog-DH5gDIbo.cjs} +120 -2
  5. package/dist/catalog-DH5gDIbo.cjs.map +1 -0
  6. package/dist/cli.js +639 -61
  7. package/dist/cli.js.map +1 -1
  8. package/dist/{index-Hmqj3r_r.d.cts → index-Cydfs-rB.d.ts} +4 -4
  9. package/dist/{index-oNG1kOp9.d.ts → index-DsVmjcLO.d.cts} +4 -4
  10. package/dist/index.cjs +2 -2
  11. package/dist/index.d.cts +2 -2
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +2 -2
  14. package/dist/report.cjs +11 -2
  15. package/dist/report.cjs.map +1 -1
  16. package/dist/report.d.cts +21 -12
  17. package/dist/report.d.ts +21 -12
  18. package/dist/report.js +11 -2
  19. package/dist/report.js.map +1 -1
  20. package/dist/{src-Dcuqz2QC.js → src-CezZ73Mm.js} +494 -59
  21. package/dist/src-CezZ73Mm.js.map +1 -0
  22. package/dist/{src-D04i3Vso.cjs → src-CyugLoks.cjs} +494 -59
  23. package/dist/src-CyugLoks.cjs.map +1 -0
  24. package/dist/transport.cjs +1 -1
  25. package/dist/transport.d.cts +1 -1
  26. package/dist/transport.d.ts +1 -1
  27. package/dist/transport.js +1 -1
  28. package/dist/{types-oH_QTnn2.d.ts → types-CUIgyj2N.d.cts} +3 -1
  29. package/dist/{types-oH_QTnn2.d.cts → types-CUIgyj2N.d.ts} +3 -1
  30. package/dist/vitest.js +614 -59
  31. package/dist/vitest.js.map +1 -1
  32. package/js/src/cli-args.ts +16 -0
  33. package/js/src/cli.ts +1 -1
  34. package/js/src/index.ts +5 -0
  35. package/js/src/protocol/event-table.ts +93 -2
  36. package/js/src/report/json.ts +14 -3
  37. package/js/src/report/sarif.ts +3 -6
  38. package/js/src/rules/catalog.ts +4 -0
  39. package/js/src/rules/checks/context.ts +48 -3
  40. package/js/src/rules/checks/lifecycle.ts +5 -2
  41. package/js/src/rules/checks/subagents.ts +78 -0
  42. package/js/src/rules/checks/text.ts +11 -3
  43. package/js/src/rules/checks/toolcalls.ts +8 -2
  44. package/package.json +2 -2
  45. package/spec/catalog.json +108 -1
  46. package/spec/event-categories.json +6 -2
  47. package/spec/fixtures/invalid/AGUI501-missing-data-prefix/scenario.json +3 -3
  48. package/spec/fixtures/invalid/AGUI502-payload-not-json/stream.jsonl +2 -2
  49. package/spec/fixtures/invalid/AGUI503-unknown-event-type/expected.json +1 -1
  50. package/spec/fixtures/invalid/AGUI503-unknown-event-type/stream.jsonl +3 -3
  51. package/spec/fixtures/invalid/AGUI504-schema-violation/stream.jsonl +4 -4
  52. package/spec/fixtures/invalid/AGUI505-unexpected-content-type/scenario.json +5 -5
  53. package/spec/fixtures/invalid/AGUI506-keepalive-gap/scenario.json +5 -5
  54. package/spec/fixtures/invalid/AGUI507-buffered-response/scenario.json +1 -1
  55. package/spec/fixtures/invalid/AGUI508-connection-dropped/scenario.json +1 -1
  56. package/spec/fixtures/invalid/AGUI601-duplicate-subagent-started/expected.json +12 -0
  57. package/spec/fixtures/invalid/AGUI601-duplicate-subagent-started/stream.jsonl +5 -0
  58. package/spec/fixtures/invalid/AGUI602-finished-without-start/expected.json +11 -0
  59. package/spec/fixtures/invalid/AGUI602-finished-without-start/stream.jsonl +3 -0
  60. package/spec/fixtures/invalid/AGUI603-error-without-start/expected.json +11 -0
  61. package/spec/fixtures/invalid/AGUI603-error-without-start/stream.jsonl +3 -0
  62. package/spec/fixtures/invalid/AGUI604-subagent-unterminated/expected.json +10 -0
  63. package/spec/fixtures/invalid/AGUI604-subagent-unterminated/stream.jsonl +3 -0
  64. package/spec/fixtures/invalid/AGUI605-unknown-parent-subagent-run-id/expected.json +11 -0
  65. package/spec/fixtures/invalid/AGUI605-unknown-parent-subagent-run-id/stream.jsonl +4 -0
  66. package/spec/fixtures/invalid/AGUI606-continuation-owner-mismatch/expected.json +11 -0
  67. package/spec/fixtures/invalid/AGUI606-continuation-owner-mismatch/stream.jsonl +6 -0
  68. package/spec/fixtures/invalid/AGUI901-raw-wraps-typed-event/stream.jsonl +3 -3
  69. package/spec/fixtures/invalid/AGUI903-custom-name-not-namespaced/stream.jsonl +3 -3
  70. package/dist/catalog-AB5vuZ8j.cjs.map +0 -1
  71. package/dist/catalog-DqTI4VLt.js.map +0 -1
  72. package/dist/src-D04i3Vso.cjs.map +0 -1
  73. package/dist/src-Dcuqz2QC.js.map +0 -1
package/dist/vitest.js CHANGED
@@ -1,20 +1,26 @@
1
1
  import { expect } from "vitest";
2
2
  //#region src/cli-args.ts
3
- function decideExitCode(summary, maxWarnings) {
3
+ function decideExitCode(summary, maxWarnings, failOn = "error") {
4
+ if (failOn === "none") return 0;
4
5
  if (summary.errors > 0) return 1;
6
+ if (failOn === "warning" && summary.warnings > 0) return 1;
5
7
  if (maxWarnings !== void 0 && summary.warnings > maxWarnings) return 1;
6
8
  return 0;
7
9
  }
8
10
  //#endregion
9
11
  //#region src/protocol/event-table.ts
10
12
  /** Version of @ag-ui/core this table was derived from. */
11
- const SDK_VERSION = "0.0.58";
13
+ const SDK_VERSION = "0.0.59";
12
14
  /** Canonical wire event types and their schemas, derived from @ag-ui/core. */
13
15
  const EVENT_TABLE = {
14
16
  "TEXT_MESSAGE_START": {
15
17
  category: "text",
16
18
  specUrl: "https://docs.ag-ui.com/concepts/events#textmessagestart",
17
19
  fields: {
20
+ "metadata": {
21
+ kind: "object",
22
+ required: false
23
+ },
18
24
  "messageId": {
19
25
  kind: "string",
20
26
  required: true
@@ -32,6 +38,10 @@ const EVENT_TABLE = {
32
38
  "name": {
33
39
  kind: "string",
34
40
  required: false
41
+ },
42
+ "subagentRunId": {
43
+ kind: "string",
44
+ required: false
35
45
  }
36
46
  }
37
47
  },
@@ -39,6 +49,10 @@ const EVENT_TABLE = {
39
49
  category: "text",
40
50
  specUrl: "https://docs.ag-ui.com/concepts/events#textmessagecontent",
41
51
  fields: {
52
+ "metadata": {
53
+ kind: "object",
54
+ required: false
55
+ },
42
56
  "messageId": {
43
57
  kind: "string",
44
58
  required: true
@@ -46,21 +60,39 @@ const EVENT_TABLE = {
46
60
  "delta": {
47
61
  kind: "string",
48
62
  required: true
63
+ },
64
+ "subagentRunId": {
65
+ kind: "string",
66
+ required: false
49
67
  }
50
68
  }
51
69
  },
52
70
  "TEXT_MESSAGE_END": {
53
71
  category: "text",
54
72
  specUrl: "https://docs.ag-ui.com/concepts/events#textmessageend",
55
- fields: { "messageId": {
56
- kind: "string",
57
- required: true
58
- } }
73
+ fields: {
74
+ "metadata": {
75
+ kind: "object",
76
+ required: false
77
+ },
78
+ "messageId": {
79
+ kind: "string",
80
+ required: true
81
+ },
82
+ "subagentRunId": {
83
+ kind: "string",
84
+ required: false
85
+ }
86
+ }
59
87
  },
60
88
  "TEXT_MESSAGE_CHUNK": {
61
89
  category: "text",
62
90
  specUrl: "https://docs.ag-ui.com/concepts/events#textmessagechunk",
63
91
  fields: {
92
+ "metadata": {
93
+ kind: "object",
94
+ required: false
95
+ },
64
96
  "messageId": {
65
97
  kind: "string",
66
98
  required: false
@@ -82,6 +114,10 @@ const EVENT_TABLE = {
82
114
  "name": {
83
115
  kind: "string",
84
116
  required: false
117
+ },
118
+ "subagentRunId": {
119
+ kind: "string",
120
+ required: false
85
121
  }
86
122
  }
87
123
  },
@@ -89,6 +125,10 @@ const EVENT_TABLE = {
89
125
  category: "toolcall",
90
126
  specUrl: "https://docs.ag-ui.com/concepts/events#toolcallstart",
91
127
  fields: {
128
+ "metadata": {
129
+ kind: "object",
130
+ required: false
131
+ },
92
132
  "toolCallId": {
93
133
  kind: "string",
94
134
  required: true
@@ -100,6 +140,10 @@ const EVENT_TABLE = {
100
140
  "parentMessageId": {
101
141
  kind: "string",
102
142
  required: false
143
+ },
144
+ "subagentRunId": {
145
+ kind: "string",
146
+ required: false
103
147
  }
104
148
  }
105
149
  },
@@ -107,6 +151,10 @@ const EVENT_TABLE = {
107
151
  category: "toolcall",
108
152
  specUrl: "https://docs.ag-ui.com/concepts/events#toolcallargs",
109
153
  fields: {
154
+ "metadata": {
155
+ kind: "object",
156
+ required: false
157
+ },
110
158
  "toolCallId": {
111
159
  kind: "string",
112
160
  required: true
@@ -114,21 +162,39 @@ const EVENT_TABLE = {
114
162
  "delta": {
115
163
  kind: "string",
116
164
  required: true
165
+ },
166
+ "subagentRunId": {
167
+ kind: "string",
168
+ required: false
117
169
  }
118
170
  }
119
171
  },
120
172
  "TOOL_CALL_END": {
121
173
  category: "toolcall",
122
174
  specUrl: "https://docs.ag-ui.com/concepts/events#toolcallend",
123
- fields: { "toolCallId": {
124
- kind: "string",
125
- required: true
126
- } }
175
+ fields: {
176
+ "metadata": {
177
+ kind: "object",
178
+ required: false
179
+ },
180
+ "toolCallId": {
181
+ kind: "string",
182
+ required: true
183
+ },
184
+ "subagentRunId": {
185
+ kind: "string",
186
+ required: false
187
+ }
188
+ }
127
189
  },
128
190
  "TOOL_CALL_CHUNK": {
129
191
  category: "toolcall",
130
192
  specUrl: "https://docs.ag-ui.com/concepts/events#toolcallchunk",
131
193
  fields: {
194
+ "metadata": {
195
+ kind: "object",
196
+ required: false
197
+ },
132
198
  "toolCallId": {
133
199
  kind: "string",
134
200
  required: false
@@ -144,6 +210,10 @@ const EVENT_TABLE = {
144
210
  "delta": {
145
211
  kind: "string",
146
212
  required: false
213
+ },
214
+ "subagentRunId": {
215
+ kind: "string",
216
+ required: false
147
217
  }
148
218
  }
149
219
  },
@@ -151,6 +221,10 @@ const EVENT_TABLE = {
151
221
  category: "toolcall",
152
222
  specUrl: "https://docs.ag-ui.com/concepts/events#toolcallresult",
153
223
  fields: {
224
+ "metadata": {
225
+ kind: "object",
226
+ required: false
227
+ },
154
228
  "messageId": {
155
229
  kind: "string",
156
230
  required: true
@@ -167,6 +241,10 @@ const EVENT_TABLE = {
167
241
  kind: "string",
168
242
  required: false,
169
243
  enum: ["tool"]
244
+ },
245
+ "subagentRunId": {
246
+ kind: "string",
247
+ required: false
170
248
  }
171
249
  }
172
250
  },
@@ -174,66 +252,117 @@ const EVENT_TABLE = {
174
252
  category: "thinking",
175
253
  deprecated: "REASONING_START",
176
254
  specUrl: "https://docs.ag-ui.com/concepts/events#thinking-events-deprecated",
177
- fields: { "title": {
178
- kind: "string",
179
- required: false
180
- } }
255
+ fields: {
256
+ "metadata": {
257
+ kind: "object",
258
+ required: false
259
+ },
260
+ "title": {
261
+ kind: "string",
262
+ required: false
263
+ }
264
+ }
181
265
  },
182
266
  "THINKING_END": {
183
267
  category: "thinking",
184
268
  deprecated: "REASONING_END",
185
269
  specUrl: "https://docs.ag-ui.com/concepts/events#thinking-events-deprecated",
186
- fields: {}
270
+ fields: { "metadata": {
271
+ kind: "object",
272
+ required: false
273
+ } }
187
274
  },
188
275
  "THINKING_TEXT_MESSAGE_START": {
189
276
  category: "thinking",
190
277
  deprecated: "REASONING_MESSAGE_START",
191
278
  specUrl: "https://docs.ag-ui.com/concepts/events#thinking-events-deprecated",
192
- fields: {}
279
+ fields: { "metadata": {
280
+ kind: "object",
281
+ required: false
282
+ } }
193
283
  },
194
284
  "THINKING_TEXT_MESSAGE_CONTENT": {
195
285
  category: "thinking",
196
286
  deprecated: "REASONING_MESSAGE_CONTENT",
197
287
  specUrl: "https://docs.ag-ui.com/concepts/events#thinking-events-deprecated",
198
- fields: { "delta": {
199
- kind: "string",
200
- required: true
201
- } }
288
+ fields: {
289
+ "metadata": {
290
+ kind: "object",
291
+ required: false
292
+ },
293
+ "delta": {
294
+ kind: "string",
295
+ required: true
296
+ }
297
+ }
202
298
  },
203
299
  "THINKING_TEXT_MESSAGE_END": {
204
300
  category: "thinking",
205
301
  deprecated: "REASONING_MESSAGE_END",
206
302
  specUrl: "https://docs.ag-ui.com/concepts/events#thinking-events-deprecated",
207
- fields: {}
303
+ fields: { "metadata": {
304
+ kind: "object",
305
+ required: false
306
+ } }
208
307
  },
209
308
  "STATE_SNAPSHOT": {
210
309
  category: "state",
211
310
  specUrl: "https://docs.ag-ui.com/concepts/events#statesnapshot",
212
- fields: { "snapshot": {
213
- kind: "any",
214
- required: true
215
- } }
311
+ fields: {
312
+ "metadata": {
313
+ kind: "object",
314
+ required: false
315
+ },
316
+ "snapshot": {
317
+ kind: "any",
318
+ required: true
319
+ },
320
+ "subagentRunId": {
321
+ kind: "string",
322
+ required: false
323
+ }
324
+ }
216
325
  },
217
326
  "STATE_DELTA": {
218
327
  category: "state",
219
328
  specUrl: "https://docs.ag-ui.com/concepts/events#statedelta",
220
- fields: { "delta": {
221
- kind: "array",
222
- required: true
223
- } }
329
+ fields: {
330
+ "metadata": {
331
+ kind: "object",
332
+ required: false
333
+ },
334
+ "delta": {
335
+ kind: "array",
336
+ required: true
337
+ },
338
+ "subagentRunId": {
339
+ kind: "string",
340
+ required: false
341
+ }
342
+ }
224
343
  },
225
344
  "MESSAGES_SNAPSHOT": {
226
345
  category: "state",
227
346
  specUrl: "https://docs.ag-ui.com/concepts/events#messagessnapshot",
228
- fields: { "messages": {
229
- kind: "array",
230
- required: true
231
- } }
347
+ fields: {
348
+ "metadata": {
349
+ kind: "object",
350
+ required: false
351
+ },
352
+ "messages": {
353
+ kind: "array",
354
+ required: true
355
+ }
356
+ }
232
357
  },
233
358
  "ACTIVITY_SNAPSHOT": {
234
359
  category: "activity",
235
360
  specUrl: "https://docs.ag-ui.com/concepts/events#activitysnapshot",
236
361
  fields: {
362
+ "metadata": {
363
+ kind: "object",
364
+ required: false
365
+ },
237
366
  "messageId": {
238
367
  kind: "string",
239
368
  required: true
@@ -249,6 +378,10 @@ const EVENT_TABLE = {
249
378
  "replace": {
250
379
  kind: "boolean",
251
380
  required: false
381
+ },
382
+ "subagentRunId": {
383
+ kind: "string",
384
+ required: false
252
385
  }
253
386
  }
254
387
  },
@@ -256,6 +389,10 @@ const EVENT_TABLE = {
256
389
  category: "activity",
257
390
  specUrl: "https://docs.ag-ui.com/concepts/events#activitydelta",
258
391
  fields: {
392
+ "metadata": {
393
+ kind: "object",
394
+ required: false
395
+ },
259
396
  "messageId": {
260
397
  kind: "string",
261
398
  required: true
@@ -267,6 +404,10 @@ const EVENT_TABLE = {
267
404
  "patch": {
268
405
  kind: "array",
269
406
  required: true
407
+ },
408
+ "subagentRunId": {
409
+ kind: "string",
410
+ required: false
270
411
  }
271
412
  }
272
413
  },
@@ -274,6 +415,10 @@ const EVENT_TABLE = {
274
415
  category: "special",
275
416
  specUrl: "https://docs.ag-ui.com/concepts/events#raw",
276
417
  fields: {
418
+ "metadata": {
419
+ kind: "object",
420
+ required: false
421
+ },
277
422
  "event": {
278
423
  kind: "any",
279
424
  required: true
@@ -281,6 +426,10 @@ const EVENT_TABLE = {
281
426
  "source": {
282
427
  kind: "string",
283
428
  required: false
429
+ },
430
+ "subagentRunId": {
431
+ kind: "string",
432
+ required: false
284
433
  }
285
434
  }
286
435
  },
@@ -288,6 +437,10 @@ const EVENT_TABLE = {
288
437
  category: "special",
289
438
  specUrl: "https://docs.ag-ui.com/concepts/events#custom",
290
439
  fields: {
440
+ "metadata": {
441
+ kind: "object",
442
+ required: false
443
+ },
291
444
  "name": {
292
445
  kind: "string",
293
446
  required: true
@@ -295,6 +448,10 @@ const EVENT_TABLE = {
295
448
  "value": {
296
449
  kind: "any",
297
450
  required: true
451
+ },
452
+ "subagentRunId": {
453
+ kind: "string",
454
+ required: false
298
455
  }
299
456
  }
300
457
  },
@@ -302,6 +459,10 @@ const EVENT_TABLE = {
302
459
  category: "lifecycle",
303
460
  specUrl: "https://docs.ag-ui.com/concepts/events#runstarted",
304
461
  fields: {
462
+ "metadata": {
463
+ kind: "object",
464
+ required: false
465
+ },
305
466
  "threadId": {
306
467
  kind: "string",
307
468
  required: true
@@ -324,6 +485,10 @@ const EVENT_TABLE = {
324
485
  category: "lifecycle",
325
486
  specUrl: "https://docs.ag-ui.com/concepts/events#runfinished",
326
487
  fields: {
488
+ "metadata": {
489
+ kind: "object",
490
+ required: false
491
+ },
327
492
  "threadId": {
328
493
  kind: "string",
329
494
  required: true
@@ -350,6 +515,10 @@ const EVENT_TABLE = {
350
515
  category: "lifecycle",
351
516
  specUrl: "https://docs.ag-ui.com/concepts/events#runerror",
352
517
  fields: {
518
+ "metadata": {
519
+ kind: "object",
520
+ required: false
521
+ },
353
522
  "message": {
354
523
  kind: "string",
355
524
  required: true
@@ -367,31 +536,65 @@ const EVENT_TABLE = {
367
536
  "STEP_STARTED": {
368
537
  category: "lifecycle",
369
538
  specUrl: "https://docs.ag-ui.com/concepts/events#stepstarted",
370
- fields: { "stepName": {
371
- kind: "string",
372
- required: true
373
- } }
539
+ fields: {
540
+ "metadata": {
541
+ kind: "object",
542
+ required: false
543
+ },
544
+ "stepName": {
545
+ kind: "string",
546
+ required: true
547
+ },
548
+ "subagentRunId": {
549
+ kind: "string",
550
+ required: false
551
+ }
552
+ }
374
553
  },
375
554
  "STEP_FINISHED": {
376
555
  category: "lifecycle",
377
556
  specUrl: "https://docs.ag-ui.com/concepts/events#stepfinished",
378
- fields: { "stepName": {
379
- kind: "string",
380
- required: true
381
- } }
557
+ fields: {
558
+ "metadata": {
559
+ kind: "object",
560
+ required: false
561
+ },
562
+ "stepName": {
563
+ kind: "string",
564
+ required: true
565
+ },
566
+ "subagentRunId": {
567
+ kind: "string",
568
+ required: false
569
+ }
570
+ }
382
571
  },
383
572
  "REASONING_START": {
384
573
  category: "reasoning",
385
574
  specUrl: "https://docs.ag-ui.com/concepts/events#reasoningstart",
386
- fields: { "messageId": {
387
- kind: "string",
388
- required: true
389
- } }
575
+ fields: {
576
+ "metadata": {
577
+ kind: "object",
578
+ required: false
579
+ },
580
+ "messageId": {
581
+ kind: "string",
582
+ required: true
583
+ },
584
+ "subagentRunId": {
585
+ kind: "string",
586
+ required: false
587
+ }
588
+ }
390
589
  },
391
590
  "REASONING_MESSAGE_START": {
392
591
  category: "reasoning",
393
592
  specUrl: "https://docs.ag-ui.com/concepts/events#reasoningmessagestart",
394
593
  fields: {
594
+ "metadata": {
595
+ kind: "object",
596
+ required: false
597
+ },
395
598
  "messageId": {
396
599
  kind: "string",
397
600
  required: true
@@ -400,6 +603,10 @@ const EVENT_TABLE = {
400
603
  kind: "string",
401
604
  required: true,
402
605
  enum: ["reasoning"]
606
+ },
607
+ "subagentRunId": {
608
+ kind: "string",
609
+ required: false
403
610
  }
404
611
  }
405
612
  },
@@ -407,6 +614,10 @@ const EVENT_TABLE = {
407
614
  category: "reasoning",
408
615
  specUrl: "https://docs.ag-ui.com/concepts/events#reasoningmessagecontent",
409
616
  fields: {
617
+ "metadata": {
618
+ kind: "object",
619
+ required: false
620
+ },
410
621
  "messageId": {
411
622
  kind: "string",
412
623
  required: true
@@ -414,21 +625,39 @@ const EVENT_TABLE = {
414
625
  "delta": {
415
626
  kind: "string",
416
627
  required: true
628
+ },
629
+ "subagentRunId": {
630
+ kind: "string",
631
+ required: false
417
632
  }
418
633
  }
419
634
  },
420
635
  "REASONING_MESSAGE_END": {
421
636
  category: "reasoning",
422
637
  specUrl: "https://docs.ag-ui.com/concepts/events#reasoningmessageend",
423
- fields: { "messageId": {
424
- kind: "string",
425
- required: true
426
- } }
638
+ fields: {
639
+ "metadata": {
640
+ kind: "object",
641
+ required: false
642
+ },
643
+ "messageId": {
644
+ kind: "string",
645
+ required: true
646
+ },
647
+ "subagentRunId": {
648
+ kind: "string",
649
+ required: false
650
+ }
651
+ }
427
652
  },
428
653
  "REASONING_MESSAGE_CHUNK": {
429
654
  category: "reasoning",
430
655
  specUrl: "https://docs.ag-ui.com/concepts/events#reasoningmessagechunk",
431
656
  fields: {
657
+ "metadata": {
658
+ kind: "object",
659
+ required: false
660
+ },
432
661
  "messageId": {
433
662
  kind: "string",
434
663
  required: false
@@ -436,21 +665,39 @@ const EVENT_TABLE = {
436
665
  "delta": {
437
666
  kind: "string",
438
667
  required: false
668
+ },
669
+ "subagentRunId": {
670
+ kind: "string",
671
+ required: false
439
672
  }
440
673
  }
441
674
  },
442
675
  "REASONING_END": {
443
676
  category: "reasoning",
444
677
  specUrl: "https://docs.ag-ui.com/concepts/events#reasoningend",
445
- fields: { "messageId": {
446
- kind: "string",
447
- required: true
448
- } }
678
+ fields: {
679
+ "metadata": {
680
+ kind: "object",
681
+ required: false
682
+ },
683
+ "messageId": {
684
+ kind: "string",
685
+ required: true
686
+ },
687
+ "subagentRunId": {
688
+ kind: "string",
689
+ required: false
690
+ }
691
+ }
449
692
  },
450
693
  "REASONING_ENCRYPTED_VALUE": {
451
694
  category: "reasoning",
452
695
  specUrl: "https://docs.ag-ui.com/concepts/events#reasoningencryptedvalue",
453
696
  fields: {
697
+ "metadata": {
698
+ kind: "object",
699
+ required: false
700
+ },
454
701
  "subtype": {
455
702
  kind: "string",
456
703
  required: true,
@@ -463,6 +710,88 @@ const EVENT_TABLE = {
463
710
  "encryptedValue": {
464
711
  kind: "string",
465
712
  required: true
713
+ },
714
+ "subagentRunId": {
715
+ kind: "string",
716
+ required: false
717
+ }
718
+ }
719
+ },
720
+ "SUBAGENT_STARTED": {
721
+ category: "subagent",
722
+ specUrl: "https://docs.ag-ui.com/concepts/events#subagent-events",
723
+ fields: {
724
+ "metadata": {
725
+ kind: "object",
726
+ required: false
727
+ },
728
+ "subagentRunId": {
729
+ kind: "string",
730
+ required: true
731
+ },
732
+ "name": {
733
+ kind: "string",
734
+ required: true
735
+ },
736
+ "description": {
737
+ kind: "string",
738
+ required: false
739
+ },
740
+ "parentSubagentRunId": {
741
+ kind: "string",
742
+ required: false
743
+ },
744
+ "parentToolCallId": {
745
+ kind: "string",
746
+ required: false
747
+ },
748
+ "parentMessageId": {
749
+ kind: "string",
750
+ required: false
751
+ }
752
+ }
753
+ },
754
+ "SUBAGENT_FINISHED": {
755
+ category: "subagent",
756
+ specUrl: "https://docs.ag-ui.com/concepts/events#subagent-events",
757
+ fields: {
758
+ "metadata": {
759
+ kind: "object",
760
+ required: false
761
+ },
762
+ "subagentRunId": {
763
+ kind: "string",
764
+ required: true
765
+ },
766
+ "result": {
767
+ kind: "any",
768
+ required: false
769
+ },
770
+ "outcome": {
771
+ kind: "object",
772
+ required: false
773
+ }
774
+ }
775
+ },
776
+ "SUBAGENT_ERROR": {
777
+ category: "subagent",
778
+ specUrl: "https://docs.ag-ui.com/concepts/events#subagent-events",
779
+ fields: {
780
+ "metadata": {
781
+ kind: "object",
782
+ required: false
783
+ },
784
+ "subagentRunId": {
785
+ kind: "string",
786
+ required: true
787
+ },
788
+ "message": {
789
+ kind: "string",
790
+ required: true
791
+ },
792
+ "code": {
793
+ kind: "string",
794
+ required: false
466
795
  }
467
796
  }
468
797
  }
@@ -478,13 +807,14 @@ const DRAFT_EVENT_TYPES = ["META"];
478
807
  //#region ../spec/catalog.json
479
808
  var catalog_default = {
480
809
  $comment: "AG-UI conformance rule catalog. Data, not code: a Python/Go implementation shares these rules. Severities follow the working agreement that behaviour the spec does not clearly govern is at most 'info' — entries with 'specQuestion' were downgraded accordingly; see docs/spec-questions.md.",
481
- catalogVersion: "0.1.0",
810
+ catalogVersion: "0.4.0",
482
811
  spec: "0.x",
483
812
  rules: [
484
813
  {
485
814
  "id": "AGUI001",
486
815
  "severity": "error",
487
816
  "title": "Run does not start with RUN_STARTED",
817
+ "category": "lifecycle",
488
818
  "messageTemplate": "First event of the run is {type}; expected RUN_STARTED",
489
819
  "specUrl": "https://docs.ag-ui.com/concepts/events#runstarted",
490
820
  "specQuote": "The RunStarted event is the first event emitted when an agent begins processing a request.",
@@ -495,6 +825,7 @@ var catalog_default = {
495
825
  "id": "AGUI002",
496
826
  "severity": "error",
497
827
  "title": "Multiple RUN_STARTED in one run",
828
+ "category": "lifecycle",
498
829
  "messageTemplate": "Duplicate RUN_STARTED (runId '{runId}') before the active run terminated",
499
830
  "specUrl": "https://docs.ag-ui.com/concepts/events#lifecycle-events",
500
831
  "specQuote": "The RunStarted and either RunFinished or RunError events are mandatory, forming the boundaries of an agent run.",
@@ -505,6 +836,7 @@ var catalog_default = {
505
836
  "id": "AGUI003",
506
837
  "severity": "error",
507
838
  "title": "Run not terminated",
839
+ "category": "lifecycle",
508
840
  "messageTemplate": "Run '{runId}' ended without RUN_FINISHED or RUN_ERROR",
509
841
  "specUrl": "https://docs.ag-ui.com/concepts/events#runfinished",
510
842
  "specQuote": "Every run terminates with either RunFinished or RunError.",
@@ -515,6 +847,7 @@ var catalog_default = {
515
847
  "id": "AGUI004",
516
848
  "severity": "error",
517
849
  "title": "Event after terminal event",
850
+ "category": "lifecycle",
518
851
  "messageTemplate": "{type} follows the run's terminal {terminalType}",
519
852
  "specUrl": "https://docs.ag-ui.com/concepts/events#lifecycle-events",
520
853
  "specQuote": "The RunStarted and either RunFinished or RunError events are mandatory, forming the boundaries of an agent run.",
@@ -525,6 +858,7 @@ var catalog_default = {
525
858
  "id": "AGUI005",
526
859
  "severity": "error",
527
860
  "title": "RUN_FINISHED and RUN_ERROR are mutually exclusive",
861
+ "category": "lifecycle",
528
862
  "messageTemplate": "{type} emitted after the run already terminated with {terminalType}",
529
863
  "specUrl": "https://docs.ag-ui.com/concepts/events#runfinished",
530
864
  "specQuote": "Every run terminates with either RunFinished or RunError.",
@@ -535,6 +869,7 @@ var catalog_default = {
535
869
  "id": "AGUI006",
536
870
  "severity": "error",
537
871
  "title": "STEP_FINISHED without matching STEP_STARTED",
872
+ "category": "lifecycle",
538
873
  "messageTemplate": "STEP_FINISHED '{stepName}' has no open STEP_STARTED",
539
874
  "specUrl": "https://docs.ag-ui.com/concepts/events#stepfinished",
540
875
  "specQuote": "The stepName must match the corresponding StepStarted event.",
@@ -545,6 +880,7 @@ var catalog_default = {
545
880
  "id": "AGUI007",
546
881
  "severity": "error",
547
882
  "title": "Step unterminated at run end",
883
+ "category": "lifecycle",
548
884
  "messageTemplate": "STEP_STARTED '{stepName}' never finished",
549
885
  "specUrl": "https://docs.ag-ui.com/concepts/events#stepstarted",
550
886
  "specQuote": "The stepName must match the corresponding StepStarted event.",
@@ -555,6 +891,7 @@ var catalog_default = {
555
891
  "id": "AGUI008",
556
892
  "severity": "warning",
557
893
  "title": "Unstable threadId/runId across the run",
894
+ "category": "lifecycle",
558
895
  "messageTemplate": "RUN_FINISHED {field} '{actual}' does not match RUN_STARTED {field} '{expected}'",
559
896
  "specUrl": "https://docs.ag-ui.com/concepts/events#runstarted",
560
897
  "specQuote": "It also provides crucial identifiers that can be used to associate subsequent events with this specific run.",
@@ -565,6 +902,7 @@ var catalog_default = {
565
902
  "id": "AGUI101",
566
903
  "severity": "error",
567
904
  "title": "TEXT_MESSAGE_CONTENT without start",
905
+ "category": "text",
568
906
  "messageTemplate": "TEXT_MESSAGE_CONTENT for messageId '{messageId}' with no open TEXT_MESSAGE_START",
569
907
  "specUrl": "https://docs.ag-ui.com/concepts/events#text-message-events",
570
908
  "specQuote": "A message begins with a TextMessageStart event, followed by one or more TextMessageContent events that deliver chunks of text as they become available, and concludes with a TextMessageEnd event.",
@@ -576,6 +914,7 @@ var catalog_default = {
576
914
  "id": "AGUI102",
577
915
  "severity": "error",
578
916
  "title": "TEXT_MESSAGE_END without start",
917
+ "category": "text",
579
918
  "messageTemplate": "TEXT_MESSAGE_END for messageId '{messageId}' with no open TEXT_MESSAGE_START",
580
919
  "specUrl": "https://docs.ag-ui.com/concepts/events#textmessageend",
581
920
  "specQuote": "messageId: Matches the ID from TextMessageStart",
@@ -587,6 +926,7 @@ var catalog_default = {
587
926
  "id": "AGUI103",
588
927
  "severity": "error",
589
928
  "title": "Text message unterminated at run end",
929
+ "category": "text",
590
930
  "messageTemplate": "TEXT_MESSAGE_START messageId '{messageId}' never ended",
591
931
  "specUrl": "https://docs.ag-ui.com/concepts/events#text-message-events",
592
932
  "specQuote": "A message begins with a TextMessageStart event, followed by one or more TextMessageContent events that deliver chunks of text as they become available, and concludes with a TextMessageEnd event.",
@@ -598,6 +938,7 @@ var catalog_default = {
598
938
  "id": "AGUI104",
599
939
  "severity": "error",
600
940
  "title": "Duplicate messageId within a run",
941
+ "category": "text",
601
942
  "messageTemplate": "messageId '{messageId}' was already used by a completed message",
602
943
  "specUrl": "https://docs.ag-ui.com/concepts/events#textmessagestart",
603
944
  "specQuote": "It establishes a unique messageId that will be referenced by subsequent content chunks and the end event.",
@@ -609,6 +950,7 @@ var catalog_default = {
609
950
  "id": "AGUI105",
610
951
  "severity": "warning",
611
952
  "title": "Empty content delta",
953
+ "category": "text",
612
954
  "messageTemplate": "TEXT_MESSAGE_CONTENT for messageId '{messageId}' has an empty delta",
613
955
  "specUrl": "https://docs.ag-ui.com/concepts/events#textmessagecontent",
614
956
  "specQuote": "delta: Text content chunk (non-empty)",
@@ -621,6 +963,7 @@ var catalog_default = {
621
963
  "id": "AGUI106",
622
964
  "severity": "error",
623
965
  "title": "Interleaved message streams sharing a messageId",
966
+ "category": "text",
624
967
  "messageTemplate": "TEXT_MESSAGE_START for messageId '{messageId}', which is already open",
625
968
  "specUrl": "https://docs.ag-ui.com/concepts/events#implementation-considerations",
626
969
  "specQuote": "Events with the same ID (e.g., messageId, toolCallId) belong to the same logical stream",
@@ -632,6 +975,7 @@ var catalog_default = {
632
975
  "id": "AGUI201",
633
976
  "severity": "error",
634
977
  "title": "TOOL_CALL_ARGS without start",
978
+ "category": "toolcall",
635
979
  "messageTemplate": "TOOL_CALL_ARGS for toolCallId '{toolCallId}' with no open TOOL_CALL_START",
636
980
  "specUrl": "https://docs.ag-ui.com/concepts/events#tool-call-events",
637
981
  "specQuote": "When an agent needs to use a tool, it emits a ToolCallStart event, followed by one or more ToolCallArgs events that stream the arguments being passed to the tool, and concludes with a ToolCallEnd event.",
@@ -643,6 +987,7 @@ var catalog_default = {
643
987
  "id": "AGUI202",
644
988
  "severity": "error",
645
989
  "title": "TOOL_CALL_END without start",
990
+ "category": "toolcall",
646
991
  "messageTemplate": "TOOL_CALL_END for toolCallId '{toolCallId}' with no open TOOL_CALL_START",
647
992
  "specUrl": "https://docs.ag-ui.com/concepts/events#toolcallend",
648
993
  "specQuote": "toolCallId: Matches the ID from ToolCallStart",
@@ -654,6 +999,7 @@ var catalog_default = {
654
999
  "id": "AGUI203",
655
1000
  "severity": "error",
656
1001
  "title": "Unterminated tool call",
1002
+ "category": "toolcall",
657
1003
  "messageTemplate": "TOOL_CALL_START id '{toolCallId}' never terminated",
658
1004
  "specUrl": "https://docs.ag-ui.com/concepts/events#tool-call-events",
659
1005
  "specQuote": "When an agent needs to use a tool, it emits a ToolCallStart event, followed by one or more ToolCallArgs events that stream the arguments being passed to the tool, and concludes with a ToolCallEnd event.",
@@ -665,6 +1011,7 @@ var catalog_default = {
665
1011
  "id": "AGUI204",
666
1012
  "severity": "error",
667
1013
  "title": "Tool call arguments are not valid JSON",
1014
+ "category": "toolcall",
668
1015
  "messageTemplate": "Concatenated TOOL_CALL_ARGS for toolCallId '{toolCallId}' do not parse as JSON: {error}",
669
1016
  "specUrl": "https://docs.ag-ui.com/concepts/events#toolcallargs",
670
1017
  "specQuote": "Frontends should concatenate these deltas in the order received to construct the complete arguments object.",
@@ -676,6 +1023,7 @@ var catalog_default = {
676
1023
  "id": "AGUI205",
677
1024
  "severity": "error",
678
1025
  "title": "Duplicate toolCallId within a run",
1026
+ "category": "toolcall",
679
1027
  "messageTemplate": "toolCallId '{toolCallId}' was already used by a completed tool call",
680
1028
  "specUrl": "https://docs.ag-ui.com/concepts/events#toolcallstart",
681
1029
  "specQuote": "toolCallId: Unique identifier for the tool call",
@@ -687,6 +1035,7 @@ var catalog_default = {
687
1035
  "id": "AGUI206",
688
1036
  "severity": "warning",
689
1037
  "title": "TOOL_CALL_RESULT before TOOL_CALL_END",
1038
+ "category": "toolcall",
690
1039
  "messageTemplate": "TOOL_CALL_RESULT for toolCallId '{toolCallId}' arrived while the call is still open",
691
1040
  "specUrl": "https://docs.ag-ui.com/concepts/events#toolcallresult",
692
1041
  "specQuote": "This event is sent after the tool has been executed by the system and contains the actual output generated by the tool.",
@@ -698,6 +1047,7 @@ var catalog_default = {
698
1047
  "id": "AGUI207",
699
1048
  "severity": "error",
700
1049
  "title": "TOOL_CALL_RESULT references unknown toolCallId",
1050
+ "category": "toolcall",
701
1051
  "messageTemplate": "TOOL_CALL_RESULT references toolCallId '{toolCallId}', which was never started",
702
1052
  "specUrl": "https://docs.ag-ui.com/concepts/events#toolcallresult",
703
1053
  "specQuote": "toolCallId: Matches the ID from the corresponding ToolCallStart event",
@@ -709,6 +1059,7 @@ var catalog_default = {
709
1059
  "id": "AGUI208",
710
1060
  "severity": "info",
711
1061
  "title": "parentMessageId references unknown message",
1062
+ "category": "toolcall",
712
1063
  "messageTemplate": "TOOL_CALL_START parentMessageId '{parentMessageId}' matches no message observed in this stream",
713
1064
  "specUrl": "https://docs.ag-ui.com/concepts/events#toolcallstart",
714
1065
  "specQuote": "The optional parentMessageId allows linking the tool call to a specific message in the conversation, providing context for why the tool is being used.",
@@ -721,6 +1072,7 @@ var catalog_default = {
721
1072
  "id": "AGUI301",
722
1073
  "severity": "info",
723
1074
  "title": "STATE_DELTA before any STATE_SNAPSHOT",
1075
+ "category": "state",
724
1076
  "messageTemplate": "STATE_DELTA precedes any STATE_SNAPSHOT; the base it applies to is not observable on this stream",
725
1077
  "specUrl": "https://docs.ag-ui.com/concepts/events#statesnapshot",
726
1078
  "specQuote": "This event is typically sent at the beginning of an interaction or when synchronization is needed.",
@@ -733,6 +1085,7 @@ var catalog_default = {
733
1085
  "id": "AGUI302",
734
1086
  "severity": "error",
735
1087
  "title": "STATE_DELTA failed to apply",
1088
+ "category": "state",
736
1089
  "messageTemplate": "STATE_DELTA failed to apply: {error}",
737
1090
  "specUrl": "https://docs.ag-ui.com/concepts/events#statedelta",
738
1091
  "specQuote": "Each delta represents specific changes to apply to the current state model.",
@@ -744,6 +1097,7 @@ var catalog_default = {
744
1097
  "id": "AGUI303",
745
1098
  "severity": "error",
746
1099
  "title": "STATE_DELTA is not a valid RFC 6902 patch document",
1100
+ "category": "state",
747
1101
  "messageTemplate": "STATE_DELTA is not a valid RFC 6902 patch document: {error}",
748
1102
  "specUrl": "https://docs.ag-ui.com/concepts/events#statedelta",
749
1103
  "specQuote": "The StateDelta event contains incremental updates to the agent's state in the form of JSON Patch operations (as defined in RFC 6902).",
@@ -755,6 +1109,7 @@ var catalog_default = {
755
1109
  "id": "AGUI304",
756
1110
  "severity": "info",
757
1111
  "title": "Mid-run STATE_SNAPSHOT discards accumulated deltas",
1112
+ "category": "state",
758
1113
  "messageTemplate": "STATE_SNAPSHOT replaces state previously built from {deltaCount} delta(s)",
759
1114
  "specUrl": "https://docs.ag-ui.com/concepts/events#statesnapshot",
760
1115
  "specQuote": "This event is typically sent at the beginning of an interaction or when synchronization is needed.",
@@ -766,6 +1121,7 @@ var catalog_default = {
766
1121
  "id": "AGUI305",
767
1122
  "severity": "warning",
768
1123
  "title": "Shared state declared but never established",
1124
+ "category": "state",
769
1125
  "messageTemplate": "features include 'shared-state' but no STATE_SNAPSHOT was emitted",
770
1126
  "specUrl": "https://docs.ag-ui.com/concepts/events#state-management-events",
771
1127
  "specQuote": "These events are used to manage and synchronize the agent's state with the frontend.",
@@ -778,6 +1134,7 @@ var catalog_default = {
778
1134
  "id": "AGUI401",
779
1135
  "severity": "error",
780
1136
  "title": "REASONING_MESSAGE_CONTENT without start",
1137
+ "category": "reasoning",
781
1138
  "messageTemplate": "REASONING_MESSAGE_CONTENT for messageId '{messageId}' with no open REASONING_MESSAGE_START",
782
1139
  "specUrl": "https://docs.ag-ui.com/concepts/events#reasoningmessagecontent",
783
1140
  "specQuote": "Multiple content events with the same messageId should be concatenated to form the complete visible reasoning.",
@@ -789,6 +1146,7 @@ var catalog_default = {
789
1146
  "id": "AGUI402",
790
1147
  "severity": "warning",
791
1148
  "title": "Reasoning unterminated at run end",
1149
+ "category": "reasoning",
792
1150
  "messageTemplate": "{startType} messageId '{messageId}' never ended",
793
1151
  "specUrl": "https://docs.ag-ui.com/concepts/events#reasoning-events",
794
1152
  "specQuote": "Reasoning events support LLM reasoning visibility and continuity, enabling chain-of-thought reasoning while maintaining privacy.",
@@ -800,6 +1158,7 @@ var catalog_default = {
800
1158
  "id": "AGUI501",
801
1159
  "severity": "error",
802
1160
  "title": "Malformed SSE framing",
1161
+ "category": "transport",
803
1162
  "messageTemplate": "Malformed SSE framing: {detail}",
804
1163
  "specUrl": "https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation",
805
1164
  "since": "0.x",
@@ -809,6 +1168,7 @@ var catalog_default = {
809
1168
  "id": "AGUI502",
810
1169
  "severity": "error",
811
1170
  "title": "Event payload is not valid JSON",
1171
+ "category": "transport",
812
1172
  "messageTemplate": "Event payload is not valid JSON: {error}",
813
1173
  "specUrl": "https://docs.ag-ui.com/concepts/events#base-event-properties",
814
1174
  "specQuote": "All events share a common set of base properties.",
@@ -819,6 +1179,7 @@ var catalog_default = {
819
1179
  "id": "AGUI503",
820
1180
  "severity": "error",
821
1181
  "title": "Unknown event type",
1182
+ "category": "transport",
822
1183
  "messageTemplate": "Unknown event type '{type}' (not in the installed AG-UI SDK v{sdkVersion}, and not RAW or CUSTOM)",
823
1184
  "specUrl": "https://docs.ag-ui.com/concepts/events#event-types-overview",
824
1185
  "specQuote": "Events in the protocol are categorized by their purpose.",
@@ -829,6 +1190,7 @@ var catalog_default = {
829
1190
  "id": "AGUI504",
830
1191
  "severity": "error",
831
1192
  "title": "Event fails schema validation for its declared type",
1193
+ "category": "transport",
832
1194
  "messageTemplate": "{type}: {detail}",
833
1195
  "specUrl": "https://docs.ag-ui.com/concepts/events#base-event-properties",
834
1196
  "specQuote": "All events share a common set of base properties.",
@@ -839,6 +1201,7 @@ var catalog_default = {
839
1201
  "id": "AGUI505",
840
1202
  "severity": "warning",
841
1203
  "title": "Unexpected Content-Type",
1204
+ "category": "transport",
842
1205
  "messageTemplate": "Content-Type '{contentType}' is neither text/event-stream nor application/x-ndjson",
843
1206
  "specUrl": "https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model",
844
1207
  "since": "0.x",
@@ -848,6 +1211,7 @@ var catalog_default = {
848
1211
  "id": "AGUI506",
849
1212
  "severity": "info",
850
1213
  "title": "No keepalive frame within the configured window",
1214
+ "category": "transport",
851
1215
  "messageTemplate": "No event or keepalive frame for {seconds}s",
852
1216
  "specUrl": "https://docs.ag-ui.com/concepts/architecture#standard-http-client",
853
1217
  "since": "0.x",
@@ -858,6 +1222,7 @@ var catalog_default = {
858
1222
  "id": "AGUI507",
859
1223
  "severity": "info",
860
1224
  "title": "Response appears buffered rather than incrementally flushed",
1225
+ "category": "transport",
861
1226
  "messageTemplate": "Response appears buffered: {detail}",
862
1227
  "specUrl": "https://docs.ag-ui.com/concepts/architecture#standard-http-client",
863
1228
  "since": "0.x",
@@ -868,16 +1233,85 @@ var catalog_default = {
868
1233
  "id": "AGUI508",
869
1234
  "severity": "error",
870
1235
  "title": "Stream ended without a terminal event",
1236
+ "category": "transport",
871
1237
  "messageTemplate": "Connection ended mid-run '{runId}' without RUN_FINISHED or RUN_ERROR",
872
1238
  "specUrl": "https://docs.ag-ui.com/concepts/events#runfinished",
873
1239
  "specQuote": "Every run terminates with either RunFinished or RunError.",
874
1240
  "since": "0.x",
875
1241
  "checkedIn": "transport"
876
1242
  },
1243
+ {
1244
+ "id": "AGUI601",
1245
+ "severity": "error",
1246
+ "title": "Duplicate SUBAGENT_STARTED for a subagentRunId",
1247
+ "category": "subagent",
1248
+ "messageTemplate": "SUBAGENT_STARTED reuses subagentRunId '{subagentRunId}', which is already in use this run",
1249
+ "specUrl": "https://docs.ag-ui.com/concepts/subagents#rules-clients-enforce",
1250
+ "specQuote": "a subagent is not started twice within a run",
1251
+ "since": "0.x",
1252
+ "checkedIn": "core"
1253
+ },
1254
+ {
1255
+ "id": "AGUI602",
1256
+ "severity": "error",
1257
+ "title": "SUBAGENT_FINISHED without matching SUBAGENT_STARTED",
1258
+ "category": "subagent",
1259
+ "messageTemplate": "SUBAGENT_FINISHED for subagentRunId '{subagentRunId}' with no open SUBAGENT_STARTED",
1260
+ "specUrl": "https://docs.ag-ui.com/concepts/subagents#rules-clients-enforce",
1261
+ "specQuote": "SubagentFinished and SubagentError name a subagent that is currently active",
1262
+ "since": "0.x",
1263
+ "checkedIn": "core"
1264
+ },
1265
+ {
1266
+ "id": "AGUI603",
1267
+ "severity": "error",
1268
+ "title": "SUBAGENT_ERROR without matching SUBAGENT_STARTED",
1269
+ "category": "subagent",
1270
+ "messageTemplate": "SUBAGENT_ERROR for subagentRunId '{subagentRunId}' with no open SUBAGENT_STARTED",
1271
+ "specUrl": "https://docs.ag-ui.com/concepts/subagents#rules-clients-enforce",
1272
+ "specQuote": "SubagentFinished and SubagentError name a subagent that is currently active",
1273
+ "since": "0.x",
1274
+ "checkedIn": "core"
1275
+ },
1276
+ {
1277
+ "id": "AGUI604",
1278
+ "severity": "error",
1279
+ "title": "Subagent unterminated at run end",
1280
+ "category": "subagent",
1281
+ "messageTemplate": "SUBAGENT_STARTED subagentRunId '{subagentRunId}' never closed with SUBAGENT_FINISHED or SUBAGENT_ERROR",
1282
+ "specUrl": "https://docs.ag-ui.com/concepts/subagents#rules-clients-enforce",
1283
+ "specQuote": "Every started subagent is closed before RunFinished.",
1284
+ "since": "0.x",
1285
+ "checkedIn": "core"
1286
+ },
1287
+ {
1288
+ "id": "AGUI605",
1289
+ "severity": "warning",
1290
+ "title": "parentSubagentRunId references a subagent never started",
1291
+ "category": "subagent",
1292
+ "messageTemplate": "SUBAGENT_STARTED parentSubagentRunId '{parentSubagentRunId}' matches no subagent observed in this stream",
1293
+ "specUrl": "https://docs.ag-ui.com/concepts/subagents#nesting-and-concurrency",
1294
+ "specQuote": "parentSubagentRunId need only name a subagent that has been started, not one still active",
1295
+ "since": "0.x",
1296
+ "checkedIn": "core"
1297
+ },
1298
+ {
1299
+ "id": "AGUI606",
1300
+ "severity": "warning",
1301
+ "title": "Continuation event's subagentRunId disagrees with its entity's owner",
1302
+ "category": "subagent",
1303
+ "messageTemplate": "{type} declares subagentRunId '{actual}', but {entityType} '{entityId}' was opened under {expected}",
1304
+ "specUrl": "https://docs.ag-ui.com/concepts/subagents#rules-clients-enforce",
1305
+ "specQuote": "Continuation and close events agree with the owner their entity was created under.",
1306
+ "since": "0.x",
1307
+ "specQuestion": "SQ-15",
1308
+ "checkedIn": "core"
1309
+ },
877
1310
  {
878
1311
  "id": "AGUI901",
879
1312
  "severity": "info",
880
1313
  "title": "RAW event wraps a typed AG-UI event",
1314
+ "category": "hygiene",
881
1315
  "messageTemplate": "RAW event wraps an event of type '{wrappedType}', which has a typed AG-UI equivalent",
882
1316
  "specUrl": "https://docs.ag-ui.com/concepts/events#raw",
883
1317
  "specQuote": "The Raw event acts as a container for events originating from external systems or sources that don't natively follow the Agent UI Protocol.",
@@ -888,6 +1322,7 @@ var catalog_default = {
888
1322
  "id": "AGUI902",
889
1323
  "severity": "info",
890
1324
  "title": "Events carry no timestamps",
1325
+ "category": "hygiene",
891
1326
  "messageTemplate": "None of the {eventCount} events carry the optional timestamp property",
892
1327
  "specUrl": "https://docs.ag-ui.com/concepts/events#base-event-properties",
893
1328
  "specQuote": "timestamp: Optional timestamp indicating when the event was created",
@@ -898,6 +1333,7 @@ var catalog_default = {
898
1333
  "id": "AGUI903",
899
1334
  "severity": "info",
900
1335
  "title": "CUSTOM event name is not namespaced",
1336
+ "category": "hygiene",
901
1337
  "messageTemplate": "CUSTOM event name '{name}' has no namespace prefix (e.g. 'vendor.event')",
902
1338
  "specUrl": "https://docs.ag-ui.com/concepts/events#custom",
903
1339
  "specQuote": "Teams should document their custom events to ensure consistent implementation across frontends and agents.",
@@ -915,6 +1351,16 @@ const SEVERITIES = [
915
1351
  "info"
916
1352
  ];
917
1353
  const LAYERS = ["core", "transport"];
1354
+ const CATEGORIES = [
1355
+ "lifecycle",
1356
+ "text",
1357
+ "toolcall",
1358
+ "state",
1359
+ "reasoning",
1360
+ "transport",
1361
+ "hygiene",
1362
+ "subagent"
1363
+ ];
918
1364
  /** Validates catalog data and returns it typed. Throws on structural problems. */
919
1365
  function validateCatalog(data) {
920
1366
  const problems = [];
@@ -928,6 +1374,7 @@ function validateCatalog(data) {
928
1374
  seen.add(rule.id);
929
1375
  if (!SEVERITIES.includes(rule.severity)) problems.push(`${where}: bad severity '${rule.severity}'`);
930
1376
  if (!rule.title) problems.push(`${where}: missing title`);
1377
+ if (!CATEGORIES.includes(rule.category)) problems.push(`${where}: bad category '${rule.category}'`);
931
1378
  if (!rule.messageTemplate) problems.push(`${where}: missing messageTemplate`);
932
1379
  if (!rule.specUrl?.startsWith("https://")) problems.push(`${where}: specUrl must be an https URL`);
933
1380
  if (!rule.since) problems.push(`${where}: missing since`);
@@ -952,10 +1399,14 @@ function newRunState(init) {
952
1399
  openMessages: /* @__PURE__ */ new Map(),
953
1400
  closedMessages: /* @__PURE__ */ new Map(),
954
1401
  knownMessageIds: /* @__PURE__ */ new Set(),
1402
+ messageOwner: /* @__PURE__ */ new Map(),
955
1403
  openToolCalls: /* @__PURE__ */ new Map(),
956
1404
  closedToolCalls: /* @__PURE__ */ new Map(),
957
1405
  knownToolCallIds: /* @__PURE__ */ new Set(),
958
1406
  openSteps: /* @__PURE__ */ new Map(),
1407
+ openSubagents: /* @__PURE__ */ new Map(),
1408
+ closedSubagents: /* @__PURE__ */ new Map(),
1409
+ knownSubagentRunIds: /* @__PURE__ */ new Set(),
959
1410
  openReasoningBlocks: /* @__PURE__ */ new Map(),
960
1411
  openReasoningMessages: /* @__PURE__ */ new Map(),
961
1412
  state: {
@@ -975,6 +1426,21 @@ function str(event, field) {
975
1426
  const v = event[field];
976
1427
  return typeof v === "string" ? v : void 0;
977
1428
  }
1429
+ /** AGUI606 — a continuation/close event's explicit subagentRunId must agree
1430
+ * with the owner recorded when its entity opened. Only compared when the
1431
+ * event explicitly tags itself; omitting the field is never flagged (SQ-15).
1432
+ * Shared by text/toolcalls/lifecycle — not the *_CHUNK forms or
1433
+ * TOOL_CALL_RESULT, which are independently attributed by spec. */
1434
+ function checkOwnerConsistency(emit, type, entityType, entityId, event, owner) {
1435
+ const actual = str(event, "subagentRunId");
1436
+ if (actual !== void 0 && actual !== owner) emit("AGUI606", {
1437
+ type,
1438
+ actual,
1439
+ entityType,
1440
+ entityId,
1441
+ expected: owner !== void 0 ? `'${owner}'` : "the run"
1442
+ }, { pointer: "/subagentRunId" });
1443
+ }
978
1444
  //#endregion
979
1445
  //#region src/rules/checks/lifecycle.ts
980
1446
  function handleStepEvent(api) {
@@ -986,7 +1452,8 @@ function handleStepEvent(api) {
986
1452
  if (open !== void 0) open.count += 1;
987
1453
  else run.openSteps.set(stepName, {
988
1454
  count: 1,
989
- firstIndex: index
1455
+ firstIndex: index,
1456
+ owner: str(event, "subagentRunId")
990
1457
  });
991
1458
  return;
992
1459
  }
@@ -996,6 +1463,7 @@ function handleStepEvent(api) {
996
1463
  emit("AGUI006", { stepName }, { pointer: "/stepName" });
997
1464
  return;
998
1465
  }
1466
+ checkOwnerConsistency(emit, type, "stepName", stepName, event, open.owner);
999
1467
  open.count -= 1;
1000
1468
  if (open.count === 0) run.openSteps.delete(stepName);
1001
1469
  }
@@ -1398,6 +1866,76 @@ function handleStateEvent(api) {
1398
1866
  }
1399
1867
  }
1400
1868
  //#endregion
1869
+ //#region src/rules/checks/subagents.ts
1870
+ function handleSubagentEvent(api) {
1871
+ const { type, event, run, emit, index } = api;
1872
+ switch (type) {
1873
+ case "SUBAGENT_STARTED": {
1874
+ const id = str(event, "subagentRunId");
1875
+ if (id === void 0) return;
1876
+ run.knownSubagentRunIds.add(id);
1877
+ const open = run.openSubagents.get(id);
1878
+ if (open !== void 0) {
1879
+ emit("AGUI601", { subagentRunId: id }, {
1880
+ pointer: "/subagentRunId",
1881
+ relatedEventIndex: open.startIndex
1882
+ });
1883
+ return;
1884
+ }
1885
+ const closed = run.closedSubagents.get(id);
1886
+ if (closed !== void 0 && !closed.resumable) {
1887
+ emit("AGUI601", { subagentRunId: id }, {
1888
+ pointer: "/subagentRunId",
1889
+ relatedEventIndex: closed.index
1890
+ });
1891
+ return;
1892
+ }
1893
+ run.openSubagents.set(id, { startIndex: index });
1894
+ if (closed !== void 0) run.closedSubagents.delete(id);
1895
+ const parent = str(event, "parentSubagentRunId");
1896
+ if (parent !== void 0 && !run.knownSubagentRunIds.has(parent)) emit("AGUI605", { parentSubagentRunId: parent }, { pointer: "/parentSubagentRunId" });
1897
+ return;
1898
+ }
1899
+ case "SUBAGENT_FINISHED": {
1900
+ const id = str(event, "subagentRunId");
1901
+ if (id === void 0) return;
1902
+ if (run.openSubagents.get(id) === void 0) {
1903
+ emit("AGUI602", { subagentRunId: id }, { pointer: "/subagentRunId" });
1904
+ return;
1905
+ }
1906
+ run.openSubagents.delete(id);
1907
+ const outcome = event.outcome;
1908
+ const resumable = typeof outcome === "object" && outcome !== null && outcome.type === "suspended";
1909
+ run.closedSubagents.set(id, {
1910
+ index,
1911
+ resumable
1912
+ });
1913
+ return;
1914
+ }
1915
+ case "SUBAGENT_ERROR": {
1916
+ const id = str(event, "subagentRunId");
1917
+ if (id === void 0) return;
1918
+ if (run.openSubagents.get(id) === void 0) {
1919
+ emit("AGUI603", { subagentRunId: id }, { pointer: "/subagentRunId" });
1920
+ return;
1921
+ }
1922
+ run.openSubagents.delete(id);
1923
+ run.closedSubagents.set(id, {
1924
+ index,
1925
+ resumable: false
1926
+ });
1927
+ return;
1928
+ }
1929
+ }
1930
+ }
1931
+ /** AGUI604 — open subagents when the run reaches a clean end. */
1932
+ function endOfRunSubagents(run, emit, atIndex) {
1933
+ for (const [id, open] of run.openSubagents) emit("AGUI604", { subagentRunId: id }, {
1934
+ eventIndex: atIndex,
1935
+ relatedEventIndex: open.startIndex
1936
+ });
1937
+ }
1938
+ //#endregion
1401
1939
  //#region src/rules/checks/text.ts
1402
1940
  function handleTextEvent(api) {
1403
1941
  const { type, event, run, emit, index } = api;
@@ -1420,8 +1958,13 @@ function handleTextEvent(api) {
1420
1958
  });
1421
1959
  return;
1422
1960
  }
1423
- run.openMessages.set(id, { startIndex: index });
1961
+ const owner = str(event, "subagentRunId");
1962
+ run.openMessages.set(id, {
1963
+ startIndex: index,
1964
+ owner
1965
+ });
1424
1966
  run.knownMessageIds.add(id);
1967
+ run.messageOwner.set(id, owner);
1425
1968
  return;
1426
1969
  }
1427
1970
  case "TEXT_MESSAGE_CONTENT": {
@@ -1440,15 +1983,18 @@ function handleTextEvent(api) {
1440
1983
  pointer: "/delta",
1441
1984
  relatedEventIndex: open.startIndex
1442
1985
  });
1986
+ checkOwnerConsistency(emit, type, "messageId", id, event, open.owner);
1443
1987
  return;
1444
1988
  }
1445
1989
  case "TEXT_MESSAGE_END": {
1446
1990
  const id = str(event, "messageId");
1447
1991
  if (id === void 0) return;
1448
- if (!run.openMessages.has(id)) {
1992
+ const open = run.openMessages.get(id);
1993
+ if (open === void 0) {
1449
1994
  emit("AGUI102", { messageId: id }, { pointer: "/messageId" });
1450
1995
  return;
1451
1996
  }
1997
+ checkOwnerConsistency(emit, type, "messageId", id, event, open.owner);
1452
1998
  run.openMessages.delete(id);
1453
1999
  run.closedMessages.set(id, index);
1454
2000
  return;
@@ -1477,6 +2023,7 @@ function handleTextEvent(api) {
1477
2023
  startIndex: index
1478
2024
  };
1479
2025
  run.knownMessageIds.add(id);
2026
+ run.messageOwner.set(id, str(event, "subagentRunId"));
1480
2027
  return;
1481
2028
  }
1482
2029
  }
@@ -1511,12 +2058,14 @@ function handleToolCallEvent(api) {
1511
2058
  });
1512
2059
  return;
1513
2060
  }
2061
+ const parent = str(event, "parentMessageId");
2062
+ const owner = str(event, "subagentRunId") ?? (parent !== void 0 ? run.messageOwner.get(parent) : void 0);
1514
2063
  run.openToolCalls.set(id, {
1515
2064
  startIndex: index,
1516
2065
  args: "",
1517
- sawArgs: false
2066
+ sawArgs: false,
2067
+ owner
1518
2068
  });
1519
- const parent = str(event, "parentMessageId");
1520
2069
  if (parent !== void 0 && !run.knownMessageIds.has(parent)) emit("AGUI208", { parentMessageId: parent }, { pointer: "/parentMessageId" });
1521
2070
  return;
1522
2071
  }
@@ -1533,6 +2082,7 @@ function handleToolCallEvent(api) {
1533
2082
  open.args += delta;
1534
2083
  open.sawArgs = true;
1535
2084
  }
2085
+ checkOwnerConsistency(emit, type, "toolCallId", id, event, open.owner);
1536
2086
  return;
1537
2087
  }
1538
2088
  case "TOOL_CALL_END": {
@@ -1543,6 +2093,7 @@ function handleToolCallEvent(api) {
1543
2093
  emit("AGUI202", { toolCallId: id }, { pointer: "/toolCallId" });
1544
2094
  return;
1545
2095
  }
2096
+ checkOwnerConsistency(emit, type, "toolCallId", id, event, open.owner);
1546
2097
  run.openToolCalls.delete(id);
1547
2098
  run.closedToolCalls.set(id, index);
1548
2099
  checkArgsJson(id, open, emit, index);
@@ -1765,6 +2316,7 @@ function createValidator(opts = {}) {
1765
2316
  endOfRunToolCalls(r, emit, atIndex);
1766
2317
  endOfRunSteps(r, emit, atIndex);
1767
2318
  endOfRunReasoning(r, emit, atIndex);
2319
+ endOfRunSubagents(r, emit, atIndex);
1768
2320
  }
1769
2321
  /** Opens the implicit run scope for streams that never announced one. */
1770
2322
  function ensureRun(index, type, emit) {
@@ -1915,6 +2467,9 @@ function createValidator(opts = {}) {
1915
2467
  break;
1916
2468
  case "thinking": break;
1917
2469
  case "activity": break;
2470
+ case "subagent":
2471
+ handleSubagentEvent(a);
2472
+ break;
1918
2473
  case "special": if (type === "RAW") {
1919
2474
  const wrapped = ev.event;
1920
2475
  if (typeof wrapped === "object" && wrapped !== null) {