@ancplua/qyl-api-schema 4.0.0 → 5.1.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/README.md +16 -1
- package/api/workflow.tsp +231 -0
- package/common/types.tsp +5 -6
- package/generated/json-schema/qyl-api-schema.json +1507 -21
- package/generated/openapi/qyl.openapi.json +9214 -5681
- package/generated/ts-runtime/api.d.ts +355 -0
- package/generated/ts-runtime/api.js +96 -1
- package/index.tsp +2 -0
- package/models/mcp-tools.tsp +153 -0
- package/models/workflow.tsp +547 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ no metric DTOs or routes. Profiles are not supported.
|
|
|
11
11
|
## Contract pipeline
|
|
12
12
|
|
|
13
13
|
```text
|
|
14
|
-
Qyl.
|
|
14
|
+
Qyl.Telemetry.SemanticConventions
|
|
15
15
|
|
|
|
16
16
|
| generated semantic key projection
|
|
17
17
|
v
|
|
@@ -45,6 +45,11 @@ regenerate the artifacts, and map the runtime model to the generated contract.
|
|
|
45
45
|
|
|
46
46
|
## Published artifacts
|
|
47
47
|
|
|
48
|
+
Both registries carry the same version from one release tag. The contract advances on
|
|
49
|
+
its own major cadence and does not track the qyl product version — it was already at
|
|
50
|
+
`5.0.0` when qyl launched at `1.0.0`. Read the current version from npm or nuget.org
|
|
51
|
+
rather than from prose here; this line moves faster than a README is revised.
|
|
52
|
+
|
|
48
53
|
| Ecosystem | Artifact | Purpose |
|
|
49
54
|
| --- | --- | --- |
|
|
50
55
|
| npm/TypeSpec | `@ancplua/qyl-api-schema` | Authored schema for TypeSpec consumers |
|
|
@@ -54,6 +59,16 @@ regenerate the artifacts, and map the runtime model to the generated contract.
|
|
|
54
59
|
`main.tsp` is the local compile entry point and includes emitter routing. `index.tsp`
|
|
55
60
|
is the published TypeSpec entry point and contains only the client-facing contract.
|
|
56
61
|
|
|
62
|
+
## Contract revision
|
|
63
|
+
|
|
64
|
+
`scripts/emit-contract-revision.mjs` stamps a deterministic revision — `sha256:` plus
|
|
65
|
+
the first 16 hex characters of the contract's canonical semantic digest — into both
|
|
66
|
+
generated faces during `npm run compile`. A collector reports the revision it was built
|
|
67
|
+
against on its health response, so a client can detect a peer built from a different
|
|
68
|
+
contract instead of discovering the mismatch one malformed field at a time. Read the
|
|
69
|
+
current value from a running collector or the generated artifacts; it is derived, never
|
|
70
|
+
hand-maintained.
|
|
71
|
+
|
|
57
72
|
## Develop
|
|
58
73
|
|
|
59
74
|
Development and CI use Node.js 24 LTS. Published npm artifacts support maintained
|
package/api/workflow.tsp
ADDED
|
@@ -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,12 +178,11 @@ scalar Temperature extends float64;
|
|
|
178
178
|
@maxLength(64)
|
|
179
179
|
scalar Sha256Hash extends string;
|
|
180
180
|
|
|
181
|
-
// The revision is a
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
@doc("Deterministic revision of the generated API contract: 'sha256:' followed by the first 16 hex characters of the SHA-256 digest of the emitted OpenAPI document.")
|
|
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.")
|
|
187
186
|
@pattern("^sha256:[a-f0-9]{16}$")
|
|
188
187
|
@minLength(23)
|
|
189
188
|
@maxLength(23)
|