@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.
- package/LICENSE +201 -0
- package/README.md +241 -0
- package/api/asyncapi.yaml +481 -0
- package/api/openapi.yaml +830 -0
- package/api/redocly.yaml +8 -0
- package/coverage.md +80 -0
- package/dist/cli.js +161 -0
- package/fixtures/conformance-a2a-task-roundtrip.json +27 -0
- package/fixtures/conformance-agent-identity.json +27 -0
- package/fixtures/conformance-agent-low-confidence.json +29 -0
- package/fixtures/conformance-agent-memory-cross-tenant.json +28 -0
- package/fixtures/conformance-agent-memory-redaction.json +32 -0
- package/fixtures/conformance-agent-memory-roundtrip.json +32 -0
- package/fixtures/conformance-agent-memory-ttl.json +31 -0
- package/fixtures/conformance-agent-pack-export.json +26 -0
- package/fixtures/conformance-agent-pack-install.json +26 -0
- package/fixtures/conformance-agent-pack-provenance.json +31 -0
- package/fixtures/conformance-agent-reasoning.json +29 -0
- package/fixtures/conformance-approval.json +27 -0
- package/fixtures/conformance-cancellable.json +33 -0
- package/fixtures/conformance-cap-breach.json +27 -0
- package/fixtures/conformance-capability-missing.json +23 -0
- package/fixtures/conformance-channel-ttl.json +60 -0
- package/fixtures/conformance-clarification.json +30 -0
- package/fixtures/conformance-conversation-capability-negotiation.json +23 -0
- package/fixtures/conformance-conversation-lifecycle.json +32 -0
- package/fixtures/conformance-conversation-replay.json +33 -0
- package/fixtures/conformance-conversation-vs-clarification.json +26 -0
- package/fixtures/conformance-delay.json +33 -0
- package/fixtures/conformance-dispatch-loop.json +38 -0
- package/fixtures/conformance-failure.json +23 -0
- package/fixtures/conformance-idempotent.json +30 -0
- package/fixtures/conformance-identity.json +32 -0
- package/fixtures/conformance-interrupt-auth-required.json +28 -0
- package/fixtures/conformance-interrupt-external-event.json +33 -0
- package/fixtures/conformance-interrupt-parent-child-cancel-child.json +27 -0
- package/fixtures/conformance-interrupt-parent-child-cancel.json +26 -0
- package/fixtures/conformance-interrupt-quorum.json +30 -0
- package/fixtures/conformance-mcp-tool-roundtrip.json +32 -0
- package/fixtures/conformance-message-reducer.json +31 -0
- package/fixtures/conformance-multi-node.json +21 -0
- package/fixtures/conformance-noop.json +23 -0
- package/fixtures/conformance-orchestrator-dispatch.json +47 -0
- package/fixtures/conformance-orchestrator-low-confidence.json +41 -0
- package/fixtures/conformance-orchestrator-terminate.json +44 -0
- package/fixtures/conformance-stream-text.json +26 -0
- package/fixtures/conformance-subworkflow-child.json +21 -0
- package/fixtures/conformance-subworkflow-parent.json +49 -0
- package/fixtures/conformance-version-fold.json +23 -0
- package/fixtures/conformance-wasm-pack-roundtrip.json +25 -0
- package/fixtures/pack-manifests/pack-private-example.json +26 -0
- package/fixtures.md +404 -0
- package/package.json +48 -0
- package/schemas/README.md +75 -0
- package/schemas/agent-manifest.schema.json +107 -0
- package/schemas/agent-ref.schema.json +53 -0
- package/schemas/capabilities.schema.json +287 -0
- package/schemas/channel-written-payload.schema.json +55 -0
- package/schemas/conversation-event.schema.json +120 -0
- package/schemas/conversation-turn.schema.json +72 -0
- package/schemas/debug-bundle.schema.json +196 -0
- package/schemas/dispatch-config.schema.json +46 -0
- package/schemas/error-envelope.schema.json +25 -0
- package/schemas/memory-entry.schema.json +36 -0
- package/schemas/memory-list-options.schema.json +21 -0
- package/schemas/node-pack-manifest.schema.json +235 -0
- package/schemas/orchestrator-decision.schema.json +60 -0
- package/schemas/run-event-payloads.schema.json +663 -0
- package/schemas/run-event.schema.json +116 -0
- package/schemas/run-options.schema.json +81 -0
- package/schemas/run-orchestrator-decided-event.schema.json +20 -0
- package/schemas/run-snapshot.schema.json +121 -0
- package/schemas/suspend-request.schema.json +182 -0
- package/schemas/workflow-definition.schema.json +430 -0
- package/src/cli.ts +187 -0
- package/src/lib/a2a-fake-peer.ts +233 -0
- package/src/lib/canaries.ts +186 -0
- package/src/lib/driver.ts +96 -0
- package/src/lib/env.ts +49 -0
- package/src/lib/fixtures.ts +93 -0
- package/src/lib/mcp-fake-server.ts +185 -0
- package/src/lib/multi-agent-capabilities.ts +155 -0
- package/src/lib/multiProcess.ts +141 -0
- package/src/lib/otel-collector.ts +312 -0
- package/src/lib/paths.ts +198 -0
- package/src/lib/polling.ts +81 -0
- package/src/lib/profiles.ts +258 -0
- package/src/lib/sse.ts +172 -0
- package/src/scenarios/a2a-task-roundtrip.test.ts +149 -0
- package/src/scenarios/agentConfidenceEscalation.test.ts +61 -0
- package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +54 -0
- package/src/scenarios/agentMemoryRedactionContract.test.ts +46 -0
- package/src/scenarios/agentMemoryRoundTrip.test.ts +52 -0
- package/src/scenarios/agentMemoryTtlExpiry.test.ts +47 -0
- package/src/scenarios/agentMessageReducer.test.ts +57 -0
- package/src/scenarios/agentMetadata.test.ts +56 -0
- package/src/scenarios/agentPackExport.test.ts +45 -0
- package/src/scenarios/agentPackInstall.test.ts +50 -0
- package/src/scenarios/agentPackProvenance.test.ts +53 -0
- package/src/scenarios/agentReasoningEvents.test.ts +72 -0
- package/src/scenarios/append-ordering.test.ts +91 -0
- package/src/scenarios/approval-payload.test.ts +120 -0
- package/src/scenarios/audit-log-integrity.test.ts +106 -0
- package/src/scenarios/auth.test.ts +55 -0
- package/src/scenarios/byok-roundtrip.test.ts +166 -0
- package/src/scenarios/cancellation.test.ts +68 -0
- package/src/scenarios/cap-breach.test.ts +149 -0
- package/src/scenarios/channel-ttl.test.ts +70 -0
- package/src/scenarios/configurable-schema.test.ts +76 -0
- package/src/scenarios/conversationCapabilityNegotiation.test.ts +39 -0
- package/src/scenarios/conversationLifecycle.test.ts +64 -0
- package/src/scenarios/conversationReplayDeterminism.test.ts +52 -0
- package/src/scenarios/conversationVsLegacySuspend.test.ts +46 -0
- package/src/scenarios/cost-attribution.test.ts +207 -0
- package/src/scenarios/debugBundle.test.ts +222 -0
- package/src/scenarios/discovery.test.ts +147 -0
- package/src/scenarios/dispatchLoop.test.ts +52 -0
- package/src/scenarios/errors.test.ts +144 -0
- package/src/scenarios/eventOrdering.test.ts +144 -0
- package/src/scenarios/failure-path.test.ts +46 -0
- package/src/scenarios/fixtures-gating.test.ts +137 -0
- package/src/scenarios/fixtures-valid.test.ts +140 -0
- package/src/scenarios/highConcurrency.test.ts +263 -0
- package/src/scenarios/idempotency.test.ts +83 -0
- package/src/scenarios/idempotencyRetry.test.ts +130 -0
- package/src/scenarios/identity-passthrough.test.ts +54 -0
- package/src/scenarios/interrupt-approval.test.ts +97 -0
- package/src/scenarios/interrupt-auth-required-resume.test.ts +88 -0
- package/src/scenarios/interrupt-clarification.test.ts +45 -0
- package/src/scenarios/interrupt-external-event-correlation.test.ts +113 -0
- package/src/scenarios/interrupt-parent-child-cascade.test.ts +102 -0
- package/src/scenarios/interrupt-quorum-resolution.test.ts +97 -0
- package/src/scenarios/interruptRace.test.ts +176 -0
- package/src/scenarios/maliciousManifest.test.ts +154 -0
- package/src/scenarios/mcp-discoverability.test.ts +129 -0
- package/src/scenarios/mcp-tool-roundtrip.test.ts +149 -0
- package/src/scenarios/multi-node-ordering.test.ts +60 -0
- package/src/scenarios/multi-region-idempotency.test.ts +52 -0
- package/src/scenarios/orchestratorConservativePath.test.ts +63 -0
- package/src/scenarios/orchestratorDispatch.test.ts +66 -0
- package/src/scenarios/orchestratorTermination.test.ts +54 -0
- package/src/scenarios/otel-emission.test.ts +113 -0
- package/src/scenarios/otel-trace-propagation.test.ts +90 -0
- package/src/scenarios/pack-registry-publish.test.ts +93 -0
- package/src/scenarios/pack-registry.test.ts +328 -0
- package/src/scenarios/pause-resume.test.ts +109 -0
- package/src/scenarios/policies.test.ts +162 -0
- package/src/scenarios/profileDerivation.test.ts +335 -0
- package/src/scenarios/providerPolicyEnforcement.test.ts +132 -0
- package/src/scenarios/rate-limit-envelope.test.ts +97 -0
- package/src/scenarios/redaction.test.ts +254 -0
- package/src/scenarios/redactionAdversarial.test.ts +162 -0
- package/src/scenarios/replay-fork-arbitrary.test.ts +347 -0
- package/src/scenarios/replay-fork.test.ts +216 -0
- package/src/scenarios/replayDeterminism.test.ts +171 -0
- package/src/scenarios/route-coverage.test.ts +129 -0
- package/src/scenarios/runs-lifecycle.test.ts +65 -0
- package/src/scenarios/runtime-capabilities.test.ts +118 -0
- package/src/scenarios/spec-corpus-validity.test.ts +1257 -0
- package/src/scenarios/staleClaim.test.ts +223 -0
- package/src/scenarios/stream-modes-buffer.test.ts +148 -0
- package/src/scenarios/stream-modes-mixed.test.ts +149 -0
- package/src/scenarios/stream-modes.test.ts +139 -0
- package/src/scenarios/streamReconnect.test.ts +162 -0
- package/src/scenarios/subworkflow.test.ts +126 -0
- package/src/scenarios/version-negotiation.test.ts +157 -0
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +47 -0
- package/src/scenarios/wasm-pack-invoke-completed.test.ts +69 -0
- package/src/scenarios/wasm-pack-invoke-suspended.test.ts +74 -0
- package/src/scenarios/wasm-pack-load.test.ts +75 -0
- package/src/scenarios/wasm-pack-memory-cap.test.ts +43 -0
- package/src/scenarios/wasm-pack-replay-determinism.test.ts +61 -0
- package/src/scenarios/webhook-sig-algorithm.test.ts +61 -0
- package/src/setup.ts +173 -0
- package/vitest.config.ts +17 -0
package/api/openapi.yaml
ADDED
|
@@ -0,0 +1,830 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
title: Workflow Orchestration Protocol (openwop) API
|
|
5
|
+
version: "1.0"
|
|
6
|
+
summary: REST surface for declaring, executing, suspending, resuming, and observing multi-step workflows.
|
|
7
|
+
description: |
|
|
8
|
+
Canonical OpenAPI 3.1 specification for openwop-compliant servers. Generated from `rest-endpoints.md` and references the JSON Schemas in `schemas/`.
|
|
9
|
+
|
|
10
|
+
See spec docs for semantics:
|
|
11
|
+
- `auth.md` — API key + scope vocabulary
|
|
12
|
+
- `idempotency.md` — `Idempotency-Key` header contract
|
|
13
|
+
- `version-negotiation.md` — `engineVersion` + `eventLogSchemaVersion`
|
|
14
|
+
- `capabilities.md` — `/.well-known/openwop` handshake
|
|
15
|
+
- `stream-modes.md` — SSE consumption modes
|
|
16
|
+
- `run-options.md` — `configurable`/`tags`/`metadata`
|
|
17
|
+
- `interrupt.md` — HITL primitive
|
|
18
|
+
- `replay.md` — `:fork` endpoint
|
|
19
|
+
contact:
|
|
20
|
+
name: openwop spec working group
|
|
21
|
+
url: https://openwop.dev/spec/v1/
|
|
22
|
+
license:
|
|
23
|
+
name: Apache-2.0
|
|
24
|
+
identifier: Apache-2.0
|
|
25
|
+
|
|
26
|
+
externalDocs:
|
|
27
|
+
description: openwop spec v1 corpus
|
|
28
|
+
url: https://openwop.dev/spec/v1/
|
|
29
|
+
|
|
30
|
+
servers:
|
|
31
|
+
- url: https://{host}/v1
|
|
32
|
+
description: openwop-compliant server
|
|
33
|
+
variables:
|
|
34
|
+
host:
|
|
35
|
+
default: api.example.com
|
|
36
|
+
description: Replace with your server's hostname.
|
|
37
|
+
|
|
38
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
39
|
+
# SECURITY
|
|
40
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
41
|
+
security:
|
|
42
|
+
- ApiKeyAuth: []
|
|
43
|
+
|
|
44
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
# TAGS
|
|
46
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
47
|
+
tags:
|
|
48
|
+
- name: discovery
|
|
49
|
+
description: Public capability + spec discovery (no auth required).
|
|
50
|
+
- name: workflows
|
|
51
|
+
description: Workflow definition manifest.
|
|
52
|
+
- name: runs
|
|
53
|
+
description: Run lifecycle — create, read, stream, cancel, fork.
|
|
54
|
+
- name: hitl
|
|
55
|
+
description: Human-in-the-loop interrupts and approvals.
|
|
56
|
+
- name: artifacts
|
|
57
|
+
description: Run-produced artifacts.
|
|
58
|
+
- name: webhooks
|
|
59
|
+
description: Subscribe to run events via outbound HTTP.
|
|
60
|
+
|
|
61
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
62
|
+
# PATHS
|
|
63
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
paths:
|
|
65
|
+
|
|
66
|
+
# ── Discovery (unauthenticated) ─────────────────────────────────────────
|
|
67
|
+
/.well-known/openwop:
|
|
68
|
+
get:
|
|
69
|
+
tags: [discovery]
|
|
70
|
+
summary: Capability declaration handshake.
|
|
71
|
+
operationId: getCapabilities
|
|
72
|
+
security: []
|
|
73
|
+
responses:
|
|
74
|
+
'200':
|
|
75
|
+
description: Capabilities object — see `capabilities.md`.
|
|
76
|
+
headers:
|
|
77
|
+
Cache-Control:
|
|
78
|
+
schema: { type: string }
|
|
79
|
+
example: 'public, max-age=300'
|
|
80
|
+
Capabilities-Etag:
|
|
81
|
+
schema: { type: string }
|
|
82
|
+
description: Optional probe handle for mid-session capability change detection.
|
|
83
|
+
content:
|
|
84
|
+
application/json:
|
|
85
|
+
schema:
|
|
86
|
+
$ref: '#/components/schemas/Capabilities'
|
|
87
|
+
'503':
|
|
88
|
+
description: Server unable to compute capabilities (transient).
|
|
89
|
+
content:
|
|
90
|
+
application/json:
|
|
91
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
92
|
+
|
|
93
|
+
/v1/openapi.json:
|
|
94
|
+
get:
|
|
95
|
+
tags: [discovery]
|
|
96
|
+
summary: Self-describing OpenAPI 3.1 spec.
|
|
97
|
+
operationId: getOpenApiSpec
|
|
98
|
+
security: []
|
|
99
|
+
responses:
|
|
100
|
+
'200':
|
|
101
|
+
description: This document.
|
|
102
|
+
content:
|
|
103
|
+
application/json:
|
|
104
|
+
schema:
|
|
105
|
+
type: object
|
|
106
|
+
'503':
|
|
107
|
+
description: Server unable to serve spec (transient).
|
|
108
|
+
content:
|
|
109
|
+
application/json:
|
|
110
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
111
|
+
|
|
112
|
+
# ── Workflows ───────────────────────────────────────────────────────────
|
|
113
|
+
/v1/workflows/{workflowId}:
|
|
114
|
+
get:
|
|
115
|
+
tags: [workflows]
|
|
116
|
+
summary: Read a workflow definition.
|
|
117
|
+
operationId: getWorkflow
|
|
118
|
+
parameters:
|
|
119
|
+
- $ref: '#/components/parameters/WorkflowId'
|
|
120
|
+
responses:
|
|
121
|
+
'200':
|
|
122
|
+
description: Workflow definition.
|
|
123
|
+
content:
|
|
124
|
+
application/json:
|
|
125
|
+
schema:
|
|
126
|
+
$ref: '../schemas/workflow-definition.schema.json'
|
|
127
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
128
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
129
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
130
|
+
|
|
131
|
+
# ── Runs ────────────────────────────────────────────────────────────────
|
|
132
|
+
/v1/runs:
|
|
133
|
+
post:
|
|
134
|
+
tags: [runs]
|
|
135
|
+
summary: Create a new run.
|
|
136
|
+
operationId: createRun
|
|
137
|
+
parameters:
|
|
138
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
139
|
+
- in: header
|
|
140
|
+
name: X-Dedup
|
|
141
|
+
schema:
|
|
142
|
+
type: string
|
|
143
|
+
enum: [enforce]
|
|
144
|
+
description: When set, server cross-host claim system rejects duplicate `(tenantId, scopeId)` pairs with `409 Conflict`.
|
|
145
|
+
- in: header
|
|
146
|
+
name: X-Force-Engine-Version
|
|
147
|
+
schema: { type: integer, minimum: 0 }
|
|
148
|
+
description: |
|
|
149
|
+
**Test-keys-only.** When set, the server emits events for this run AS IF it
|
|
150
|
+
were running the specified engine version (must be within the server's
|
|
151
|
+
advertised `Capabilities.testing.forceEngineVersionRange`). Used by the
|
|
152
|
+
conformance suite to verify version-negotiation fold-best-effort tolerance
|
|
153
|
+
across the spec's forward-compat matrix. Servers MUST reject on production
|
|
154
|
+
API keys with `403 force_engine_version_forbidden`. Closes F5.
|
|
155
|
+
requestBody:
|
|
156
|
+
required: true
|
|
157
|
+
content:
|
|
158
|
+
application/json:
|
|
159
|
+
schema:
|
|
160
|
+
# The body is the WorkflowId + inputs + transport-specific
|
|
161
|
+
# routing fields, plus the openwop RunOptions overlay (configurable,
|
|
162
|
+
# tags, metadata) hoisted into a first-class JSON Schema at
|
|
163
|
+
# ../schemas/run-options.schema.json. allOf composes the two
|
|
164
|
+
# so callers see one unified body shape.
|
|
165
|
+
allOf:
|
|
166
|
+
- type: object
|
|
167
|
+
required: [workflowId]
|
|
168
|
+
properties:
|
|
169
|
+
workflowId: { type: string, minLength: 1 }
|
|
170
|
+
inputs:
|
|
171
|
+
type: object
|
|
172
|
+
description: Workflow inputs (consumed by triggers/nodes).
|
|
173
|
+
tenantId:
|
|
174
|
+
type: string
|
|
175
|
+
description: Tenant scoping. Server typically defaults from API key.
|
|
176
|
+
scopeId:
|
|
177
|
+
type: string
|
|
178
|
+
description: Opaque correlation ID for `X-Dedup` semantics.
|
|
179
|
+
callbackUrl:
|
|
180
|
+
type: string
|
|
181
|
+
format: uri
|
|
182
|
+
description: Signed-token HITL callback URL (see `interrupt.md`).
|
|
183
|
+
additionalProperties: false
|
|
184
|
+
- $ref: '../schemas/run-options.schema.json'
|
|
185
|
+
responses:
|
|
186
|
+
'201':
|
|
187
|
+
description: Run accepted.
|
|
188
|
+
headers:
|
|
189
|
+
openwop-Idempotent-Replay:
|
|
190
|
+
schema: { type: boolean }
|
|
191
|
+
description: Set when the response was served from the idempotency cache.
|
|
192
|
+
content:
|
|
193
|
+
application/json:
|
|
194
|
+
schema:
|
|
195
|
+
type: object
|
|
196
|
+
required: [runId, status, eventsUrl]
|
|
197
|
+
properties:
|
|
198
|
+
runId: { type: string }
|
|
199
|
+
status:
|
|
200
|
+
type: string
|
|
201
|
+
enum: [pending, running, waiting-approval, waiting-input]
|
|
202
|
+
eventsUrl: { type: string, format: uri }
|
|
203
|
+
statusUrl: { type: string, format: uri }
|
|
204
|
+
'400': { $ref: '#/components/responses/ValidationError' }
|
|
205
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
206
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
207
|
+
'409':
|
|
208
|
+
description: '`X-Dedup` collision OR concurrent `Idempotency-Key` collision.'
|
|
209
|
+
headers:
|
|
210
|
+
Retry-After:
|
|
211
|
+
schema: { type: integer }
|
|
212
|
+
description: Seconds until the active claim is stale-eligible.
|
|
213
|
+
content:
|
|
214
|
+
application/json:
|
|
215
|
+
schema:
|
|
216
|
+
$ref: '#/components/schemas/RunClaimConflict'
|
|
217
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
218
|
+
|
|
219
|
+
/v1/runs/{runId}:
|
|
220
|
+
get:
|
|
221
|
+
tags: [runs]
|
|
222
|
+
summary: Read run state (cached projection).
|
|
223
|
+
operationId: getRun
|
|
224
|
+
parameters:
|
|
225
|
+
- $ref: '#/components/parameters/RunId'
|
|
226
|
+
responses:
|
|
227
|
+
'200':
|
|
228
|
+
description: Projected run state.
|
|
229
|
+
content:
|
|
230
|
+
application/json:
|
|
231
|
+
schema:
|
|
232
|
+
$ref: '#/components/schemas/RunSnapshot'
|
|
233
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
234
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
235
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
236
|
+
|
|
237
|
+
/v1/runs/{runId}/events:
|
|
238
|
+
get:
|
|
239
|
+
tags: [runs]
|
|
240
|
+
summary: SSE stream of run events.
|
|
241
|
+
operationId: streamRunEvents
|
|
242
|
+
parameters:
|
|
243
|
+
- $ref: '#/components/parameters/RunId'
|
|
244
|
+
- in: query
|
|
245
|
+
name: streamMode
|
|
246
|
+
schema:
|
|
247
|
+
type: string
|
|
248
|
+
default: updates
|
|
249
|
+
pattern: '^(values|updates|messages|debug)(,(values|updates|messages|debug))*$'
|
|
250
|
+
description: |
|
|
251
|
+
Single mode: `values` / `updates` / `messages` / `debug`.
|
|
252
|
+
Mixed mode: comma-separated combination (e.g., `updates,messages`)
|
|
253
|
+
per S4 closure — server emits union-of-filters with per-event
|
|
254
|
+
`event:` field labeling which mode admitted each event.
|
|
255
|
+
`values` MUST NOT combine with other modes (state.snapshot semantics
|
|
256
|
+
need exclusive ownership). See `stream-modes.md`. Default `updates`.
|
|
257
|
+
- in: query
|
|
258
|
+
name: bufferMs
|
|
259
|
+
schema:
|
|
260
|
+
type: integer
|
|
261
|
+
minimum: 0
|
|
262
|
+
maximum: 5000
|
|
263
|
+
description: |
|
|
264
|
+
Optional batching hint per S3 closure. When set, the server
|
|
265
|
+
accumulates events for up to N ms (or until a forced-flush
|
|
266
|
+
trigger fires — terminal events, suspensions, connection close)
|
|
267
|
+
and emits a single SSE event with `event: batch` and `data:` as
|
|
268
|
+
a JSON array of `RunEventDoc`. Range 0..5000; `0` = no buffering.
|
|
269
|
+
See `stream-modes.md` §Aggregation hint.
|
|
270
|
+
- in: header
|
|
271
|
+
name: Last-Event-ID
|
|
272
|
+
schema: { type: string }
|
|
273
|
+
description: Resume from sequence after this ID.
|
|
274
|
+
responses:
|
|
275
|
+
'200':
|
|
276
|
+
description: SSE stream. Auto-closes on terminal event. Keep-alive comments every 30s.
|
|
277
|
+
content:
|
|
278
|
+
text/event-stream:
|
|
279
|
+
schema:
|
|
280
|
+
type: string
|
|
281
|
+
description: SSE events. Each event has `id:`, `event:`, `data:` per RFC 8895.
|
|
282
|
+
'400':
|
|
283
|
+
description: Unsupported `streamMode`.
|
|
284
|
+
content:
|
|
285
|
+
application/json:
|
|
286
|
+
schema:
|
|
287
|
+
$ref: '#/components/schemas/UnsupportedStreamMode'
|
|
288
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
289
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
290
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
291
|
+
|
|
292
|
+
/v1/runs/{runId}/events/poll:
|
|
293
|
+
get:
|
|
294
|
+
tags: [runs]
|
|
295
|
+
summary: Long-poll fallback for non-SSE clients.
|
|
296
|
+
operationId: pollRunEvents
|
|
297
|
+
parameters:
|
|
298
|
+
- $ref: '#/components/parameters/RunId'
|
|
299
|
+
- in: query
|
|
300
|
+
name: lastSequence
|
|
301
|
+
schema: { type: integer, minimum: 0 }
|
|
302
|
+
- in: query
|
|
303
|
+
name: timeout
|
|
304
|
+
schema: { type: integer, minimum: 1, maximum: 60, default: 30 }
|
|
305
|
+
description: Seconds to wait for new events. Max 60.
|
|
306
|
+
responses:
|
|
307
|
+
'200':
|
|
308
|
+
description: Events since `lastSequence`.
|
|
309
|
+
content:
|
|
310
|
+
application/json:
|
|
311
|
+
schema:
|
|
312
|
+
type: object
|
|
313
|
+
required: [events, isComplete]
|
|
314
|
+
properties:
|
|
315
|
+
events:
|
|
316
|
+
type: array
|
|
317
|
+
items:
|
|
318
|
+
$ref: '../schemas/run-event.schema.json'
|
|
319
|
+
isComplete: { type: boolean }
|
|
320
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
321
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
322
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
323
|
+
|
|
324
|
+
/v1/runs/{runId}/cancel:
|
|
325
|
+
post:
|
|
326
|
+
tags: [runs]
|
|
327
|
+
summary: Cancel an in-flight run.
|
|
328
|
+
operationId: cancelRun
|
|
329
|
+
parameters:
|
|
330
|
+
- $ref: '#/components/parameters/RunId'
|
|
331
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
332
|
+
requestBody:
|
|
333
|
+
content:
|
|
334
|
+
application/json:
|
|
335
|
+
schema:
|
|
336
|
+
type: object
|
|
337
|
+
properties:
|
|
338
|
+
reason: { type: string }
|
|
339
|
+
responses:
|
|
340
|
+
'200':
|
|
341
|
+
description: Run cancellation accepted (cascade may be async).
|
|
342
|
+
content:
|
|
343
|
+
application/json:
|
|
344
|
+
schema:
|
|
345
|
+
type: object
|
|
346
|
+
properties:
|
|
347
|
+
runId: { type: string }
|
|
348
|
+
status: { type: string, enum: [cancelled, cancelling] }
|
|
349
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
350
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
351
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
352
|
+
|
|
353
|
+
/v1/runs/{runId}:fork:
|
|
354
|
+
post:
|
|
355
|
+
tags: [runs]
|
|
356
|
+
summary: Fork the run for replay or branch (see `replay.md`).
|
|
357
|
+
operationId: forkRun
|
|
358
|
+
parameters:
|
|
359
|
+
- $ref: '#/components/parameters/RunId'
|
|
360
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
361
|
+
requestBody:
|
|
362
|
+
required: true
|
|
363
|
+
content:
|
|
364
|
+
application/json:
|
|
365
|
+
schema:
|
|
366
|
+
type: object
|
|
367
|
+
required: [fromSeq, mode]
|
|
368
|
+
properties:
|
|
369
|
+
fromSeq:
|
|
370
|
+
type: integer
|
|
371
|
+
minimum: 0
|
|
372
|
+
description: Inclusive — events `< fromSeq` are fixed history; `>= fromSeq` are re-executed.
|
|
373
|
+
mode:
|
|
374
|
+
type: string
|
|
375
|
+
enum: [replay, branch]
|
|
376
|
+
runOptionsOverlay:
|
|
377
|
+
type: object
|
|
378
|
+
description: For `branch` mode only — caller-supplied `RunOptions` to overlay.
|
|
379
|
+
additionalProperties: false
|
|
380
|
+
responses:
|
|
381
|
+
'201':
|
|
382
|
+
description: Fork accepted, new run started.
|
|
383
|
+
content:
|
|
384
|
+
application/json:
|
|
385
|
+
schema:
|
|
386
|
+
type: object
|
|
387
|
+
required: [runId, sourceRunId, mode, status, eventsUrl]
|
|
388
|
+
properties:
|
|
389
|
+
runId: { type: string }
|
|
390
|
+
sourceRunId: { type: string }
|
|
391
|
+
fromSeq: { type: integer }
|
|
392
|
+
mode: { type: string, enum: [replay, branch] }
|
|
393
|
+
status: { type: string }
|
|
394
|
+
eventsUrl: { type: string, format: uri }
|
|
395
|
+
'400':
|
|
396
|
+
description: Invalid `fromSeq`, `replay` with non-empty `runOptionsOverlay`, etc.
|
|
397
|
+
content:
|
|
398
|
+
application/json:
|
|
399
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
400
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
401
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
402
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
403
|
+
'422':
|
|
404
|
+
description: "`fromSeq` references a sequence number that doesn't exist in the source run's event log."
|
|
405
|
+
content:
|
|
406
|
+
application/json:
|
|
407
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
408
|
+
|
|
409
|
+
/v1/runs/{runId}:pause:
|
|
410
|
+
post:
|
|
411
|
+
tags: [runs]
|
|
412
|
+
summary: Administratively pause an in-flight run (RFC Track 13).
|
|
413
|
+
description: |
|
|
414
|
+
Operator-driven pause distinct from cancel (terminal) and HITL suspend (workflow-driven).
|
|
415
|
+
Emits a `run.paused` event when the pause takes effect; exit only via `:resume` or `:cancel`.
|
|
416
|
+
operationId: pauseRun
|
|
417
|
+
parameters:
|
|
418
|
+
- $ref: '#/components/parameters/RunId'
|
|
419
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
420
|
+
requestBody:
|
|
421
|
+
content:
|
|
422
|
+
application/json:
|
|
423
|
+
schema:
|
|
424
|
+
type: object
|
|
425
|
+
properties:
|
|
426
|
+
reason:
|
|
427
|
+
type: string
|
|
428
|
+
description: Free-form rationale, persisted on the `run.paused` event payload.
|
|
429
|
+
drainPolicy:
|
|
430
|
+
type: string
|
|
431
|
+
enum: [immediate, drain-current-node]
|
|
432
|
+
default: drain-current-node
|
|
433
|
+
description: |
|
|
434
|
+
`immediate` snapshots between events; `drain-current-node` lets the running node
|
|
435
|
+
reach a terminal before transitioning to `paused`.
|
|
436
|
+
additionalProperties: false
|
|
437
|
+
responses:
|
|
438
|
+
'202':
|
|
439
|
+
description: Pause requested; transition emits `run.paused` when complete.
|
|
440
|
+
content:
|
|
441
|
+
application/json:
|
|
442
|
+
schema:
|
|
443
|
+
type: object
|
|
444
|
+
required: [runId, status]
|
|
445
|
+
properties:
|
|
446
|
+
runId: { type: string }
|
|
447
|
+
status: { type: string, enum: [paused] }
|
|
448
|
+
pausedAt: { type: string, format: date-time }
|
|
449
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
450
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
451
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
452
|
+
'409':
|
|
453
|
+
description: Run is already paused, terminal, or in a state that cannot be paused.
|
|
454
|
+
content:
|
|
455
|
+
application/json:
|
|
456
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
457
|
+
|
|
458
|
+
/v1/runs/{runId}:resume:
|
|
459
|
+
post:
|
|
460
|
+
tags: [runs]
|
|
461
|
+
summary: Resume a paused run (RFC Track 13).
|
|
462
|
+
description: |
|
|
463
|
+
Reverses a prior `:pause`. Run transitions from `paused` to `running` and emits `run.resumed`.
|
|
464
|
+
operationId: resumeRun
|
|
465
|
+
parameters:
|
|
466
|
+
- $ref: '#/components/parameters/RunId'
|
|
467
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
468
|
+
requestBody:
|
|
469
|
+
content:
|
|
470
|
+
application/json:
|
|
471
|
+
schema:
|
|
472
|
+
type: object
|
|
473
|
+
properties:
|
|
474
|
+
reason: { type: string }
|
|
475
|
+
additionalProperties: false
|
|
476
|
+
responses:
|
|
477
|
+
'202':
|
|
478
|
+
description: Resume requested.
|
|
479
|
+
content:
|
|
480
|
+
application/json:
|
|
481
|
+
schema:
|
|
482
|
+
type: object
|
|
483
|
+
required: [runId, status]
|
|
484
|
+
properties:
|
|
485
|
+
runId: { type: string }
|
|
486
|
+
status: { type: string, enum: [running] }
|
|
487
|
+
resumedAt: { type: string, format: date-time }
|
|
488
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
489
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
490
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
491
|
+
'409':
|
|
492
|
+
description: Run is not currently paused.
|
|
493
|
+
content:
|
|
494
|
+
application/json:
|
|
495
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
496
|
+
|
|
497
|
+
# ── HITL ────────────────────────────────────────────────────────────────
|
|
498
|
+
/v1/runs/{runId}/interrupts/{nodeId}:
|
|
499
|
+
post:
|
|
500
|
+
tags: [hitl]
|
|
501
|
+
summary: Resolve an interrupt via the run-scoped surface.
|
|
502
|
+
operationId: resolveInterruptByRun
|
|
503
|
+
parameters:
|
|
504
|
+
- $ref: '#/components/parameters/RunId'
|
|
505
|
+
- in: path
|
|
506
|
+
name: nodeId
|
|
507
|
+
required: true
|
|
508
|
+
schema: { type: string, minLength: 1 }
|
|
509
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
510
|
+
requestBody:
|
|
511
|
+
required: true
|
|
512
|
+
content:
|
|
513
|
+
application/json:
|
|
514
|
+
schema:
|
|
515
|
+
type: object
|
|
516
|
+
required: [resumeValue]
|
|
517
|
+
properties:
|
|
518
|
+
resumeValue:
|
|
519
|
+
description: Validated against the interrupt's `resumeSchema` if declared.
|
|
520
|
+
additionalProperties: false
|
|
521
|
+
responses:
|
|
522
|
+
'200':
|
|
523
|
+
description: Interrupt resolved; executor unblocks.
|
|
524
|
+
content:
|
|
525
|
+
application/json:
|
|
526
|
+
schema:
|
|
527
|
+
type: object
|
|
528
|
+
properties:
|
|
529
|
+
runId: { type: string }
|
|
530
|
+
nodeId: { type: string }
|
|
531
|
+
status: { type: string }
|
|
532
|
+
'400': { $ref: '#/components/responses/ValidationError' }
|
|
533
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
534
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
535
|
+
'404':
|
|
536
|
+
description: Interrupt not found or already resolved.
|
|
537
|
+
content:
|
|
538
|
+
application/json:
|
|
539
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
540
|
+
'409':
|
|
541
|
+
description: Concurrent resolve — only one wins.
|
|
542
|
+
content:
|
|
543
|
+
application/json:
|
|
544
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
545
|
+
'422':
|
|
546
|
+
description: Run was cancelled while interrupt was pending.
|
|
547
|
+
content:
|
|
548
|
+
application/json:
|
|
549
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
550
|
+
|
|
551
|
+
/v1/interrupts/{token}:
|
|
552
|
+
parameters:
|
|
553
|
+
- in: path
|
|
554
|
+
name: token
|
|
555
|
+
required: true
|
|
556
|
+
schema: { type: string }
|
|
557
|
+
description: HMAC-signed token issued by the server at suspension time. Format `base64url(payload).hmac_sha256(secret, payload)`.
|
|
558
|
+
get:
|
|
559
|
+
tags: [hitl]
|
|
560
|
+
summary: Inspect an interrupt without resolving (signed-token surface).
|
|
561
|
+
operationId: inspectInterruptByToken
|
|
562
|
+
security: [] # token is the auth
|
|
563
|
+
responses:
|
|
564
|
+
'200':
|
|
565
|
+
description: Interrupt details.
|
|
566
|
+
content:
|
|
567
|
+
application/json:
|
|
568
|
+
schema: { $ref: '../schemas/suspend-request.schema.json' }
|
|
569
|
+
'410':
|
|
570
|
+
description: Token expired.
|
|
571
|
+
content:
|
|
572
|
+
application/json:
|
|
573
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
574
|
+
post:
|
|
575
|
+
tags: [hitl]
|
|
576
|
+
summary: Resolve an interrupt via signed token (asynchronous callback).
|
|
577
|
+
operationId: resolveInterruptByToken
|
|
578
|
+
security: [] # token is the auth
|
|
579
|
+
parameters:
|
|
580
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
581
|
+
requestBody:
|
|
582
|
+
required: true
|
|
583
|
+
content:
|
|
584
|
+
application/json:
|
|
585
|
+
schema:
|
|
586
|
+
type: object
|
|
587
|
+
required: [resumeValue]
|
|
588
|
+
properties:
|
|
589
|
+
resumeValue: {}
|
|
590
|
+
additionalProperties: false
|
|
591
|
+
responses:
|
|
592
|
+
'200':
|
|
593
|
+
description: Resolution accepted.
|
|
594
|
+
content:
|
|
595
|
+
application/json:
|
|
596
|
+
schema: { type: object }
|
|
597
|
+
'410':
|
|
598
|
+
description: Token expired.
|
|
599
|
+
content:
|
|
600
|
+
application/json:
|
|
601
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
602
|
+
|
|
603
|
+
# ── Artifacts ───────────────────────────────────────────────────────────
|
|
604
|
+
/v1/runs/{runId}/artifacts/{artifactId}:
|
|
605
|
+
get:
|
|
606
|
+
tags: [artifacts]
|
|
607
|
+
summary: Read a run-produced artifact.
|
|
608
|
+
operationId: getArtifact
|
|
609
|
+
parameters:
|
|
610
|
+
- $ref: '#/components/parameters/RunId'
|
|
611
|
+
- in: path
|
|
612
|
+
name: artifactId
|
|
613
|
+
required: true
|
|
614
|
+
schema: { type: string, minLength: 1 }
|
|
615
|
+
responses:
|
|
616
|
+
'200':
|
|
617
|
+
description: Artifact payload.
|
|
618
|
+
content:
|
|
619
|
+
application/json:
|
|
620
|
+
schema:
|
|
621
|
+
type: object
|
|
622
|
+
description: Implementation-defined artifact shape.
|
|
623
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
624
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
625
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
626
|
+
|
|
627
|
+
# ── Webhooks ────────────────────────────────────────────────────────────
|
|
628
|
+
/v1/webhooks:
|
|
629
|
+
post:
|
|
630
|
+
tags: [webhooks]
|
|
631
|
+
summary: Register a webhook subscription.
|
|
632
|
+
operationId: registerWebhook
|
|
633
|
+
parameters:
|
|
634
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
635
|
+
requestBody:
|
|
636
|
+
required: true
|
|
637
|
+
content:
|
|
638
|
+
application/json:
|
|
639
|
+
schema:
|
|
640
|
+
type: object
|
|
641
|
+
required: [url, events]
|
|
642
|
+
properties:
|
|
643
|
+
url: { type: string, format: uri }
|
|
644
|
+
events:
|
|
645
|
+
type: array
|
|
646
|
+
items: { type: string }
|
|
647
|
+
description: Event types to subscribe to (see `run-event.schema.json` enum).
|
|
648
|
+
secret:
|
|
649
|
+
type: string
|
|
650
|
+
description: Server signs payloads with this secret using HMAC-SHA256.
|
|
651
|
+
tags:
|
|
652
|
+
type: array
|
|
653
|
+
items: { type: string }
|
|
654
|
+
description: Filter to runs carrying these tags (see `run-options.md`).
|
|
655
|
+
additionalProperties: false
|
|
656
|
+
responses:
|
|
657
|
+
'201':
|
|
658
|
+
description: Webhook registered.
|
|
659
|
+
content:
|
|
660
|
+
application/json:
|
|
661
|
+
schema:
|
|
662
|
+
type: object
|
|
663
|
+
required: [webhookId]
|
|
664
|
+
properties:
|
|
665
|
+
webhookId: { type: string }
|
|
666
|
+
'400': { $ref: '#/components/responses/ValidationError' }
|
|
667
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
668
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
669
|
+
|
|
670
|
+
/v1/webhooks/{webhookId}:
|
|
671
|
+
delete:
|
|
672
|
+
tags: [webhooks]
|
|
673
|
+
summary: Unregister a webhook.
|
|
674
|
+
operationId: unregisterWebhook
|
|
675
|
+
parameters:
|
|
676
|
+
- in: path
|
|
677
|
+
name: webhookId
|
|
678
|
+
required: true
|
|
679
|
+
schema: { type: string, minLength: 1 }
|
|
680
|
+
responses:
|
|
681
|
+
'204':
|
|
682
|
+
description: Unregistered.
|
|
683
|
+
'401': { $ref: '#/components/responses/Unauthenticated' }
|
|
684
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
685
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
686
|
+
|
|
687
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
688
|
+
# COMPONENTS
|
|
689
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
690
|
+
components:
|
|
691
|
+
|
|
692
|
+
securitySchemes:
|
|
693
|
+
ApiKeyAuth:
|
|
694
|
+
type: http
|
|
695
|
+
scheme: bearer
|
|
696
|
+
bearerFormat: API key
|
|
697
|
+
description: |
|
|
698
|
+
openwop API key. Format implementation-defined; reference impl uses `hk_`/`hk_test_` prefixes.
|
|
699
|
+
Each key carries one or more scopes from the canonical vocabulary
|
|
700
|
+
(`manifest:read`, `runs:create`, `runs:read`, `runs:cancel`,
|
|
701
|
+
`artifacts:read`, `webhooks:manage`, `approvals:respond`).
|
|
702
|
+
See `auth.md`.
|
|
703
|
+
|
|
704
|
+
parameters:
|
|
705
|
+
WorkflowId:
|
|
706
|
+
in: path
|
|
707
|
+
name: workflowId
|
|
708
|
+
required: true
|
|
709
|
+
schema: { type: string, minLength: 1, maxLength: 128 }
|
|
710
|
+
|
|
711
|
+
RunId:
|
|
712
|
+
in: path
|
|
713
|
+
name: runId
|
|
714
|
+
required: true
|
|
715
|
+
schema: { type: string, minLength: 1, maxLength: 128 }
|
|
716
|
+
|
|
717
|
+
IdempotencyKey:
|
|
718
|
+
in: header
|
|
719
|
+
name: Idempotency-Key
|
|
720
|
+
required: false
|
|
721
|
+
schema:
|
|
722
|
+
type: string
|
|
723
|
+
maxLength: 255
|
|
724
|
+
description: |
|
|
725
|
+
Per-mutation idempotency token (see `idempotency.md` Layer 1).
|
|
726
|
+
Server caches `(tenantId, endpoint, key)` → response for ≥24h.
|
|
727
|
+
Duplicate requests return the cached response with header
|
|
728
|
+
`openwop-Idempotent-Replay: true`.
|
|
729
|
+
|
|
730
|
+
responses:
|
|
731
|
+
Unauthenticated:
|
|
732
|
+
description: Missing or invalid credential.
|
|
733
|
+
content:
|
|
734
|
+
application/json:
|
|
735
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
736
|
+
|
|
737
|
+
Forbidden:
|
|
738
|
+
description: Credential valid but lacks required scope or fails resource binding.
|
|
739
|
+
content:
|
|
740
|
+
application/json:
|
|
741
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
742
|
+
|
|
743
|
+
NotFound:
|
|
744
|
+
description: Resource doesn't exist or caller can't see it (do not leak existence).
|
|
745
|
+
content:
|
|
746
|
+
application/json:
|
|
747
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
748
|
+
|
|
749
|
+
ValidationError:
|
|
750
|
+
description: Request body or parameters malformed.
|
|
751
|
+
content:
|
|
752
|
+
application/json:
|
|
753
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
754
|
+
|
|
755
|
+
RateLimited:
|
|
756
|
+
description: Too many requests.
|
|
757
|
+
headers:
|
|
758
|
+
Retry-After:
|
|
759
|
+
schema: { type: integer }
|
|
760
|
+
content:
|
|
761
|
+
application/json:
|
|
762
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
763
|
+
|
|
764
|
+
schemas:
|
|
765
|
+
|
|
766
|
+
# Hoisted to first-class JSON Schemas in ../schemas/ so the SDK and
|
|
767
|
+
# conformance suite can validate against the same source. The
|
|
768
|
+
# in-line aliases below pull them via $ref so existing
|
|
769
|
+
# `#/components/schemas/Error` references keep working.
|
|
770
|
+
|
|
771
|
+
Error:
|
|
772
|
+
$ref: '../schemas/error-envelope.schema.json'
|
|
773
|
+
|
|
774
|
+
Capabilities:
|
|
775
|
+
$ref: '../schemas/capabilities.schema.json'
|
|
776
|
+
|
|
777
|
+
RunSnapshot:
|
|
778
|
+
$ref: '../schemas/run-snapshot.schema.json'
|
|
779
|
+
|
|
780
|
+
RunClaimConflict:
|
|
781
|
+
description: |
|
|
782
|
+
Specialization of the canonical `ErrorEnvelope` shape for
|
|
783
|
+
`run_already_active`. Conflict metadata lives under `details`
|
|
784
|
+
so the top-level error shape remains `{error, message, details?}`.
|
|
785
|
+
allOf:
|
|
786
|
+
- $ref: '#/components/schemas/Error'
|
|
787
|
+
- type: object
|
|
788
|
+
required: [error, message, details]
|
|
789
|
+
properties:
|
|
790
|
+
error:
|
|
791
|
+
type: string
|
|
792
|
+
enum: [run_already_active]
|
|
793
|
+
message: { type: string }
|
|
794
|
+
details:
|
|
795
|
+
type: object
|
|
796
|
+
required: [activeRunId, activeHost]
|
|
797
|
+
properties:
|
|
798
|
+
activeRunId: { type: string }
|
|
799
|
+
activeHost:
|
|
800
|
+
type: string
|
|
801
|
+
enum: [browser, cloud]
|
|
802
|
+
retryAfter:
|
|
803
|
+
type: integer
|
|
804
|
+
description: 'Seconds. Mirrors the `Retry-After` header.'
|
|
805
|
+
|
|
806
|
+
UnsupportedStreamMode:
|
|
807
|
+
description: |
|
|
808
|
+
Specialization of the canonical `ErrorEnvelope` shape (see
|
|
809
|
+
`error-envelope.schema.json`) for the `unsupported_stream_mode`
|
|
810
|
+
case. The `supported` array lives in `details` per the canonical
|
|
811
|
+
envelope's contextual-data slot, NOT at the top level. SDK
|
|
812
|
+
consumers using a generic ErrorEnvelope parser will find the
|
|
813
|
+
list under `details.supported` regardless of which validator
|
|
814
|
+
fired.
|
|
815
|
+
allOf:
|
|
816
|
+
- $ref: '#/components/schemas/Error'
|
|
817
|
+
- type: object
|
|
818
|
+
required: [error, message, details]
|
|
819
|
+
properties:
|
|
820
|
+
error:
|
|
821
|
+
type: string
|
|
822
|
+
enum: [unsupported_stream_mode]
|
|
823
|
+
message: { type: string }
|
|
824
|
+
details:
|
|
825
|
+
type: object
|
|
826
|
+
required: [supported]
|
|
827
|
+
properties:
|
|
828
|
+
supported:
|
|
829
|
+
type: array
|
|
830
|
+
items: { type: string, enum: [values, updates, messages, debug] }
|