@ancplua/qyl-api-schema 6.0.0 → 7.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.
@@ -0,0 +1,204 @@
1
+ import "./workflow.tsp";
2
+
3
+ using Qyl.Api.Contracts.Workflow;
4
+
5
+ namespace Qyl.Api.Contracts.Diagnostics;
6
+
7
+ @doc("The versioned extension discriminator for a protected agent diagnostic snapshot.")
8
+ enum AgentDiagnosticExtensionId {
9
+ snapshot: "qyl.agent.diagnostic.snapshot",
10
+ }
11
+
12
+ @doc("Wire-format version of an agent diagnostic snapshot. Version 1 is the only accepted format.")
13
+ @minValue(1)
14
+ @maxValue(1)
15
+ scalar AgentDiagnosticFormatVersion extends int32;
16
+
17
+ @doc("Stable machine identifier of one diagnostic snapshot. This identifier is a value and must never be promoted to a telemetry key.")
18
+ @pattern("^[A-Za-z0-9_][A-Za-z0-9._:/\\[\\]-]{0,127}$")
19
+ @minLength(1)
20
+ @maxLength(128)
21
+ scalar AgentDiagnosticSnapshotId extends string;
22
+
23
+ @doc("Stable machine identifier of the probe that captured a diagnostic snapshot. This identifier is a value and must never be promoted to a telemetry key.")
24
+ @pattern("^[A-Za-z0-9_][A-Za-z0-9._:/\\[\\]-]{0,127}$")
25
+ @minLength(1)
26
+ @maxLength(128)
27
+ scalar AgentDiagnosticProbeId extends string;
28
+
29
+ @doc("Stable machine identifier of one diagnostic check. This identifier is a value and must never be promoted to a telemetry key.")
30
+ @pattern("^[A-Za-z0-9_][A-Za-z0-9._:/\\[\\]-]{0,127}$")
31
+ @minLength(1)
32
+ @maxLength(128)
33
+ scalar AgentDiagnosticCheckId extends string;
34
+
35
+ @doc("Stable machine name of one dynamically captured variable. Names are data values, never telemetry attribute keys, event names, or span names.")
36
+ @pattern("^[A-Za-z0-9_][A-Za-z0-9._:/\\[\\]-]{0,127}$")
37
+ @minLength(1)
38
+ @maxLength(128)
39
+ scalar AgentDiagnosticVariableName extends string;
40
+
41
+ @doc("Execution boundary at which the state frame was captured.")
42
+ enum AgentDiagnosticPhase {
43
+ input: "input",
44
+ output: "output",
45
+ error: "error",
46
+ checkpoint: "checkpoint",
47
+ }
48
+
49
+ @doc("Machine-computed aggregate result of a diagnostic snapshot. unknown reports one or more unknown check outcomes. not_evaluated is reserved for a snapshot whose checks array is empty.")
50
+ enum AgentDiagnosticOutcome {
51
+ pass: "pass",
52
+ fail: "fail",
53
+ unknownResult: "unknown",
54
+ notEvaluated: "not_evaluated",
55
+ }
56
+
57
+ @doc("Machine-computed result of one diagnostic check. For exists, an absent or null actual variable produces fail. For every other operator, missing required operands produce unknown; incompatible operand types also produce unknown. not_evaluated is deliberately not a check outcome.")
58
+ enum AgentDiagnosticCheckOutcome {
59
+ pass: "pass",
60
+ fail: "fail",
61
+ unknownResult: "unknown",
62
+ }
63
+
64
+ @doc("Declared JSON-level type of a diagnostic variable.")
65
+ enum AgentDiagnosticValueType {
66
+ null: "null",
67
+ boolean: "boolean",
68
+ integer: "integer",
69
+ number: "number",
70
+ string: "string",
71
+ json: "json",
72
+ }
73
+
74
+ @doc("Data-handling classification assigned before a diagnostic variable is captured.")
75
+ enum AgentDiagnosticClassification {
76
+ public: "public",
77
+ internal: "internal",
78
+ sensitive: "sensitive",
79
+ secret: "secret",
80
+ }
81
+
82
+ @doc("Closed operation evaluated by a diagnostic check. Checks are structural and never carry expression strings.")
83
+ enum AgentDiagnosticOperator {
84
+ equal: "equal",
85
+ notEqual: "not_equal",
86
+ exists: "exists",
87
+ typeIs: "type_is",
88
+ contains: "contains",
89
+ lessThan: "less_than",
90
+ greaterThan: "greater_than",
91
+ }
92
+
93
+ @doc("Common identity and policy fields for one dynamic diagnostic variable.")
94
+ model AgentDiagnosticVariableBase {
95
+ name: AgentDiagnosticVariableName;
96
+ type: AgentDiagnosticValueType;
97
+ classification: AgentDiagnosticClassification;
98
+ }
99
+
100
+ @doc("A variable whose typed JSON value is present in protected snapshot content. The value is required and must match type: null is JSON null; boolean is a JSON boolean; integer is a signed 64-bit JSON integer; number is a finite JSON number; string is a JSON string; json is a JSON object or array. The protected content boundary, not this model, controls access to all captured values.")
101
+ model CapturedAgentDiagnosticVariable extends AgentDiagnosticVariableBase {
102
+ capture: "value";
103
+ value: unknown | null;
104
+ }
105
+
106
+ @doc("A variable observed by the probe whose value was replaced by policy. A value field is forbidden.")
107
+ model RedactedAgentDiagnosticVariable extends AgentDiagnosticVariableBase {
108
+ capture: "redacted";
109
+ }
110
+
111
+ @doc("A variable whose value was unavailable or deliberately not captured. A value field is forbidden.")
112
+ model OmittedAgentDiagnosticVariable extends AgentDiagnosticVariableBase {
113
+ capture: "omitted";
114
+ }
115
+
116
+ @doc("One dynamically named variable in a protected diagnostic snapshot. Capture is the discriminator and makes value presence unambiguous.")
117
+ union AgentDiagnosticVariable {
118
+ value: CapturedAgentDiagnosticVariable,
119
+ redacted: RedactedAgentDiagnosticVariable,
120
+ omitted: OmittedAgentDiagnosticVariable,
121
+ }
122
+
123
+ @doc("One structural, machine-computed check result. actual and expected reference variable names only. For equal, not_equal, contains, less_than, and greater_than, expected is required and expected_type is omitted. For exists, both are omitted and an absent or null actual variable produces fail. For type_is, expected is omitted and expected_type is required. For operators other than exists, missing required operands produce unknown; incompatible operand types also produce unknown. not_evaluated is reserved for the snapshot aggregate when checks is empty and is not emitted for an individual check.")
124
+ model AgentDiagnosticCheckResult {
125
+ @encodedName("application/json", "check_id")
126
+ checkId: AgentDiagnosticCheckId;
127
+
128
+ operator: AgentDiagnosticOperator;
129
+ actual: AgentDiagnosticVariableName;
130
+ expected?: AgentDiagnosticVariableName;
131
+
132
+ @encodedName("application/json", "expected_type")
133
+ expectedType?: AgentDiagnosticValueType;
134
+
135
+ outcome: AgentDiagnosticCheckOutcome;
136
+ }
137
+
138
+ @doc("Version 1 protected JSON state frame captured for an artificial-intelligence agent. extension_id and format_version are its schema identity. capture_nonce is fresh entropy and is not a stable identifier. Variables and checks are bounded, dynamic names remain values, and no human-oriented message or expression text is part of the contract. Overall outcome is not_evaluated only when checks is empty. For a non-empty checks array it is fail if any check fails, otherwise unknown if any check is unknown, otherwise pass.")
139
+ model AgentDiagnosticSnapshot {
140
+ @encodedName("application/json", "extension_id")
141
+ extensionId: AgentDiagnosticExtensionId;
142
+
143
+ @encodedName("application/json", "format_version")
144
+ formatVersion: AgentDiagnosticFormatVersion;
145
+
146
+ @encodedName("application/json", "snapshot_id")
147
+ snapshotId: AgentDiagnosticSnapshotId;
148
+
149
+ @doc("Fresh 128-bit random nonce encoded as exactly 32 lowercase hexadecimal characters. It prevents equality inference across otherwise identical protected captures and must not be used as an identity key.")
150
+ @encodedName("application/json", "capture_nonce")
151
+ @pattern("^[0-9a-f]{32}$")
152
+ @minLength(32)
153
+ @maxLength(32)
154
+ captureNonce: string;
155
+
156
+ @encodedName("application/json", "probe_id")
157
+ probeId: AgentDiagnosticProbeId;
158
+
159
+ phase: AgentDiagnosticPhase;
160
+
161
+ @maxItems(64)
162
+ variables: AgentDiagnosticVariable[];
163
+
164
+ @maxItems(64)
165
+ checks: AgentDiagnosticCheckResult[];
166
+
167
+ outcome: AgentDiagnosticOutcome;
168
+ }
169
+
170
+ @doc("Value-free event-data projection for a protected agent diagnostic snapshot. Encode this shape in WorkflowEventAppend.data on the existing content_captured event kind. content_ref must also occur in that event's content_refs and identifies UTF-8 JSON conforming to AgentDiagnosticSnapshot. Counts are computed from the referenced snapshot; failed_check_count counts checks whose outcome is fail. No variable names, values, human messages, expressions, nonce, or classifications may appear in this summary.")
171
+ model AgentDiagnosticSnapshotSummary {
172
+ @encodedName("application/json", "extension_id")
173
+ extensionId: AgentDiagnosticExtensionId;
174
+
175
+ @encodedName("application/json", "format_version")
176
+ formatVersion: AgentDiagnosticFormatVersion;
177
+
178
+ @encodedName("application/json", "snapshot_id")
179
+ snapshotId: AgentDiagnosticSnapshotId;
180
+
181
+ @encodedName("application/json", "probe_id")
182
+ probeId: AgentDiagnosticProbeId;
183
+
184
+ phase: AgentDiagnosticPhase;
185
+ outcome: AgentDiagnosticOutcome;
186
+
187
+ @encodedName("application/json", "variable_count")
188
+ @minValue(0)
189
+ @maxValue(64)
190
+ variableCount: int32;
191
+
192
+ @encodedName("application/json", "check_count")
193
+ @minValue(0)
194
+ @maxValue(64)
195
+ checkCount: int32;
196
+
197
+ @encodedName("application/json", "failed_check_count")
198
+ @minValue(0)
199
+ @maxValue(64)
200
+ failedCheckCount: int32;
201
+
202
+ @encodedName("application/json", "content_ref")
203
+ contentRef: WorkflowContentRef;
204
+ }
@@ -1,10 +1,12 @@
1
1
  import "../common/types.tsp";
