@openwop/openwop-conformance 1.0.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 (175) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +241 -0
  3. package/api/asyncapi.yaml +481 -0
  4. package/api/openapi.yaml +830 -0
  5. package/api/redocly.yaml +8 -0
  6. package/coverage.md +80 -0
  7. package/dist/cli.js +161 -0
  8. package/fixtures/conformance-a2a-task-roundtrip.json +27 -0
  9. package/fixtures/conformance-agent-identity.json +27 -0
  10. package/fixtures/conformance-agent-low-confidence.json +29 -0
  11. package/fixtures/conformance-agent-memory-cross-tenant.json +28 -0
  12. package/fixtures/conformance-agent-memory-redaction.json +32 -0
  13. package/fixtures/conformance-agent-memory-roundtrip.json +32 -0
  14. package/fixtures/conformance-agent-memory-ttl.json +31 -0
  15. package/fixtures/conformance-agent-pack-export.json +26 -0
  16. package/fixtures/conformance-agent-pack-install.json +26 -0
  17. package/fixtures/conformance-agent-pack-provenance.json +31 -0
  18. package/fixtures/conformance-agent-reasoning.json +29 -0
  19. package/fixtures/conformance-approval.json +27 -0
  20. package/fixtures/conformance-cancellable.json +33 -0
  21. package/fixtures/conformance-cap-breach.json +27 -0
  22. package/fixtures/conformance-capability-missing.json +23 -0
  23. package/fixtures/conformance-channel-ttl.json +60 -0
  24. package/fixtures/conformance-clarification.json +30 -0
  25. package/fixtures/conformance-conversation-capability-negotiation.json +23 -0
  26. package/fixtures/conformance-conversation-lifecycle.json +32 -0
  27. package/fixtures/conformance-conversation-replay.json +33 -0
  28. package/fixtures/conformance-conversation-vs-clarification.json +26 -0
  29. package/fixtures/conformance-delay.json +33 -0
  30. package/fixtures/conformance-dispatch-loop.json +38 -0
  31. package/fixtures/conformance-failure.json +23 -0
  32. package/fixtures/conformance-idempotent.json +30 -0
  33. package/fixtures/conformance-identity.json +32 -0
  34. package/fixtures/conformance-interrupt-auth-required.json +28 -0
  35. package/fixtures/conformance-interrupt-external-event.json +33 -0
  36. package/fixtures/conformance-interrupt-parent-child-cancel-child.json +27 -0
  37. package/fixtures/conformance-interrupt-parent-child-cancel.json +26 -0
  38. package/fixtures/conformance-interrupt-quorum.json +30 -0
  39. package/fixtures/conformance-mcp-tool-roundtrip.json +32 -0
  40. package/fixtures/conformance-message-reducer.json +31 -0
  41. package/fixtures/conformance-multi-node.json +21 -0
  42. package/fixtures/conformance-noop.json +23 -0
  43. package/fixtures/conformance-orchestrator-dispatch.json +47 -0
  44. package/fixtures/conformance-orchestrator-low-confidence.json +41 -0
  45. package/fixtures/conformance-orchestrator-terminate.json +44 -0
  46. package/fixtures/conformance-stream-text.json +26 -0
  47. package/fixtures/conformance-subworkflow-child.json +21 -0
  48. package/fixtures/conformance-subworkflow-parent.json +49 -0
  49. package/fixtures/conformance-version-fold.json +23 -0
  50. package/fixtures/conformance-wasm-pack-roundtrip.json +25 -0
  51. package/fixtures/pack-manifests/pack-private-example.json +26 -0
  52. package/fixtures.md +404 -0
  53. package/package.json +48 -0
  54. package/schemas/README.md +75 -0
  55. package/schemas/agent-manifest.schema.json +107 -0
  56. package/schemas/agent-ref.schema.json +53 -0
  57. package/schemas/capabilities.schema.json +287 -0
  58. package/schemas/channel-written-payload.schema.json +55 -0
  59. package/schemas/conversation-event.schema.json +120 -0
  60. package/schemas/conversation-turn.schema.json +72 -0
  61. package/schemas/debug-bundle.schema.json +196 -0
  62. package/schemas/dispatch-config.schema.json +46 -0
  63. package/schemas/error-envelope.schema.json +25 -0
  64. package/schemas/memory-entry.schema.json +36 -0
  65. package/schemas/memory-list-options.schema.json +21 -0
  66. package/schemas/node-pack-manifest.schema.json +235 -0
  67. package/schemas/orchestrator-decision.schema.json +60 -0
  68. package/schemas/run-event-payloads.schema.json +663 -0
  69. package/schemas/run-event.schema.json +116 -0
  70. package/schemas/run-options.schema.json +81 -0
  71. package/schemas/run-orchestrator-decided-event.schema.json +20 -0
  72. package/schemas/run-snapshot.schema.json +121 -0
  73. package/schemas/suspend-request.schema.json +182 -0
  74. package/schemas/workflow-definition.schema.json +430 -0
  75. package/src/cli.ts +187 -0
  76. package/src/lib/a2a-fake-peer.ts +233 -0
  77. package/src/lib/canaries.ts +186 -0
  78. package/src/lib/driver.ts +96 -0
  79. package/src/lib/env.ts +49 -0
  80. package/src/lib/fixtures.ts +93 -0
  81. package/src/lib/mcp-fake-server.ts +185 -0
  82. package/src/lib/multi-agent-capabilities.ts +155 -0
  83. package/src/lib/multiProcess.ts +141 -0
  84. package/src/lib/otel-collector.ts +312 -0
  85. package/src/lib/paths.ts +198 -0
  86. package/src/lib/polling.ts +81 -0
  87. package/src/lib/profiles.ts +258 -0
  88. package/src/lib/sse.ts +172 -0
  89. package/src/scenarios/a2a-task-roundtrip.test.ts +149 -0
  90. package/src/scenarios/agentConfidenceEscalation.test.ts +61 -0
  91. package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +54 -0
  92. package/src/scenarios/agentMemoryRedactionContract.test.ts +46 -0
  93. package/src/scenarios/agentMemoryRoundTrip.test.ts +52 -0
  94. package/src/scenarios/agentMemoryTtlExpiry.test.ts +47 -0
  95. package/src/scenarios/agentMessageReducer.test.ts +57 -0
  96. package/src/scenarios/agentMetadata.test.ts +56 -0
  97. package/src/scenarios/agentPackExport.test.ts +45 -0
  98. package/src/scenarios/agentPackInstall.test.ts +50 -0
  99. package/src/scenarios/agentPackProvenance.test.ts +53 -0
  100. package/src/scenarios/agentReasoningEvents.test.ts +72 -0
  101. package/src/scenarios/append-ordering.test.ts +91 -0
  102. package/src/scenarios/approval-payload.test.ts +120 -0
  103. package/src/scenarios/audit-log-integrity.test.ts +106 -0
  104. package/src/scenarios/auth.test.ts +55 -0
  105. package/src/scenarios/byok-roundtrip.test.ts +166 -0
  106. package/src/scenarios/cancellation.test.ts +68 -0
  107. package/src/scenarios/cap-breach.test.ts +149 -0
  108. package/src/scenarios/channel-ttl.test.ts +70 -0
  109. package/src/scenarios/configurable-schema.test.ts +76 -0
  110. package/src/scenarios/conversationCapabilityNegotiation.test.ts +39 -0
  111. package/src/scenarios/conversationLifecycle.test.ts +64 -0
  112. package/src/scenarios/conversationReplayDeterminism.test.ts +52 -0
  113. package/src/scenarios/conversationVsLegacySuspend.test.ts +46 -0
  114. package/src/scenarios/cost-attribution.test.ts +207 -0
  115. package/src/scenarios/debugBundle.test.ts +222 -0
  116. package/src/scenarios/discovery.test.ts +147 -0
  117. package/src/scenarios/dispatchLoop.test.ts +52 -0
  118. package/src/scenarios/errors.test.ts +144 -0
  119. package/src/scenarios/eventOrdering.test.ts +144 -0
  120. package/src/scenarios/failure-path.test.ts +46 -0
  121. package/src/scenarios/fixtures-gating.test.ts +137 -0
  122. package/src/scenarios/fixtures-valid.test.ts +140 -0
  123. package/src/scenarios/highConcurrency.test.ts +263 -0
  124. package/src/scenarios/idempotency.test.ts +83 -0
  125. package/src/scenarios/idempotencyRetry.test.ts +130 -0
  126. package/src/scenarios/identity-passthrough.test.ts +54 -0
  127. package/src/scenarios/interrupt-approval.test.ts +97 -0
  128. package/src/scenarios/interrupt-auth-required-resume.test.ts +88 -0
  129. package/src/scenarios/interrupt-clarification.test.ts +45 -0
  130. package/src/scenarios/interrupt-external-event-correlation.test.ts +113 -0
  131. package/src/scenarios/interrupt-parent-child-cascade.test.ts +102 -0
  132. package/src/scenarios/interrupt-quorum-resolution.test.ts +97 -0
  133. package/src/scenarios/interruptRace.test.ts +176 -0
  134. package/src/scenarios/maliciousManifest.test.ts +154 -0
  135. package/src/scenarios/mcp-discoverability.test.ts +129 -0
  136. package/src/scenarios/mcp-tool-roundtrip.test.ts +149 -0
  137. package/src/scenarios/multi-node-ordering.test.ts +60 -0
  138. package/src/scenarios/multi-region-idempotency.test.ts +52 -0
  139. package/src/scenarios/orchestratorConservativePath.test.ts +63 -0
  140. package/src/scenarios/orchestratorDispatch.test.ts +66 -0
  141. package/src/scenarios/orchestratorTermination.test.ts +54 -0
  142. package/src/scenarios/otel-emission.test.ts +113 -0
  143. package/src/scenarios/otel-trace-propagation.test.ts +90 -0
  144. package/src/scenarios/pack-registry-publish.test.ts +93 -0
  145. package/src/scenarios/pack-registry.test.ts +328 -0
  146. package/src/scenarios/pause-resume.test.ts +109 -0
  147. package/src/scenarios/policies.test.ts +162 -0
  148. package/src/scenarios/profileDerivation.test.ts +335 -0
  149. package/src/scenarios/providerPolicyEnforcement.test.ts +132 -0
  150. package/src/scenarios/rate-limit-envelope.test.ts +97 -0
  151. package/src/scenarios/redaction.test.ts +254 -0
  152. package/src/scenarios/redactionAdversarial.test.ts +162 -0
  153. package/src/scenarios/replay-fork-arbitrary.test.ts +347 -0
  154. package/src/scenarios/replay-fork.test.ts +216 -0
  155. package/src/scenarios/replayDeterminism.test.ts +171 -0
  156. package/src/scenarios/route-coverage.test.ts +129 -0
  157. package/src/scenarios/runs-lifecycle.test.ts +65 -0
  158. package/src/scenarios/runtime-capabilities.test.ts +118 -0
  159. package/src/scenarios/spec-corpus-validity.test.ts +1257 -0
  160. package/src/scenarios/staleClaim.test.ts +223 -0
  161. package/src/scenarios/stream-modes-buffer.test.ts +148 -0
  162. package/src/scenarios/stream-modes-mixed.test.ts +149 -0
  163. package/src/scenarios/stream-modes.test.ts +139 -0
  164. package/src/scenarios/streamReconnect.test.ts +162 -0
  165. package/src/scenarios/subworkflow.test.ts +126 -0
  166. package/src/scenarios/version-negotiation.test.ts +157 -0
  167. package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +47 -0
  168. package/src/scenarios/wasm-pack-invoke-completed.test.ts +69 -0
  169. package/src/scenarios/wasm-pack-invoke-suspended.test.ts +74 -0
  170. package/src/scenarios/wasm-pack-load.test.ts +75 -0
  171. package/src/scenarios/wasm-pack-memory-cap.test.ts +43 -0
  172. package/src/scenarios/wasm-pack-replay-determinism.test.ts +61 -0
  173. package/src/scenarios/webhook-sig-algorithm.test.ts +61 -0
  174. package/src/setup.ts +173 -0
  175. package/vitest.config.ts +17 -0
