@ancplua/qyl-api-schema 11.5.0 → 11.6.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.
@@ -2,8 +2,16 @@ import "../common/types.tsp";
2
2
  import "../otel/logs.tsp";
3
3
  import "../otel/span.tsp";
4
4
  import "./session.tsp";
5
+ import "./metrics.tsp";
6
+ import "./annotations.tsp";
7
+ import "./saved-queries.tsp";
8
+ import "../common/resource.tsp";
5
9
 
10
+ using TypeSpec.OpenAPI;
6
11
  using Qyl.Api.Contracts.Common;
12
+ using Qyl.Api.Contracts.Annotations;
13
+ using Qyl.Api.Contracts.SavedQueries;
14
+ using Qyl.Api.Contracts.OTel.Metrics;
7
15
  using Qyl.Api.Contracts.Domains.Observe.Session;
8
16
  using Qyl.Api.Contracts.OTel.Logs;
9
17
  using Qyl.Api.Contracts.OTel.Traces;
@@ -16,6 +24,79 @@ enum McpDataMode {
16
24
  demo: "demo",
17
25
  }
18
26
 
27
+ @doc("""
28
+ OAuth scopes of the qyl MCP server. `qyl:read` alone keeps the read-only
29
+ tool surface; `qyl:write` adds the create and update tools; `qyl:delete`
30
+ adds the one delete tool. No scope deletes telemetry.
31
+ """)
32
+ enum McpScope {
33
+ read: "qyl:read",
34
+ write: "qyl:write",
35
+ delete: "qyl:delete",
36
+ }
37
+
38
+ @doc("Stable failure code of a qyl MCP tool result. A model branches on the code, never on the message.")
39
+ union ToolErrorCode {
40
+ invalidArgument: "invalid_argument",
41
+ notFound: "not_found",
42
+ noProjectAccess: "no_project_access",
43
+ collectorUnreachable: "collector_unreachable",
44
+ collectorTimeout: "collector_timeout",
45
+ cancelled: "cancelled",
46
+ collectorUnauthorized: "collector_unauthorized",
47
+ collectorRateLimited: "collector_rate_limited",
48
+ collectorRejected: "collector_rejected",
49
+ collectorError: "collector_error",
50
+ contractMismatch: "contract_mismatch",
51
+
52
+ @doc("The token lacks the scope the tool needs: qyl:write or qyl:delete.")
53
+ insufficientScope: "insufficient_scope",
54
+
55
+ @doc("HTTP 409: the change conflicts with existing state, e.g. a duplicate saved-query name.")
56
+ conflict: "conflict",
57
+
58
+ @doc("HTTP 412: the etag is stale; re-read the resource and retry with its current etag.")
59
+ preconditionFailed: "precondition_failed",
60
+
61
+ @doc("HTTP 428: the request carried no etag.")
62
+ preconditionRequired: "precondition_required",
63
+
64
+ internal: "internal",
65
+ }
66
+
67
+ @doc("A failed tool call, carried in structuredContent.error.")
68
+ model ToolError {
69
+ code: ToolErrorCode;
70
+
71
+ @doc("Human-readable description of this failure.")
72
+ message: string;
73
+
74
+ @doc("Whether the same call can succeed when repeated unchanged.")
75
+ retryable: boolean;
76
+ }
77
+
78
+ @doc("Pagination members of a paged tool output.")
79
+ model ToolPage {
80
+ @doc("Whether more items exist beyond this page. False only when the result is complete.")
81
+ @encodedName("application/json", "has_more")
82
+ hasMore: boolean;
83
+
84
+ @doc("Pass as `cursor` to the same tool with the same filters for the next page.")
85
+ @encodedName("application/json", "next_cursor")
86
+ nextCursor?: Cursor;
87
+ }
88
+
89
+ @doc("Time-range members of a tool input.")
90
+ model ToolTimeRange {
91
+ @doc("Start of the window (inclusive), RFC 3339.")
92
+ @encodedName("application/json", "start_time")
93
+ startTime?: utcDateTime;
94
+
95
+ @doc("End of the window (exclusive), RFC 3339.")
96
+ @encodedName("application/json", "end_time")
97
+ endTime?: utcDateTime;
98
+ }
99
+
19
100
  @doc("Data projection requested by the app-only fetch_telemetry tool.")