2
2
  import "../otel/logs.tsp";
3
3
  import "../otel/span.tsp";
4
+ import "./diagnostics.tsp";
4
5
  import "./session.tsp";
5
6
  import "./workflow.tsp";
6
7
 
7
8
  using Qyl.Api.Contracts.Common;
9
+ using Qyl.Api.Contracts.Diagnostics;
8
10
  using Qyl.Api.Contracts.Domains.Observe.Session;
9
11
  using Qyl.Api.Contracts.OTel.Logs;
10
12
  using Qyl.Api.Contracts.OTel.Traces;
@@ -218,11 +220,82 @@ model FetchTelemetryOutput {
218
220
  mode: McpDataMode;
219
221
  }
220
222
 
223
+ @doc("Input for get_active_workflow_run.")
224
+ model GetActiveWorkflowRunInput {}
225
+
226
+ @doc("Structured output for get_active_workflow_run.")
227
+ model GetActiveWorkflowRunOutput {
228
+ active: boolean;
229
+
230
+ @encodedName("application/json", "live_controls_available")
231
+ liveControlsAvailable: boolean;
232
+
233
+ @encodedName("application/json", "run_id")
234
+ runId?: WorkflowRunId;
235
+
236
+ @encodedName("application/json", "thread_id")
237
+ threadId?: string;
238
+
239
+ @encodedName("application/json", "started_at")
240
+ startedAt?: utcDateTime;
241
+ }
242
+
243
+ @doc("One dynamically named JSON value submitted for protected diagnostic capture. Classification is applied before the frame leaves the observer bridge.")
244
+ model RecordDiagnosticSnapshotVariableInput {
245
+ name: AgentDiagnosticVariableName;
246
+ classification: AgentDiagnosticClassification;
247
+ value: unknown | null;
248
+ }
249
+
250
+ @doc("One structural diagnostic check submitted for evaluation. equal, not_equal, contains, less_than, and greater_than require expected and forbid expected_type; type_is requires expected_type and forbids expected; exists forbids both.")
251
+ model RecordDiagnosticSnapshotCheckInput {
252
+ @encodedName("application/json", "check_id")
253
+ checkId: AgentDiagnosticCheckId;
254
+
255
+ operator: AgentDiagnosticOperator;
256
+ actual: AgentDiagnosticVariableName;
257
+ expected?: AgentDiagnosticVariableName;
258
+
259
+ @encodedName("application/json", "expected_type")
260
+ expectedType?: AgentDiagnosticValueType;
261
+ }
262
+
263
+ @doc("Input for record_diagnostic_snapshot. Reuse the same snapshot_id and semantic payload when retrying; changing the payload under an existing snapshot_id is a conflict.")
264
+ model RecordDiagnosticSnapshotInput {
265
+ @encodedName("application/json", "snapshot_id")
266
+ snapshotId: AgentDiagnosticSnapshotId;
267
+
268
+ @encodedName("application/json", "probe_id")
269
+ probeId: AgentDiagnosticProbeId;
270
+
271
+ phase: AgentDiagnosticPhase;
272
+
273
+ @maxItems(64)
274
+ variables: RecordDiagnosticSnapshotVariableInput[];
275
+
276
+ @maxItems(64)
277
+ checks?: RecordDiagnosticSnapshotCheckInput[] = #[];
278
+ }
279
+
280
+ @doc("Structured output for record_diagnostic_snapshot.")
281
+ model RecordDiagnosticSnapshotOutput {
282
+ recorded: boolean;
283
+ code: string;
284
+
285
+ @encodedName("application/json", "snapshot_id")
286
+ snapshotId: AgentDiagnosticSnapshotId;
287
+
288
+ @encodedName("application/json", "event_id")
289
+ eventId?: WorkflowEventId;
290
+
291
+ field?: string;
292
+ }
293
+
221
294
  @doc("Input for list_workflow_runs.")