@@ -0,0 +1,481 @@
1
+ asyncapi: 3.1.0
2
+
3
+ info:
4
+ title: Workflow Orchestration Protocol (openwop) SSE Event Stream
5
+ version: "1.0"
6
+ externalDocs:
7
+ description: openwop spec v1 corpus
8
+ url: https://openwop.dev/spec/v1/
9
+ description: |
10
+ Canonical AsyncAPI 3.0 specification for the openwop server's
11
+ Server-Sent Events surface. Formalizes `stream-modes.md`
12
+ and references the run-event JSON Schema via `$ref` so external SDK
13
+ authors can codegen typed consumers without re-reading the prose.
14
+
15
+ Four canonical stream modes are exposed via the `streamMode` query
16
+ parameter on a single endpoint (`GET /v1/runs/{runId}/events`):
17
+
18
+ - `updates` — minimal state-change deltas (default; lowest bandwidth)
19
+ - `values` — full `state.snapshot` after every transition
20
+ - `messages` — LLM token chunks for chat-style UIs
21
+ - `debug` — full event firehose including internal events
22
+
23
+ Each mode is modeled as a separate AsyncAPI channel because the
24
+ payload union differs per mode. The underlying transport (HTTPS SSE)
25
+ is shared; only the filter + synthesis layer differs.
26
+
27
+ See `stream-modes.md` for the complete event-to-mode mapping table.
28
+ contact:
29
+ name: openwop spec working group
30
+ url: https://openwop.dev/spec/v1/
31
+ license:
32
+ name: Apache-2.0
33
+
34
+ defaultContentType: text/event-stream
35
+
36
+ # ─────────────────────────────────────────────────────────────────────────────
37
+ # SERVERS
38
+ # ─────────────────────────────────────────────────────────────────────────────
39
+ servers:
40
+ production:
41
+ host: '{host}'
42
+ pathname: /v1
43
+ protocol: https
44
+ description: openwop-compliant server
45
+ variables:
46
+ host:
47
+ default: api.example.com
48
+ description: Replace with your server's hostname.
49
+ security:
50
+ - $ref: '#/components/securitySchemes/ApiKeyAuth'
51
+
52
+ # ─────────────────────────────────────────────────────────────────────────────
53
+ # CHANNELS — one per streamMode (filter contract differs)
54
+ # ─────────────────────────────────────────────────────────────────────────────
55
+ channels:
56
+
57
+ runEventsUpdates:
58
+ address: /runs/{runId}/events
59
+ title: SSE — updates mode (default)
60
+ summary: Minimal state-change deltas for UI/CLI consumers.
61
+ description: |
62
+ Default consumption mode. Emits an SSE event for each terminal
63
+ node transition, suspension transition, run transition, and
64
+ artifact production. Payloads are deltas (the change since the
65
+ last event), NOT full snapshots.
66
+
67
+ Termination: server closes the connection on a terminal run
68
+ event (`run.completed`, `run.failed`, `run.cancelled`).
69
+
70
+ Selected via `?streamMode=updates` (or by omitting the query
71
+ parameter — `updates` is the default per `stream-modes.md`).
72
+ parameters:
73
+ runId:
74
+ $ref: '#/components/parameters/RunId'
75
+ messages:
76
+ runStarted: { $ref: '#/components/messages/RunStarted' }
77
+ runCompleted: { $ref: '#/components/messages/RunCompleted' }
78
+ runFailed: { $ref: '#/components/messages/RunFailed' }
79
+ runCancelled: { $ref: '#/components/messages/RunCancelled' }
80
+ runPaused: { $ref: '#/components/messages/RunPaused' }
81
+ runResumed: { $ref: '#/components/messages/RunResumed' }
82
+ nodeCompleted: { $ref: '#/components/messages/NodeCompleted' }
83
+ nodeFailed: { $ref: '#/components/messages/NodeFailed' }
84
+ nodeSkipped: { $ref: '#/components/messages/NodeSkipped' }
85
+ nodeSuspended: { $ref: '#/components/messages/NodeSuspended' }
86
+ approvalRequested: { $ref: '#/components/messages/ApprovalRequested' }
87
+ approvalReceived: { $ref: '#/components/messages/ApprovalReceived' }
88
+ clarificationRequested: { $ref: '#/components/messages/ClarificationRequested' }
89
+ clarificationResolved: { $ref: '#/components/messages/ClarificationResolved' }
90
+ interruptRequested: { $ref: '#/components/messages/InterruptRequested' }
91
+ interruptResolved: { $ref: '#/components/messages/InterruptResolved' }
92
+ artifactCreated: { $ref: '#/components/messages/ArtifactCreated' }
93
+
94
+ runEventsValues:
95
+ address: /runs/{runId}/events
96
+ title: SSE — values mode
97
+ summary: Full state snapshots after every transition.
98
+ description: |
99
+ Higher-bandwidth mode for consumers that don't maintain their
100
+ own state machine. Emits a synthesized `state.snapshot` event
101
+ after each `updates`-tier transition. Payload is the complete
102
+ `ProjectedRunState` (status, nodeStates, variables,
103
+ currentNodeId, channels).
104
+
105
+ On resumption (`Last-Event-ID` header), the server MUST emit a
106
+ fresh `state.snapshot` first so the resuming client gets a
107
+ baseline before continuing with subsequent snapshots.
108
+
109
+ Selected via `?streamMode=values`.
110
+ parameters:
111
+ runId:
112
+ $ref: '#/components/parameters/RunId'
113
+ messages:
114
+ stateSnapshot: { $ref: '#/components/messages/StateSnapshot' }
115
+
116
+ runEventsMessages:
117
+ address: /runs/{runId}/events
118
+ title: SSE — messages mode
119
+ summary: LLM token chunks for chat-style UIs.
120
+ description: |
121
+ Per-token chunks from any AI node currently streaming
122
+ (`core.ai.callPrompt`, `core.ai.generateFromPrompt`, etc).
123
+ Other event types are filtered out — consumers wanting state
124
+ transitions should pair this with a separate `updates` stream.
125
+
126
+ If no AI nodes execute during the run, the stream is empty
127
+ until termination.
128
+
129
+ Selected via `?streamMode=messages`.
130
+ parameters:
131
+ runId:
132
+ $ref: '#/components/parameters/RunId'
133
+ messages:
134
+ aiMessageChunk: { $ref: '#/components/messages/AiMessageChunk' }
135
+
136
+ runEventsDebug:
137
+ address: /runs/{runId}/events
138
+ title: SSE — debug mode
139
+ summary: Full event firehose including internal events.
140
+ description: |
141
+ Every `RunEventDoc` from the durable event log, including
142
+ events filtered out of `updates`: `log.appended`,
143
+ `variable.changed`, `version.pinned`, `lease.*`,
144
+ `node.retried`, internal projection writes, and any
145
+ vendor-extension events.
146
+
147
+ Highest bandwidth. Used by replay tools, debuggers, and
148
+ conformance tests.
149
+
150
+ Selected via `?streamMode=debug`.
151
+ parameters:
152
+ runId:
153
+ $ref: '#/components/parameters/RunId'
154
+ messages:
155
+ anyRunEvent: { $ref: '#/components/messages/AnyRunEvent' }
156
+
157
+ # ─────────────────────────────────────────────────────────────────────────────
158
+ # OPERATIONS — consumer-side (receive)
159
+ # ─────────────────────────────────────────────────────────────────────────────
160
+ operations:
161
+
162
+ subscribeUpdates:
163
+ action: receive
164
+ channel:
165
+ $ref: '#/channels/runEventsUpdates'
166
+ title: Subscribe to updates stream
167
+ summary: Receive minimal state-change events for a run.
168
+ description: |
169
+ Long-lived SSE subscription. Connection auto-closes on
170
+ terminal run event. Honor the `Last-Event-ID` request header
171
+ for resumption — server begins streaming from the sequence
172
+ AFTER the supplied ID and MUST NOT re-emit the resumption
173
+ point itself.
174
+ bindings:
175
+ http:
176
+ method: GET
177
+ query:
178
+ type: object
179
+ properties:
180
+ streamMode:
181
+ type: string
182
+ enum: [updates]
183
+ default: updates
184
+
185
+ subscribeValues:
186
+ action: receive
187
+ channel:
188
+ $ref: '#/channels/runEventsValues'
189
+ title: Subscribe to values stream
190
+ summary: Receive full state snapshots after every transition.
191
+ bindings:
192
+ http:
193
+ method: GET
194
+ query:
195
+ type: object
196
+ required: [streamMode]
197
+ properties:
198
+ streamMode:
199
+ type: string
200
+ enum: [values]
201
+
202
+ subscribeMessages:
203
+ action: receive
204
+ channel:
205
+ $ref: '#/channels/runEventsMessages'
206
+ title: Subscribe to messages stream
207
+ summary: Receive per-token AI chunks.
208
+ bindings:
209
+ http:
210
+ method: GET
211
+ query:
212
+ type: object
213
+ required: [streamMode]
214
+ properties:
215
+ streamMode:
216
+ type: string
217
+ enum: [messages]
218
+
219
+ subscribeDebug:
220
+ action: receive
221
+ channel:
222
+ $ref: '#/channels/runEventsDebug'
223
+ title: Subscribe to debug stream
224
+ summary: Receive every engine event including internal/log/lease.
225
+ bindings:
226
+ http:
227
+ method: GET
228
+ query:
229
+ type: object
230
+ required: [streamMode]
231
+ properties:
232
+ streamMode:
233
+ type: string
234
+ enum: [debug]
235
+
236
+ # ─────────────────────────────────────────────────────────────────────────────
237
+ # COMPONENTS
238
+ # ─────────────────────────────────────────────────────────────────────────────
239
+ components:
240
+
241
+ securitySchemes:
242
+ ApiKeyAuth:
243
+ type: httpApiKey
244
+ in: header
245
+ name: Authorization
246
+ description: |
247
+ Bearer-style API key. Format implementation-defined; reference
248
+ impl uses `hk_`/`hk_test_` prefixes. Required scopes:
249
+ `runs:read` to subscribe. See `auth.md`.
250
+
251
+ parameters:
252
+ RunId:
253
+ description: The run to subscribe to. Format opaque; clients MUST treat as a string.
254
+
255
+ # ── Messages ─────────────────────────────────────────────────────────────
256
+ # All `updates`/`debug`-mode messages share the canonical RunEventDoc shape
257
+ # (run-event.schema.json). Each named message below pins the `type` field
258
+ # to a specific RunEventType discriminator so codegens can emit narrowed
259
+ # consumer handlers.
260
+
261
+ messages:
262
+
263
+ # ── Run-lifecycle ────────────────────────────────────────────────────
264
+ RunStarted:
265
+ name: run.started
266
+ title: Run started
267
+ summary: A new run was registered and execution began.
268
+ contentType: application/json
269
+ payload:
270
+ $ref: '#/components/schemas/RunEventDoc'
271
+
272
+ RunCompleted:
273
+ name: run.completed
274
+ title: Run completed (terminal)
275
+ summary: Run reached terminal success state. SSE connection closes after this event.
276
+ contentType: application/json
277
+ payload:
278
+ $ref: '#/components/schemas/RunEventDoc'
279
+
280
+ RunFailed:
281
+ name: run.failed
282
+ title: Run failed (terminal)
283
+ summary: Run reached terminal failure state. SSE connection closes after this event.
284
+ contentType: application/json
285
+ payload:
286
+ $ref: '#/components/schemas/RunEventDoc'
287
+
288
+ RunCancelled:
289
+ name: run.cancelled
290
+ title: Run cancelled (terminal)
291
+ summary: Run was cancelled by user or admin. SSE connection closes after this event.
292
+ contentType: application/json
293
+ payload:
294
+ $ref: '#/components/schemas/RunEventDoc'
295
+
296
+ RunPaused:
297
+ name: run.paused
298
+ title: Run paused
299
+ summary: Run paused (e.g., capability limit reached, manual pause).
300
+ contentType: application/json
301
+ payload:
302
+ $ref: '#/components/schemas/RunEventDoc'
303
+
304
+ RunResumed:
305
+ name: run.resumed
306
+ title: Run resumed
307
+ summary: Run resumed from pause/suspend.
308
+ contentType: application/json
309
+ payload:
310
+ $ref: '#/components/schemas/RunEventDoc'
311
+
312
+ # ── Node-lifecycle ───────────────────────────────────────────────────
313
+ NodeCompleted:
314
+ name: node.completed
315
+ title: Node completed successfully
316
+ contentType: application/json
317
+ payload:
318
+ $ref: '#/components/schemas/RunEventDoc'
319
+
320
+ NodeFailed:
321
+ name: node.failed
322
+ title: Node failed
323
+ contentType: application/json
324
+ payload:
325
+ $ref: '#/components/schemas/RunEventDoc'
326
+
327
+ NodeSkipped:
328
+ name: node.skipped
329
+ title: Node skipped due to edge condition
330
+ contentType: application/json
331
+ payload:
332
+ $ref: '#/components/schemas/RunEventDoc'
333
+
334
+ NodeSuspended:
335
+ name: node.suspended
336
+ title: Node suspended (HITL or external-event wait)
337
+ contentType: application/json
338
+ payload:
339
+ $ref: '#/components/schemas/RunEventDoc'
340
+
341
+ # ── HITL ─────────────────────────────────────────────────────────────
342
+ ApprovalRequested:
343
+ name: approval.requested
344
+ title: Approval requested
345
+ summary: Engine emitted an approval interrupt awaiting user resolution.
346
+ contentType: application/json
347
+ payload:
348
+ $ref: '#/components/schemas/RunEventDoc'
349
+
350
+ ApprovalReceived:
351
+ name: approval.received
352
+ title: Approval received
353
+ summary: User resolved an approval interrupt (accept/reject/refine/edit).
354
+ contentType: application/json
355
+ payload:
356
+ $ref: '#/components/schemas/RunEventDoc'
357
+
358
+ ClarificationRequested:
359
+ name: clarification.requested
360
+ title: Clarification requested
361
+ contentType: application/json
362
+ payload:
363
+ $ref: '#/components/schemas/RunEventDoc'
364
+
365
+ ClarificationResolved:
366
+ name: clarification.resolved
367
+ title: Clarification resolved
368
+ contentType: application/json
369
+ payload:
370
+ $ref: '#/components/schemas/RunEventDoc'
371
+
372
+ InterruptRequested:
373
+ name: interrupt.requested
374
+ title: Interrupt requested (canonical HITL primitive)
375
+ summary: |
376
+ The discriminated-union form of approval/clarification/external-event/custom.
377
+ Servers emitting `interrupt.requested` SHOULD also emit the legacy
378
+ kind-specific event (`approval.requested` etc) for backward compat
379
+ until consumers migrate.
380
+ contentType: application/json
381
+ payload:
382
+ $ref: '#/components/schemas/RunEventDoc'
383
+
384
+ InterruptResolved:
385
+ name: interrupt.resolved
386
+ title: Interrupt resolved
387
+ contentType: application/json
388
+ payload:
389
+ $ref: '#/components/schemas/RunEventDoc'
390
+
391
+ # ── Artifacts ────────────────────────────────────────────────────────
392
+ ArtifactCreated:
393
+ name: artifact.created
394
+ title: Artifact produced by a node
395
+ summary: A typed artifact (PRD, plan, theme, etc) was created and registered.
396
+ contentType: application/json
397
+ payload:
398
+ $ref: '#/components/schemas/RunEventDoc'
399
+
400
+ # ── Synthesized for `values` mode ────────────────────────────────────
401
+ StateSnapshot:
402
+ name: state.snapshot
403
+ title: Full projected run state
404
+ summary: |
405
+ Synthesized event emitted by the server in `values` mode after
406
+ each `updates`-tier transition. NOT a member of the canonical
407
+ `RunEventType` enum — this is a per-mode synthetic.
408
+ contentType: application/json
409
+ payload:
410
+ $ref: '#/components/schemas/StateSnapshotPayload'
411
+
412
+ # ── Synthesized for `messages` mode ──────────────────────────────────
413
+ AiMessageChunk:
414
+ name: ai.message.chunk
415
+ title: AI token chunk
416
+ summary: Per-token streaming chunk from a `core.ai.*` node.
417
+ contentType: application/json
418
+ payload:
419
+ $ref: '#/components/schemas/AiMessageChunkPayload'
420
+
421
+ # ── Catch-all for `debug` mode ───────────────────────────────────────
422
+ AnyRunEvent:
423
+ name: any
424
+ title: Any RunEventDoc
425
+ summary: |
426
+ Type-erased handler for `debug` mode — discriminate on the
427
+ `type` field per the `RunEventType` enum in the run-event
428
+ JSON Schema. Includes events filtered out of `updates`:
429
+ `log.appended`, `variable.changed`, `version.pinned`,
430
+ `lease.*`, `node.retried`, `replay.diverged`, etc.
431
+ contentType: application/json
432
+ payload:
433
+ $ref: '#/components/schemas/RunEventDoc'
434
+
435
+ # ── Schemas ────────────────────────────────────────────────────────────
436
+ schemas:
437
+
438
+ # The canonical persisted-event shape. Defined externally so the same
439
+ # contract is shared with REST event-poll responses (rest-endpoints.md
440
+ # `GET /v1/runs/{runId}/events/poll`) and offline replay tools.
441
+ RunEventDoc:
442
+ $ref: '../schemas/run-event.schema.json'
443
+
444
+ StateSnapshotPayload:
445
+ # S1 closure (2026-04-27): reuse the canonical RunSnapshot
446
+ # projection shape verbatim. Same type returned by
447
+ # `GET /v1/runs/{runId}` — consumers can swap polling for
448
+ # values-mode SSE without re-modeling state.
449
+ $ref: '../schemas/run-snapshot.schema.json'
450
+
451
+ AiMessageChunkPayload:
452
+ # S2 closure (2026-04-27): tiered metadata. Bare {nodeId, runId,
453
+ # chunk, isLast} is the minimum compliant payload; `meta`
454
+ # adds Tier 1 typed slots (finishReason / logprobs / toolCalls /
455
+ # model / usage) and a Tier 2 provider-pass-through escape hatch.
456
+ # Schema definition lives at run-event-payloads.schema.json#$defs.outputChunk
457
+ # — referenced here verbatim so the SSE consumer + run-event log
458
+ # share a single shape contract.
459
+ type: object
460
+ required: [nodeId, runId, chunk, isLast]
461
+ properties:
462
+ nodeId: { type: string }
463
+ runId: { type: string }
464
+ chunk:
465
+ type: string
466
+ description: The new token(s) since the previous chunk.
467
+ isLast:
468
+ type: boolean
469
+ description: True for the final chunk of a given AI node call.
470
+ meta:
471
+ type: object
472
+ description: |
473
+ Tiered metadata. Tier 1: typed slots — `finishReason`
474
+ ("stop"|"length"|"tool_calls"|"content_filter"), `logprobs`,
475
+ `toolCalls`, `model`, `usage` ({promptTokens,
476
+ completionTokens, totalTokens}). Tier 2: provider-pass-through
477
+ via `provider` + `providerExtensions`. Consumers SHOULD prefer
478
+ Tier 1; Tier 2 is the escape hatch for fields the spec hasn't
479
+ typed yet. See run-event-payloads.schema.json#$defs._chunkMeta
480
+ for the full definition + per-field constraints.
481
+ additionalProperties: true