20
101
  enum FetchTelemetryView {
21
102
  traces: "traces",
@@ -26,10 +107,15 @@ enum FetchTelemetryView {
26
107
 
27
108
  @doc("Input for display_traces.")
28
109
  model DisplayTracesInput {
110
+ @doc("Open this trace selected; omit to list recent traces.")
29
111
  @encodedName("application/json", "trace_id")
30
112
  traceId?: TraceId;
113
+
114
+ @doc("List only the traces of this session.")
31
115
  @encodedName("application/json", "session_id")
32
116
  sessionId?: SessionId;
117
+
118
+ @doc("Maximum traces to list.")
33
119
  @minValue(1)
34
120
  @maxValue(100)
35
121
  limit?: int32 = 20;
@@ -38,34 +124,61 @@ model DisplayTracesInput {
38
124
  @doc("Structured output for display_traces.")
39
125
  model DisplayTracesOutput {
40
126
  traces: Trace[];
127
+
41
128
  @encodedName("application/json", "selected_trace_id")
42
129
  selectedTraceId?: TraceId;
130
+
43
131
  mode: McpDataMode;
132
+
133
+ @doc("Set when the call failed.")
134
+ error?: ToolError;
44
135
  }
45
136
 
46
137
  @doc("Input for display_mcp_dashboard.")
47
138
  model DisplayMcpDashboardInput {
139
+ @doc("Window length in whole hours.")
48
140
  @minValue(1)
49
141
  @maxValue(168)
50
- hours?: float64 = 24;
142
+ hours?: int32 = 24;
51
143
  }
52
144
 
53
145
  @doc("Structured output for display_mcp_dashboard.")
54
146
  model DisplayMcpDashboardOutput {
55
147
  stats: McpDashboardStats;
148
+
149
+ @doc("Set when the call failed.")
150
+ error?: ToolError;
56
151
  }
57
152
 
58
153
  @doc("Input for list_traces.")
59
154
  model ListTracesInput {
155
+ @doc("Maximum traces to return in this page.")
60
156
  @minValue(1)
61
157
  @maxValue(100)
62
158
  limit?: int32 = 20;
159
+
160
+ ...ToolTimeRange;
161
+
162
+ @doc("Keep traces with at least one span from this service.")
163
+ @encodedName("application/json", "service_name")
164
+ serviceName?: string;
165
+
166
+ @doc("Keep only traces with at least one error span.")
167
+ @encodedName("application/json", "errors_only")
168
+ errorsOnly?: boolean;
169
+
170
+ @doc("`next_cursor` of a previous list_traces call with the same filters.")
171
+ cursor?: Cursor;
63
172
  }
64
173
 
65
174
  @doc("Structured output for list_traces.")
66
175
  model ListTracesOutput {
67
176
  traces: TraceSummary[];
68
177
  mode: McpDataMode;
178
+ ...ToolPage;
179
+
180
+ @doc("Set when the call failed.")
181
+ error?: ToolError;
69
182
  }
70
183
 
71
184
  @doc("Input for get_trace.")
@@ -92,43 +205,86 @@ model GetTraceInput {
92
205
  model GetTraceOutput {
93
206
  trace: Trace;
94
207
  mode: McpDataMode;
208
+
209
+ @doc("Annotations on the trace and its spans, newest first.")
210
+ annotations?: Annotation[];
211
+
212
+ @doc("Set when the call failed.")
213
+ error?: ToolError;
95
214
  }
96
215
 
97
216
  @doc("Input for list_sessions.")
98
217
  model ListSessionsInput {
218
+ @doc("Maximum sessions to return in this page.")
99
219
  @minValue(1)
100
220
  @maxValue(100)
101
221
  limit?: int32 = 20;
222
+
223
+ @doc("Return only sessions that are still active; omitted or false includes ended sessions.")
102
224
  @encodedName("application/json", "active_only")
103
225
  activeOnly?: boolean;
226
+
227
+ ...ToolTimeRange;
228
+
229
+ @doc("`next_cursor` of a previous list_sessions call with the same filters.")
230
+ cursor?: Cursor;
104
231
  }
105
232
 
106
233
  @doc("Structured output for list_sessions.")
107
234
  model ListSessionsOutput {
108
235
  sessions: SessionEntity[];
109
236
  mode: McpDataMode;
237
+ ...ToolPage;
238
+
239
+ @doc("Annotations on the listed sessions, newest first; each names its session in `target`.")
240
+ annotations?: Annotation[];
241
+
242
+ @doc("Set when the call failed.")
243
+ error?: ToolError;
110
244
  }
111
245
 
112
246
  @doc("Input for search_logs.")
113
247
  model SearchLogsInput {
248
+ @doc("Return only log records correlated with this trace.")
114
249
  @encodedName("application/json", "trace_id")
115
250
  traceId?: TraceId;
251
+
252
+ @doc("Return only log records from this service.")
116
253
  @encodedName("application/json", "service_name")
117
254
  serviceName?: string;
255
+
256
+ @doc("Minimum OpenTelemetry severity number: 9 info, 13 warn, 17 error.")
118
257
  @encodedName("application/json", "severity_min")
119
258
  @minValue(1)
120
259
  @maxValue(24)
121
260
  severityMin?: int32;
261
+
262
+ @doc("Substring searched in the log body.")
122
263
  query?: string;
264
+
265
+ @doc("Maximum log records to return in this page.")
123
266
  @minValue(1)
124
267
  @maxValue(200)
125
268
  limit?: int32 = 50;
269
+
270
+ @doc("Return only log records of this session.")
271
+ @encodedName("application/json", "session_id")
272
+ sessionId?: SessionId;
273
+
274
+ ...ToolTimeRange;
275
+
276
+ @doc("`next_cursor` of a previous search_logs call with the same filters.")
277
+ cursor?: Cursor;
126
278
  }
127
279
 
128
280
  @doc("Structured output for search_logs.")
129
281
  model SearchLogsOutput {
130
282
  logs: LogRecord[];
131
283
  mode: McpDataMode;
284
+ ...ToolPage;
285
+
286
+ @doc("Set when the call failed.")
287
+ error?: ToolError;
132
288
  }
133
289
 
134
290
  @doc("Outcome of one CI phase span, projected from its OpenTelemetry span status.")
@@ -203,28 +359,72 @@ model CiLogOutput {
203
359
  runId?: SessionId;
204
360
 
205
361
  phases?: CiPhase[];
206
-
207
362
  mode: McpDataMode;
363
+
364
+ @doc("Set when the call failed.")
365
+ error?: ToolError;
366
+ }
367
+
368
+ @doc("fetch_telemetry input for the trace list (view `traces`).")
369
+ model FetchTelemetryTracesInput {
370
+ view: "traces";
371
+
372
+ @doc("Return this one trace as the list, selected.")
373
+ @encodedName("application/json", "trace_id")
374
+ traceId?: TraceId;
375
+
376
+ @minValue(1)
377
+ @maxValue(200)
378
+ limit?: int32;
208
379
  }
209
380
 
210
- @doc("Input for the app-only fetch_telemetry tool.")
211
- model FetchTelemetryInput {
212
- view: FetchTelemetryView;
381
+ @doc("fetch_telemetry input for one trace (view `trace`).")
382
+ model FetchTelemetryTraceInput {
383
+ view: "trace";
384
+
385
+ @encodedName("application/json", "trace_id")
386
+ traceId: TraceId;
387
+ }
388
+
389
+ @doc("fetch_telemetry input for log records (view `logs`).")
390
+ model FetchTelemetryLogsInput {
391
+ view: "logs";
392
+
213
393
  @encodedName("application/json", "trace_id")
214
394
  traceId?: TraceId;
395
+
215
396
  @encodedName("application/json", "service_name")
216
397
  serviceName?: string;
398
+
217
399
  @encodedName("application/json", "severity_min")
218
400
  @minValue(1)
219
401
  @maxValue(24)
220
402
  severityMin?: int32;
403
+
221
404
  query?: string;
405
+
222
406
  @minValue(1)
223
407
  @maxValue(200)
224
408
  limit?: int32;
409
+ }
410
+
411
+ @doc("fetch_telemetry input for MCP traffic statistics (view `mcp_stats`).")
412
+ model FetchTelemetryMcpStatsInput {
413
+ view: "mcp_stats";
414
+
415
+ @doc("Window length in whole hours.")
225
416
  @minValue(1)
226
417
  @maxValue(168)
227
- hours?: float64;
418
+ hours?: int32;
419
+ }
420
+
421
+ @doc("Input for the app-only fetch_telemetry tool: exactly one view and the members that view takes.")
422
+ @discriminated(#{ envelope: "none", discriminatorPropertyName: "view" })
423
+ union FetchTelemetryInput {
424
+ traces: FetchTelemetryTracesInput,
425
+ trace: FetchTelemetryTraceInput,
426
+ logs: FetchTelemetryLogsInput,
427
+ mcp_stats: FetchTelemetryMcpStatsInput,
228
428
  }
229
429
 
230
430
  @doc("Structured output for the app-only fetch_telemetry tool.")
@@ -234,6 +434,9 @@ model FetchTelemetryOutput {
234
434
  logs?: LogRecord[];
235
435
  stats?: McpDashboardStats;
236
436
  mode: McpDataMode;
437
+
438
+ @doc("Set when the call failed.")
439
+ error?: ToolError;
237
440
  }
238
441
 
239
442
  @doc("Aggregate MCP traffic statistics shown by qyl.mcp.")
@@ -241,16 +444,22 @@ model McpDashboardStats {
241
444
  window: McpDashboardWindow;
242
445
  buckets: McpDashboardBucket[];
243
446
  totals: McpDashboardTotals;
447
+
244
448
  @encodedName("application/json", "by_server")
245
449
  byServer: McpNameRequestCount[];
450
+
246
451
  @encodedName("application/json", "by_transport")
247
452
  byTransport: McpNameRequestCount[];
453
+
248
454
  @encodedName("application/json", "by_method")
249
455
  byMethod: McpNameRequestCount[];
456
+
250
457
  tools: McpToolStats[];
458
+
251
459
  @encodedName("application/json", "span_count_analyzed")
252
460
  @minValue(0)
253
461
  spanCountAnalyzed: int32;
462
+
254
463
  truncated: boolean;
255
464
  mode: McpDataMode;
256
465
  }
@@ -258,15 +467,19 @@ model McpDashboardStats {
258
467
  model McpDashboardWindow {
259
468
  start: utcDateTime;
260
469
  end: utcDateTime;
470
+
471
+ @doc("Bucket width in integer milliseconds.")
261
472
  @encodedName("application/json", "bucket_ms")
262
473
  @minValue(0)
263
- bucketMs: float64;
474
+ bucketMs: int64;
264
475
  }
265
476
 
266
477
  model McpDashboardBucket {
267
478
  start: utcDateTime;
479
+
268
480
  @minValue(0)
269
481
  requests: int32;
482
+
270
483
  @minValue(0)
271
484
  errors: int32;
272
485
  }
@@ -274,8 +487,10 @@ model McpDashboardBucket {
274
487
  model McpDashboardTotals {
275
488
  @minValue(0)
276
489
  requests: int32;
490
+
277
491
  @minValue(0)
278
492
  errors: int32;
493
+
279
494
  @encodedName("application/json", "error_rate")
280
495
  @minValue(0)
281
496
  @maxValue(1)
@@ -284,24 +499,238 @@ model McpDashboardTotals {
284
499
 
285
500
  model McpNameRequestCount {
286
501
  name: string;
502
+
287
503
  @minValue(0)
288
504
  requests: int32;
289
505
  }
290
506
 
291
507
  model McpToolStats {
292
508
  name: string;
509
+
293
510
  @minValue(0)
294
511
  requests: int32;
512
+
295
513
  @minValue(0)
296
514
  errors: int32;
515
+
297
516
  @encodedName("application/json", "error_rate")
298
517
  @minValue(0)
299
518
  @maxValue(1)
300
519
  errorRate: float64;
520
+
301
521
  @encodedName("application/json", "avg_ms")
302
522
  @minValue(0)
303
523
  avgMs: float64;
524
+
304
525
  @encodedName("application/json", "p95_ms")
305
526
  @minValue(0)
306
527
  p95Ms: float64;
307
528
  }
529
+
530
+ // -----------------------------------------------------------------------------
531
+ // Metric tools: list_metrics, get_metric_series, query_metric
532
+ // -----------------------------------------------------------------------------
533
+
534
+ @doc("Input for list_metrics.")
535
+ model ListMetricsInput {
536
+ @doc("Return only names starting with this prefix.")
537
+ @encodedName("application/json", "name_prefix")
538
+ namePrefix?: string;
539
+
540
+ @minValue(1)
541
+ @maxValue(1000)
542
+ limit?: int32 = 200;
543
+
544
+ @doc("`next_cursor` of a previous list_metrics call with the same prefix.")
545
+ cursor?: Cursor;
546
+ }
547
+
548
+ @doc("Structured output for list_metrics.")
549
+ model ListMetricsOutput {
550
+ items: MetricDescriptor[];
551
+ ...ToolPage;
552
+
553
+ @doc("Set when the call failed.")
554
+ error?: ToolError;
555
+ }
556
+
557
+ @doc("Input for get_metric_series.")
558
+ model GetMetricSeriesInput {
559
+ @encodedName("application/json", "metric_name")
560
+ @minLength(1)
561
+ metricName: string;
562
+
563
+ @doc("Attribute matchers a series must all satisfy; serialized to `attr` and `attr_prefix`.")
564
+ @maxItems(32)
565
+ matchers?: MetricAttributeMatcher[];
566
+
567
+ @minValue(1)
568
+ @maxValue(1000)
569
+ limit?: int32 = 200;
570
+
571
+ @doc("`next_cursor` of a previous get_metric_series call with the same filters.")
572
+ cursor?: Cursor;
573
+ }
574
+
575
+ @doc("Structured output for get_metric_series.")
576
+ model GetMetricSeriesOutput {
577
+ items: MetricSeries[];
578
+ ...ToolPage;
579
+
580
+ @doc("Set when the call failed.")
581
+ error?: ToolError;
582
+ }
583
+
584
+ @doc("Input for query_metric.")
585
+ model QueryMetricInput {
586
+ @encodedName("application/json", "metric_name")
587
+ @minLength(1)
588
+ metricName: string;
589
+
590
+ @encodedName("application/json", "start_time")
591
+ startTime: utcDateTime;
592
+
593
+ @encodedName("application/json", "end_time")
594
+ endTime: utcDateTime;
595
+
596
+ @doc("Bucket width in integer milliseconds.")
597
+ @encodedName("application/json", "step_ms")
598
+ @minValue(1)
599
+ @maxValue(86400000)
600
+ stepMs?: int64 = 60000;
601
+
602
+ aggregation?: MetricAggregation = MetricAggregation.avg;
603
+
604
+ @doc("Attribute keys to split the result by.")
605
+ @encodedName("application/json", "group_by")
606
+ @maxItems(16)
607
+ groupBy?: string[];
608
+
609
+ @doc("Attribute matchers a series must all satisfy; serialized to `attr` and `attr_prefix`.")
610
+ @maxItems(32)
611
+ matchers?: MetricAttributeMatcher[];
612
+
613
+ @encodedName("application/json", "series_limit")
614
+ @minValue(1)
615
+ @maxValue(500)
616
+ seriesLimit?: int32 = 50;
617
+ }
618
+
619
+ @doc("Structured output for query_metric: the collector's range-query result.")
620
+ model QueryMetricOutput {
621
+ ...MetricQueryResult;
622
+
623
+ @doc("Set when the call failed.")
624
+ error?: ToolError;
625
+ }
626
+
627
+ // -----------------------------------------------------------------------------
628
+ // Write tools (scope qyl:write; delete needs qyl:delete)
629
+ // -----------------------------------------------------------------------------
630
+
631
+ @doc("Input for create_annotation.")
632
+ model CreateAnnotationInput {
633
+ ...AnnotationCreateRequest;
634
+ }
635
+
636
+ @doc("Input for update_annotation.")
637
+ model UpdateAnnotationInput {
638
+ id: ResourceId;
639
+
640
+ @doc("The annotation's current `etag`, sent as If-Match.")
641
+ etag: ETag;
642
+
643
+ ...AnnotationUpdateRequest;
644
+ }
645
+
646
+ @doc("Structured output for create_annotation and update_annotation.")
647
+ model AnnotationOutput {
648
+ annotation?: Annotation;
649
+
650
+ @doc("Set when the call failed.")
651
+ error?: ToolError;
652
+ }
653
+
654
+ @doc("Input for create_saved_query.")
655
+ model CreateSavedQueryInput {
656
+ ...SavedQueryCreateRequest;
657
+ }
658
+
659
+ @doc("Input for update_saved_query.")
660
+ model UpdateSavedQueryInput {
661
+ id: ResourceId;
662
+
663
+ @doc("The saved query's current `etag`, sent as If-Match.")
664
+ etag: ETag;
665
+
666
+ ...SavedQueryUpdateRequest;
667
+ }
668
+
669
+ @doc("Structured output for create_saved_query and update_saved_query.")
670
+ model SavedQueryOutput {
671
+ @encodedName("application/json", "saved_query")
672
+ savedQuery?: SavedQuery;
673
+
674
+ @doc("Set when the call failed.")
675
+ error?: ToolError;
676
+ }
677
+
678
+ @doc("Input for list_saved_queries.")
679
+ model ListSavedQueriesInput {
680
+ signal?: SavedQuerySignal;
681
+
682
+ @minValue(1)
683
+ @maxValue(100)
684
+ limit?: int32 = 20;
685
+
686
+ cursor?: Cursor;
687
+ }
688
+
689
+ @doc("Structured output for list_saved_queries.")
690
+ model ListSavedQueriesOutput {
691
+ @encodedName("application/json", "saved_queries")
692
+ savedQueries: SavedQuery[];
693
+
694
+ ...ToolPage;
695
+
696
+ @doc("Set when the call failed.")
697
+ error?: ToolError;
698
+ }
699
+
700
+ @doc("Input for run_saved_query.")
701
+ model RunSavedQueryInput {
702
+ id: ResourceId;
703
+ ...SavedQueryRunRequest;
704
+ }
705
+
706
+ @doc("Structured output for run_saved_query.")
707
+ model RunSavedQueryOutput {
708
+ result?: SavedQueryRunResult;
709
+ mode?: McpDataMode;
710
+
711
+ @doc("Set when the call failed.")
712
+ error?: ToolError;
713
+ }
714
+
715
+ @doc("The user-created resource kinds the delete tool accepts.")
716
+ enum DeletableKind {
717
+ annotation: "annotation",
718
+ savedQuery: "saved_query",
719
+ }
720
+
721
+ @doc("Input for the delete tool. Telemetry is never deletable.")
722
+ model DeleteInput {
723
+ kind: DeletableKind;
724
+ id: ResourceId;
725
+
726
+ @doc("The resource's current `etag`, sent as If-Match.")
727
+ etag: ETag;
728
+ }
729
+
730
+ @doc("Structured output for the delete tool.")
731
+ model DeleteOutput {
732
+ deleted: boolean;
733
+
734
+ @doc("Set when the call failed.")
735
+ error?: ToolError;
736
+ }