222
295
  model ListWorkflowRunsInput {
223
296
  status?: WorkflowRunStatus;
224
297
 
225
- cursor?: string;
298
+ cursor?: WorkflowRunCursor;
226
299
 
227
300
  @minValue(1)
228
301
  @maxValue(100)
@@ -234,7 +307,7 @@ model ListWorkflowRunsOutput {
234
307
  runs: WorkflowRun[];
235
308
 
236
309
  @encodedName("application/json", "next_cursor")
237
- nextCursor?: string;
310
+ nextCursor?: WorkflowRunCursor;
238
311
 
239
312
  @encodedName("application/json", "has_more")
240
313
  hasMore: boolean;
@@ -247,16 +320,18 @@ model GetWorkflowGraphInput {
247
320
  @encodedName("application/json", "run_id")
248
321
  runId: WorkflowRunId;
249
322
 
323
+ @doc("Opaque node continuation. Reuse it unchanged from the preceding snapshot's next_node_cursor; do not parse, construct, or modify it.")
250
324
  @encodedName("application/json", "node_cursor")
251
- nodeCursor?: string;
325
+ nodeCursor?: WorkflowNodeCursor;
252
326
 
253
327
  @encodedName("application/json", "node_limit")
254
328
  @minValue(1)
255
329
  @maxValue(1000)
256
330
  nodeLimit?: int32 = 250;
257
331
 
332
+ @doc("Opaque edge continuation. Reuse it unchanged from the preceding snapshot's next_edge_cursor; do not parse, construct, or modify it.")
258
333
  @encodedName("application/json", "edge_cursor")
259
- edgeCursor?: string;
334
+ edgeCursor?: WorkflowEdgeCursor;
260
335
 
261
336
  @encodedName("application/json", "edge_limit")
262
337
  @minValue(1)
@@ -275,16 +350,18 @@ model DisplayWorkflowGraphInput {
275
350
  @encodedName("application/json", "run_id")
276
351
  runId?: WorkflowRunId;
277
352
 
353
+ @doc("Opaque node continuation. Reuse it unchanged from the preceding snapshot's next_node_cursor; do not parse, construct, or modify it.")
278
354
  @encodedName("application/json", "node_cursor")
279
- nodeCursor?: string;
355
+ nodeCursor?: WorkflowNodeCursor;
280
356
 
281
357
  @encodedName("application/json", "node_limit")
282
358
  @minValue(1)
283
359
  @maxValue(1000)
284
360
  nodeLimit?: int32 = 250;
285
361
 
362
+ @doc("Opaque edge continuation. Reuse it unchanged from the preceding snapshot's next_edge_cursor; do not parse, construct, or modify it.")
286
363
  @encodedName("application/json", "edge_cursor")
287
- edgeCursor?: string;
364
+ edgeCursor?: WorkflowEdgeCursor;
288
365
 
289
366
  @encodedName("application/json", "edge_limit")
290
367
  @minValue(1)
@@ -308,7 +385,7 @@ model FetchWorkflowGraphUpdatesInput {
308
385
  runId: WorkflowRunId;
309
386
 
310
387
  @encodedName("application/json", "after_sequence")
311
- afterSequence: WorkflowSequence;
388
+ afterSequence: WorkflowJournalPosition;
312
389
 
313
390
  @minValue(1)
314
391
  @maxValue(1000)
@@ -319,16 +396,18 @@ model FetchWorkflowGraphUpdatesInput {
319
396
  @maxValue(30000)
320
397
  waitMs?: int32 = 20000;
321
398
 
399
+ @doc("Opaque node continuation. Reuse it unchanged from the preceding snapshot's next_node_cursor; do not parse, construct, or modify it.")
322
400
  @encodedName("application/json", "node_cursor")
323
- nodeCursor?: string;
401
+ nodeCursor?: WorkflowNodeCursor;
324
402
 
325
403
  @encodedName("application/json", "node_limit")
326
404
  @minValue(1)
327
405
  @maxValue(1000)
328
406
  nodeLimit?: int32 = 250;
329
407
 
408
+ @doc("Opaque edge continuation. Reuse it unchanged from the preceding snapshot's next_edge_cursor; do not parse, construct, or modify it.")
330
409
  @encodedName("application/json", "edge_cursor")
331
- edgeCursor?: string;
410
+ edgeCursor?: WorkflowEdgeCursor;
332
411
 
333
412
  @encodedName("application/json", "edge_limit")
334
413
  @minValue(1)
@@ -348,6 +427,30 @@ model FetchWorkflowGraphUpdatesOutput {
348
427
  mode: McpDataMode;
349
428
  }
350
429
 
430
+ @doc("Input for inspect_workflow_events.")
431
+ model InspectWorkflowEventsInput {
432
+ @encodedName("application/json", "run_id")
433
+ runId: WorkflowRunId;
434
+
435
+ @encodedName("application/json", "after_sequence")
436
+ afterSequence: WorkflowJournalPosition;
437
+
438
+ @minValue(1)
439
+ @maxValue(1000)
440
+ limit?: int32 = 250;
441
+
442
+ @doc("Optional captured payload to retrieve lazily for the selected run.")
443
+ @encodedName("application/json", "content_ref")
444
+ contentRef?: WorkflowContentRef;
445
+ }
446
+
447
+ @doc("Structured output for inspect_workflow_events.")
448
+ model InspectWorkflowEventsOutput {
449
+ page: WorkflowEventPage;
450
+ content?: WorkflowContent;
451
+ mode: McpDataMode;
452
+ }
453
+
351
454
  @doc("Input for control_workflow_run.")
352
455
  model ControlWorkflowRunInput {
353
456
  @encodedName("application/json", "run_id")
@@ -9,6 +9,17 @@ namespace Qyl.Api.Contracts.Workflow;
9
9
  @maxLength(128)
10
10
  scalar WorkflowRunId extends string;
11
11
 
12
+ @doc("Opaque incarnation identifier for one workflow run's projected state.")
13
+ @pattern("^[0-9a-f]{12}4[0-9a-f]{3}[89ab][0-9a-f]{15}$")
14
+ @minLength(32)
15
+ @maxLength(32)
16
+ scalar WorkflowGeneration extends string;
17
+
18
+ @doc("Opaque workflow-run list continuation scoped to the project and status filter. Reuse it unchanged; clients must not parse or construct it.")
19
+ @minLength(1)
20
+ @maxLength(512)
21
+ scalar WorkflowRunCursor extends string;
22
+
12
23
  @doc("Stable identifier of one workflow attempt.")
13
24
  @minLength(1)
14
25
  @maxLength(128)
@@ -34,11 +45,26 @@ scalar WorkflowEventId extends string;
34
45
  @maxLength(128)
35
46
  scalar WorkflowCommandId extends string;
36
47
 
37
- @doc("Stable identifier of one graph node.")
48
+ @doc("Stable identifier of one graph node. Canonical tuples structurally distinguish run scope from attempt scope, escape colon as \\c and backslash as \\\\, and never infer scope from a literal component value. A canonical identifier over 192 Unicode scalar values is replaced by its kind, a tilde, and the full lowercase 64-hex SHA-256 of the length-prefixed canonical tuple.")
38
49
  @minLength(1)
39
50
  @maxLength(192)
40
51
  scalar WorkflowNodeId extends string;
41
52
 
53
+ @doc("Stable identifier of one graph edge. Endpoint tuples preserve the nodes' structural run-versus-attempt scope and ordinal component boundaries, escape colon as \\c and backslash as \\\\, and never infer scope from a literal component value. A canonical identifier over 192 Unicode scalar values is replaced by its edge kind, a tilde, and the full lowercase 64-hex SHA-256 of the length-prefixed canonical tuple.")
54
+ @minLength(1)
55
+ @maxLength(192)
56
+ scalar WorkflowEdgeId extends string;
57
+
58
+ @doc("Opaque node-page continuation scoped to one workflow run and generation. Reuse it unchanged; clients must not parse or construct it.")
59
+ @minLength(1)
60
+ @maxLength(1536)
61
+ scalar WorkflowNodeCursor extends string;
62
+
63
+ @doc("Opaque edge-page continuation scoped to one workflow run and generation. Reuse it unchanged; clients must not parse or construct it.")
64
+ @minLength(1)
65
+ @maxLength(1536)
66
+ scalar WorkflowEdgeCursor extends string;
67
+
42
68
  @doc("Content-addressed reference to a captured workflow payload.")
43
69
  @pattern("^sha256:[a-f0-9]{64}$")
44
70
  @minLength(71)
@@ -50,6 +76,11 @@ scalar WorkflowContentRef extends string;
50
76
  @encode(string)
51
77
  scalar WorkflowSequence extends uint64;
52
78
 
79
+ @doc("Collector-assigned position in the authoritative workflow journal, encoded without JavaScript precision loss.")
80
+ @minValue(0)
81
+ @encode(string)
82
+ scalar WorkflowJournalPosition extends uint64;
83
+
53
84
  @doc("Current lifecycle of a workflow run.")
54
85
  enum WorkflowRunStatus {
55
86
  active: "active",
@@ -165,11 +196,60 @@ enum WorkflowContentEncoding {
165
196
  base64: "base64",
166
197
  }
167
198
 
199
+ @doc("A valid committed projection that can be served to readers.")
200
+ model CommittedWorkflowProjectionStatus {
201
+ state: "committed";
202
+ generation: WorkflowGeneration;
203
+
204
+ @encodedName("application/json", "journal_position")
205
+ journalPosition: WorkflowJournalPosition;
206
+ }
207
+
208
+ @doc("The requested generation is being reconstructed from its authoritative journal.")
209
+ model RebuildingWorkflowProjectionStatus {
210
+ state: "rebuilding";
211
+ generation: WorkflowGeneration;
212
+
213
+ @encodedName("application/json", "target_journal_position")
214
+ targetJournalPosition: WorkflowJournalPosition;
215
+
216
+ @encodedName("application/json", "retry_after_ms")
217
+ @minValue(1)
218
+ retryAfterMs: int32;
219
+ }
220
+
221
+ @doc("Projection work is temporarily unavailable after a retryable storage failure.")
222
+ model UnavailableWorkflowProjectionStatus {
223
+ state: "unavailable";
224
+ generation?: WorkflowGeneration;
225
+
226
+ @encodedName("application/json", "retry_after_ms")
227
+ @minValue(1)
228
+ retryAfterMs: int32;
229
+ }
230
+
231
+ @doc("Derived projection state is corrupt or incompatible and cannot currently be served.")
232
+ model CorruptWorkflowProjectionStatus {
233
+ state: "corrupt";
234
+ generation?: WorkflowGeneration;
235
+ reason: "corrupt_derived_state" | "incompatible_derived_state";
236
+ }
237
+
238
+ @doc("Closed public availability state for one workflow projection. Storage paths, hashes, fingerprints, and database errors remain private.")
239
+ union WorkflowProjectionStatus {
240
+ committed: CommittedWorkflowProjectionStatus,
241
+ rebuilding: RebuildingWorkflowProjectionStatus,
242
+ unavailable: UnavailableWorkflowProjectionStatus,
243
+ corrupt: CorruptWorkflowProjectionStatus,
244
+ }
245
+
168
246
  @doc("One immutable workflow run.")
169
247
  model WorkflowRun {
170
248
  @encodedName("application/json", "run_id")
171
249
  runId: WorkflowRunId;
172
250
 
251
+ generation: WorkflowGeneration;
252
+
173
253
  @encodedName("application/json", "thread_id")
174
254
  threadId?: string;
175
255
 
@@ -183,7 +263,7 @@ model WorkflowRun {
183
263
  endedAt?: utcDateTime;
184
264
 
185
265
  @encodedName("application/json", "latest_journal_sequence")
186
- latestJournalSequence: WorkflowSequence;
266
+ latestJournalSequence: WorkflowJournalPosition;
187
267
 
188
268
  @encodedName("application/json", "active_attempt_id")
189
269
  activeAttemptId?: WorkflowAttemptId;
@@ -212,7 +292,7 @@ model WorkflowRunPage {
212
292
  items: WorkflowRun[];
213
293
 
214
294
  @encodedName("application/json", "next_cursor")
215
- nextCursor?: string;
295
+ nextCursor?: WorkflowRunCursor;
216
296
 
217
297
  @encodedName("application/json", "has_more")
218
298
  hasMore: boolean;
@@ -301,10 +381,10 @@ model WorkflowEventBatchAppendResponse {
301
381
  acknowledgedSourceSequence: WorkflowSequence;
302
382
 
303
383
  @encodedName("application/json", "first_journal_sequence")
304
- firstJournalSequence?: WorkflowSequence;
384
+ firstJournalSequence?: WorkflowJournalPosition;
305
385
 
306
386
  @encodedName("application/json", "last_journal_sequence")
307
- lastJournalSequence?: WorkflowSequence;
387
+ lastJournalSequence?: WorkflowJournalPosition;
308
388
  }
309
389
 
310
390
  @doc("One immutable event after collector journal sequence assignment.")
@@ -316,7 +396,7 @@ model WorkflowJournalEvent extends WorkflowEventAppend {
316
396
  clientId: string;
317
397
 
318
398
  @encodedName("application/json", "journal_sequence")
319
- journalSequence: WorkflowSequence;
399
+ journalSequence: WorkflowJournalPosition;
320
400
  }
321
401
 
322
402
  @doc("A bounded page of workflow journal events.")
@@ -324,10 +404,10 @@ model WorkflowEventPage {
324
404
  events: WorkflowJournalEvent[];
325
405
 
326
406
  @encodedName("application/json", "next_sequence")
327
- nextSequence: WorkflowSequence;
407
+ nextSequence: WorkflowJournalPosition;
328
408
 
329
409
  @encodedName("application/json", "high_water_mark")
330
- highWaterMark: WorkflowSequence;
410
+ highWaterMark: WorkflowJournalPosition;
331
411
 
332
412
  @encodedName("application/json", "cursor_gap")
333
413
  cursorGap: boolean;
@@ -390,10 +470,10 @@ model WorkflowGraphNode {
390
470
  attributes?: Record<unknown>;
391
471
  }
392
472
 
393
- @doc("One typed edge in the deterministic workflow graph projection.")
473
+ @doc("One typed edge in the deterministic workflow graph projection. Data, Control, and Gate edges are causal dependencies. Temporal edges describe observed order, Resource edges describe resource use, and Conflict edges describe contention; Temporal, Resource, and Conflict edges are excluded from critical-path causality.")
394
474
  model WorkflowGraphEdge {
395
475
  @encodedName("application/json", "edge_id")
396
- edgeId: string;
476
+ edgeId: WorkflowEdgeId;
397
477
 
398
478
  @encodedName("application/json", "source_node_id")
399
479
  sourceNodeId: WorkflowNodeId;
@@ -405,7 +485,7 @@ model WorkflowGraphEdge {
405
485
  provenance: WorkflowEdgeProvenance;
406
486
  }
407
487
 
408
- @doc("Work and critical-path statistics for a workflow graph.")
488
+ @doc("Work and critical-path statistics for a workflow graph. Every ToolCall, Wait, Gate, and duration-bearing Message or Item contributes an independently weighted interval even when it has no Agent owner. An Agent contributes its own-work fragments: its interval minus the union of precisely owned child intervals clipped to the Agent interval. Precisely owned children are Control-linked Agent and ToolCall nodes, Temporal-linked Wait nodes, Gate-linked Gate nodes, and Data-linked duration-bearing Message or Item nodes. Peak concurrency sweeps every positive independently weighted or Agent own-work fragment. Critical-path analysis uses only Data, Control, and Gate edges, condenses each causal strongly connected component, charges every component member exactly once, and expands selected component members in ordinal node-id order.")
409
489
  model WorkflowGraphStatistics {
410
490
  @encodedName("application/json", "t1_ms")
411
491
  t1Ms: DurationMs;
@@ -434,18 +514,23 @@ model WorkflowGraphStatistics {
434
514
  @doc("Deterministic graph projection at one journal cursor.")
435
515
  model WorkflowGraphSnapshot {
436
516
  run: WorkflowRun;
517
+
518
+ @encodedName("application/json", "projection_status")
519
+ projectionStatus: WorkflowProjectionStatus;
437
520
  nodes: WorkflowGraphNode[];
438
521
  edges: WorkflowGraphEdge[];
439
522
  statistics: WorkflowGraphStatistics;
440
523
 
441
524
  @encodedName("application/json", "journal_sequence")
442
- journalSequence: WorkflowSequence;
525
+ journalSequence: WorkflowJournalPosition;
443
526
 
444
527
  @encodedName("application/json", "next_node_cursor")
445
- nextNodeCursor?: string;
528
+ @doc("Opaque node continuation for the next page. Reuse it unchanged as node_cursor on the next graph request; do not parse, construct, or modify it.")
529
+ nextNodeCursor?: WorkflowNodeCursor;
446
530
 
447
531
  @encodedName("application/json", "next_edge_cursor")
448
- nextEdgeCursor?: string;
532
+ @doc("Opaque edge continuation for the next page. Reuse it unchanged as edge_cursor on the next graph request; do not parse, construct, or modify it.")
533
+ nextEdgeCursor?: WorkflowEdgeCursor;
449
534
 
450
535
  @encodedName("application/json", "has_more_nodes")
451
536
  hasMoreNodes: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ancplua/qyl-api-schema",
3
- "version": "6.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "TypeSpec source of truth for qyl API contracts. Emits OpenAPI, JSON Schema, Qyl.Api.Contracts DTOs, and TypeScript contract types; not an OpenTelemetry package, storage schema, or server implementation.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -62,6 +62,7 @@
62
62
  "models/runner.tsp",
63
63
  "models/workbench.tsp",
64
64
  "models/workflow.tsp",
65
+ "models/diagnostics.tsp",
65
66
  "models/mcp-tools.tsp",
66
67
  "models/session.tsp",
67
68
  "otel/enums.tsp",
@@ -87,10 +88,11 @@
87
88
  "build:emitters": "tsc -p emitters/csharp && tsc -p emitters/ts-types && tsc -p emitters/qyl-lint",
88
89
  "build:ts-runtime": "tsc -p tsconfig.contracts.json",
89
90
  "build:json-schema": "node scripts/openapi-to-json-schema.mjs",
91
+ "emit:mcp-tool-schemas": "node scripts/emit-mcp-tool-schemas.mjs",
90
92
  "emit:contract-revision": "node scripts/emit-contract-revision.mjs",
91
93
  "prepare": "npm run build:emitters",
92
94
  "prepack": "npm run compile",
93
- "compile": "npm run clean:generated && npm run build:emitters && tsp compile main.tsp && npm run emit:contract-revision && npm run build:json-schema && npm run build:ts-runtime",
95
+ "compile": "npm run clean:generated && npm run build:emitters && tsp compile main.tsp && npm run emit:contract-revision && npm run build:json-schema && npm run emit:mcp-tool-schemas && npm run build:ts-runtime",
94
96
  "format": "tsp format **/*.tsp",
95
97
  "lint": "npm run build:emitters && tsp compile main.tsp --no-emit --warn-as-error",
96
98
  "lint:public": "npm run build:emitters && tsp compile index.tsp --no-emit --warn-as-error",
@@ -100,11 +102,11 @@
100
102
  },
101
103
  "peerDependencies": {
102
104
  "@typespec/compiler": "^1.13.0 || >=1.13.0-dev.0",
103
- "@typespec/events": "^0.83.0 || ^0.84.0",
105
+ "@typespec/events": "^0.83.0 || ^0.84.0 || ^0.85.0",
104
106
  "@typespec/http": "^1.13.0",
105
107
  "@typespec/openapi": "^1.13.0",
106
108
  "@typespec/openapi3": "^1.13.0",
107
- "@typespec/sse": ">=0.83.0 <0.85.0"
109
+ "@typespec/sse": ">=0.83.0 <0.86.0"
108
110
  },
109
111
  "peerDependenciesMeta": {
110
112
  "@typespec/compiler": {