@ancplua/qyl-api-schema 3.0.0 → 5.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.
@@ -0,0 +1,231 @@
1
+ import "@typespec/events";
2
+ import "@typespec/http";
3
+ import "@typespec/sse";
4
+
5
+ import "../common/errors.tsp";
6
+ import "../models/workflow.tsp";
7
+ import "./routes.tsp";
8
+
9
+ using TypeSpec.Events;
10
+ using TypeSpec.Http;
11
+ using TypeSpec.SSE;
12
+
13
+ using Qyl.Api.Contracts.Common.Errors;
14
+ using Qyl.Api.Contracts.Workflow;
15
+
16
+ namespace Qyl.Api.Contracts.Workflow;
17
+
18
+ @doc("Keep-alive emitted while a workflow event stream has no new event.")
19
+ model WorkflowHeartbeatEvent {
20
+ type: "heartbeat";
21
+
22
+ @encodedName("application/json", "high_water_mark")
23
+ highWaterMark: WorkflowSequence;
24
+
25
+ timestamp: utcDateTime;
26
+ }
27
+
28
+ @doc("Signals that the requested cursor predates retained workflow history.")
29
+ model WorkflowCursorGapEvent {
30
+ type: "cursor_gap";
31
+
32
+ @encodedName("application/json", "oldest_available_sequence")
33
+ oldestAvailableSequence: WorkflowSequence;
34
+
35
+ @encodedName("application/json", "high_water_mark")
36
+ highWaterMark: WorkflowSequence;
37
+
38
+ timestamp: utcDateTime;
39
+ }
40
+
41
+ @events
42
+ union WorkflowStreamEvents {
43
+ event: WorkflowJournalEvent,
44
+ heartbeat: WorkflowHeartbeatEvent,
45
+ cursorGap: WorkflowCursorGapEvent,
46
+ }
47
+
48
+ @route("/api/v1/workflow-runs")
49
+ @tag("Workflow runs")
50
+ @useAuth(Qyl.Api.Contracts.QylApiKeyHeaderAuth)
51
+ interface WorkflowRunsApi {
52
+ @post
53
+ create(
54
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
55
+ @body request: WorkflowRunCreateRequest,
56
+ ):
57
+ | WorkflowRun
58
+ | ValidationError
59
+ | UnauthorizedError
60
+ | ConflictError
61
+ | ServiceUnavailableError
62
+ | InternalServerError;
63
+
64
+ @get
65
+ list(
66
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
67
+ @query status?: WorkflowRunStatus,
68
+ @query
69
+ @minValue(1)
70
+ @maxValue(200)
71
+ limit?: int32 = 50,
72
+ @query cursor?: string,
73
+ ):
74
+ | WorkflowRunPage
75
+ | ValidationError
76
+ | UnauthorizedError
77
+ | ServiceUnavailableError
78
+ | InternalServerError;
79
+
80
+ @get
81
+ @route("/{run_id}")
82
+ get(
83
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
84
+ @path("run_id") runId: WorkflowRunId,
85
+ ):
86
+ | WorkflowRun
87
+ | UnauthorizedError
88
+ | NotFoundError
89
+ | ServiceUnavailableError
90
+ | InternalServerError;
91
+
92
+ @post
93
+ @route("/{run_id}/events")
94
+ appendEvents(
95
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
96
+ @path("run_id") runId: WorkflowRunId,
97
+ @body request: WorkflowEventBatchAppendRequest,
98
+ ):
99
+ | WorkflowEventBatchAppendResponse
100
+ | ValidationError
101
+ | UnauthorizedError
102
+ | NotFoundError
103
+ | ConflictError
104
+ | ServiceUnavailableError
105
+ | InternalServerError;
106
+
107
+ @get
108
+ @route("/{run_id}/events")
109
+ readEvents(
110
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
111
+ @path("run_id") runId: WorkflowRunId,
112
+ @query("after_sequence") afterSequence?: WorkflowSequence,
113
+ @query
114
+ @minValue(1)
115
+ @maxValue(1000)
116
+ limit?: int32 = 250,
117
+ @query("wait_ms")
118
+ @minValue(0)
119
+ @maxValue(30000)
120
+ waitMs?: int32 = 0,
121
+ ):
122
+ | WorkflowEventPage
123
+ | ValidationError
124
+ | UnauthorizedError
125
+ | NotFoundError
126
+ | ServiceUnavailableError
127
+ | InternalServerError;
128
+
129
+ @get
130
+ @route("/{run_id}/graph")
131
+ getGraph(
132
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
133
+ @path("run_id") runId: WorkflowRunId,
134
+ @query("node_cursor") nodeCursor?: string,
135
+ @query("node_limit")
136
+ @minValue(1)
137
+ @maxValue(1000)
138
+ nodeLimit?: int32 = 250,
139
+ @query("edge_cursor") edgeCursor?: string,
140
+ @query("edge_limit")
141
+ @minValue(1)
142
+ @maxValue(2000)
143
+ edgeLimit?: int32 = 500,
144
+ ):
145
+ | WorkflowGraphSnapshot
146
+ | ValidationError
147
+ | UnauthorizedError
148
+ | NotFoundError
149
+ | ServiceUnavailableError
150
+ | InternalServerError;
151
+
152
+ @get
153
+ @route("/{run_id}/content/{content_ref}")
154
+ getContent(
155
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
156
+ @path("run_id") runId: WorkflowRunId,
157
+ @path("content_ref") contentRef: WorkflowContentRef,
158
+ ):
159
+ | WorkflowContent
160
+ | UnauthorizedError
161
+ | NotFoundError
162
+ | ServiceUnavailableError
163
+ | InternalServerError;
164
+
165
+ @get
166
+ @route("/{run_id}/stream")
167
+ stream(
168
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
169
+ @path("run_id") runId: WorkflowRunId,
170
+ @header("Last-Event-ID") lastEventId?: string,
171
+ ):
172
+ | SSEStream<WorkflowStreamEvents>
173
+ | ValidationError
174
+ | UnauthorizedError
175
+ | NotFoundError
176
+ | ServiceUnavailableError
177
+ | InternalServerError;
178
+
179
+ @post
180
+ @route("/{run_id}/commands")
181
+ submitControl(
182
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
183
+ @path("run_id") runId: WorkflowRunId,
184
+ @body request: WorkflowControlRequest,
185
+ ):
186
+ | WorkflowControlCommand
187
+ | ValidationError
188
+ | UnauthorizedError
189
+ | NotFoundError
190
+ | ConflictError
191
+ | ServiceUnavailableError
192
+ | InternalServerError;
193
+
194
+ @get
195
+ @route("/{run_id}/commands")
196
+ pollControls(
197
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
198
+ @path("run_id") runId: WorkflowRunId,
199
+ @query("after_sequence") afterSequence?: WorkflowSequence,
200
+ @query
201
+ @minValue(1)
202
+ @maxValue(100)
203
+ limit?: int32 = 20,
204
+ @query("wait_ms")
205
+ @minValue(0)
206
+ @maxValue(30000)
207
+ waitMs?: int32 = 0,
208
+ ):
209
+ | WorkflowControlCommandPage
210
+ | ValidationError
211
+ | UnauthorizedError
212
+ | NotFoundError
213
+ | ServiceUnavailableError
214
+ | InternalServerError;
215
+
216
+ @post
217
+ @route("/{run_id}/commands/{command_id}/status")
218
+ updateControl(
219
+ ...Qyl.Api.Contracts.ProjectScopeHeader,
220
+ @path("run_id") runId: WorkflowRunId,
221
+ @path("command_id") commandId: WorkflowCommandId,
222
+ @body request: WorkflowControlStatusUpdateRequest,
223
+ ):
224
+ | WorkflowControlCommand
225
+ | ValidationError
226
+ | UnauthorizedError
227
+ | NotFoundError
228
+ | ConflictError
229
+ | ServiceUnavailableError
230
+ | InternalServerError;
231
+ }
package/common/types.tsp CHANGED
@@ -178,6 +178,17 @@ scalar Temperature extends float64;
178
178
  @maxLength(64)
179
179
  scalar Sha256Hash extends string;
180
180
 
181
+ // The revision is a canonical digest of the semantic OpenAPI projection and the
182
+ // exported telemetry-key projection, not a package version. Presentation-only
183
+ // fields do not change it. Truncated to 16 hex characters because it is compared
184
+ // for equality, never used as a security boundary.
185
+ @doc("Deterministic revision of the generated API contract: 'sha256:' followed by the first 16 hex characters of its canonical semantic digest.")
186
+ @pattern("^sha256:[a-f0-9]{16}$")
187
+ @minLength(23)
188
+ @maxLength(23)
189
+ @example("sha256:0f1e2d3c4b5a6978")
190
+ scalar ContractRevision extends string;
191
+
181
192
  @doc("Semantic version string (e.g., 1.2.3)")
182
193
  @pattern("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$")
183
194
  @example("2.1.0")