@lionhummer/constellation 0.3.0 → 0.4.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 CHANGED
@@ -94,6 +94,10 @@ Each invocation creates a new request. For application retries, persist the comp
94
94
  | `waiting` | Handle the pending input. Tools always require a consumer; wait checkpoints do too. SSE observation does not answer inputs. |
95
95
  | `failed` | Inspect `request.reason`, `request.error`, attempts and timeline for provider, routing or deadline failure. |
96
96
 
97
+ ## Release 0.4.0
98
+
99
+ Telemetry now returns metadata by default. Use `include: "content"` for full content, with the same permission/scope. Adds key-aware `discover`, explicit request timings, accurate endpoint filter types, HTTP chunk pagination, and billing/traffic methods. Deploy the matching server before using these methods.
100
+
97
101
  ## Release 0.3.0
98
102
 
99
103
  This pre-1.0 release breaks the earlier SDK contract. Use namespaced execution methods; flat aliases and the old drive/protocol surface are removed. Keys, credentials, users and capacity administration are internal-only. Provider-definition writes also require an internal operator. External telemetry and other registry authoring remain available. Deploy a server containing these API changes before switching clients; publishing this package does not deploy the server or upgrade any downstream application dependency.
@@ -156,3 +160,44 @@ Use the documented namespaces throughout: `requests.create`, `requests.get`,
156
160
  `requests.streamEvents`, `inputs.claim`, `inputs.respond`, `spans.start`,
157
161
  `spans.add`, and `logs.add`. Their implementation helpers are private; flat
158
162
  method aliases are not part of the client API.
163
+
164
+ ## Caller failures and delivery retries
165
+
166
+ A failed webhook delivery is one attempt, not the final request outcome. Constellation retains failed attempts even when a later retry succeeds. Retryable delivery warnings include the input ID, attempt number, callback HTTP failure and retry delay; terminal failures remain errors. The callback drawer shows that delivery and the current request state.
167
+
168
+ The SDK records checkpoint and tool exceptions in `attributes.error` on the caller span and preserves the original exception. Root-cause name, bounded message and optional code are included; SQL dumps, stack traces and arbitrary error object fields are omitted, and common credential forms are redacted. This is best-effort redaction: keep sensitive values out of exception messages. Closed error spans with these details produce one linked request error log. Keep complete diagnostics in your application's own logs. Historical spans without error attributes cannot reconstruct the original exception.
169
+
170
+ ## Discover available HTTP operations
171
+
172
+ ```ts
173
+ const contract = await client.discover();
174
+ console.log(contract["x-constellation-access"]);
175
+ console.log(Object.keys(contract.paths));
176
+ ```
177
+
178
+ `discover(signal?)` calls `GET /v1/discover` with the client's bearer key and returns a typed OpenAPI document filtered to that key's permissions and workspace/user scope. It works with execution, management or telemetry keys. `/v1/openapi.json` is the secondary HTTP path. This describes available operations; resource ownership, model access and request lifecycle are still validated when calling them. Discovery does not grant additional access. Requires a server with the discovery endpoint deployed.
179
+
180
+ ## Scoped telemetry and timing
181
+
182
+ Telemetry returns metadata by default: request identity/status, timestamps, costs, token counts, attempt commitment/fallback flags and record metadata. Full request/log/HTTP content requires `include: "content"`; this uses the same telemetry permission and key scope, with no extra permission. SDK content fields are optional because the default omits them. Workspace and user scope applies to hot and archived requests, events, records, HTTP, timing and timeline navigation. Global telemetry endpoints require an unscoped key.
183
+
184
+ ```typescript
185
+ const page = await client.telemetry.requests.list({ externalId: "thread-123", limit: 25 });
186
+ for (const request of page.items) {
187
+ const timing = await client.telemetry.requests.getTimings(request.id);
188
+ console.log(request.status, timing.queueMs, timing.attempts);
189
+ }
190
+ const detail = await client.telemetry.requests.get(requestId, { include: "content" });
191
+ const logs = await client.telemetry.requests.listRecords(requestId, "logs", {
192
+ level: "warn", offset: 0, limit: 25, include: "content",
193
+ });
194
+ const body = await client.telemetry.requests.getHttpBody(requestId, attemptId, {
195
+ direction: "response", offset: 0, limit: 16384, include: "content",
196
+ });
197
+ ```
198
+
199
+ `requests.getTimings` is also available with execution authority. Timing responses include admission, queue, worker preparation, provider attempts and caller waits. Admission and preparation have recorded child/detail spans; IDs and provenance match the console. Concurrent waits count once in `callerWaitMs`. Missing/incomplete measurements are null. Read `complete`, `truncated` and `asOf`; grouped totals can overlap and are not additive.
200
+
201
+ Request lists accept `RequestListQuery`, including exact `externalId` and requested-model filters, exclusions and substring matches. Record lists accept `RequestRecordsQuery` (`id`, `q`, log-only `level`, `offset`, `limit`). `PageQuery.filters` belongs only to registry list rows. Every other method has its endpoint's exact query type. See the [HTTP filter matrix](../../docs/api.md#filter-audit-and-exact-query-support) for search semantics, caps, cursor behavior and capabilities not currently provided.
202
+
203
+ Unscoped telemetry also exposes `observability.getBilling`, `getTraffic`, `getTiming`, dashboard and measurement series. Use `providerId` for local series and `upstream` for gateway series. `system.getComponent(component, { status, statusNot, q, offset })` and `jobs.listHistory` page matching operational records; notifications use fixed 25-item pages and status/offset, not generic filters.
package/dist/index.js CHANGED
@@ -1,4 +1,22 @@
1
- // ../../packages/client-core/src/index.ts
1
+ // ../client-core/src/error-details.ts
2
+ function callerErrorDetails(error) {
3
+ let cause = error;
4
+ const seen = new Set;
5
+ for (let depth = 0;depth < 8 && cause instanceof Error && !seen.has(cause); depth++) {
6
+ seen.add(cause);
7
+ if (!(cause.cause instanceof Error))
8
+ break;
9
+ cause = cause.cause;
10
+ }
11
+ const record = cause && typeof cause === "object" ? cause : {};
12
+ const name = cause instanceof Error ? cause.name.slice(0, 80) : "CallerError";
13
+ const code = typeof record.code === "string" && /^[a-zA-Z0-9_-]{1,80}$/.test(record.code) ? record.code : undefined;
14
+ const raw = cause instanceof Error ? cause.message : "Caller handler threw a non-Error value";
15
+ const message = (/Failed query:|\bparams:/i.test(raw) ? "Caller database operation failed; see caller logs" : raw).replace(/\b(?:Bearer\s+)[^\s,;]+/gi, "Bearer [redacted]").replace(/((?:password|token|secret|api[_-]?key)\s*[=:]\s*)[^\s,;]+/gi, "$1[redacted]").replace(/(https?:\/\/)[^\s/@]+:[^\s/@]+@/gi, "$1[redacted]@").slice(0, 512);
16
+ return { name, message, ...code ? { code } : {} };
17
+ }
18
+
19
+ // ../client-core/src/index.ts
2
20
  class ConstellationError extends Error {
3
21
  status;
4
22
  code;
@@ -306,7 +324,7 @@ class RequestClient {
306
324
  await this.#respond(id, pending.id, { ...response, claimId: consumerId }, activeSignal);
307
325
  } catch (error) {
308
326
  if (!activeSignal?.aborted && !closed)
309
- await span.end({ status: "error" }, activeSignal).catch(() => {});
327
+ await span.end({ status: "error", attributes: { error: callerErrorDetails(error) } }, activeSignal).catch(() => {});
310
328
  throw error;
311
329
  }
312
330
  }, options.signal);
@@ -347,6 +365,7 @@ class RequestClient {
347
365
  const span = await this.#startSpan(id, `tool.${pending.payload.name}`, { stepId: pending.stepId ?? undefined, inputId: pending.id }, activeSignal);
348
366
  let result;
349
367
  let isError = false;
368
+ let errorDetails;
350
369
  try {
351
370
  if (pending.payload.validationError)
352
371
  throw new Error(pending.payload.validationError);
@@ -361,9 +380,10 @@ class RequestClient {
361
380
  } catch (error) {
362
381
  activeSignal?.throwIfAborted();
363
382
  isError = true;
383
+ errorDetails = callerErrorDetails(error);
364
384
  result = { error: error instanceof Error ? error.message : "Tool failed" };
365
385
  }
366
- await span.end({ status: isError ? "error" : "ok" }, activeSignal);
386
+ await span.end({ status: isError ? "error" : "ok", ...errorDetails ? { attributes: { error: errorDetails } } : {} }, activeSignal);
367
387
  await this.#claim(id, pending.id, consumerId, activeSignal);
368
388
  await this.#respond(id, pending.id, { result, isError, claimId: consumerId }, activeSignal);
369
389
  }, options.signal);
@@ -389,13 +409,16 @@ class RequestClient {
389
409
  preview: (input, signal) => this.#resolve(input, signal),
390
410
  get: (id, signal) => this.#inspect(id, signal),
391
411
  getSummary: (id, signal) => this.#inspectSummary(id, signal),
412
+ getTimings: (id, signal) => this.#call(`/v1/requests/${encodeURIComponent(id)}/timings`, "GET", undefined, signal),
392
413
  list: (query = {}, signal) => this.#list(query, signal),
393
414
  cancel: (id, signal) => this.#cancel(id, signal),
394
415
  listEvents: (id, after = 0, signal) => this.#call(`/v1/requests/${encodeURIComponent(id)}/events${queryString({ after })}`, "GET", undefined, signal),
395
416
  streamEvents: (id, options = {}) => this.#events(id, options),
396
417
  listRecords: (id, kind, query = {}, signal) => this.#records(id, kind, query, signal),
397
418
  getTimeline: (id, options = {}) => this.#timeline(id, options),
398
- getHttpExchange: (id, attemptId, signal) => this.#call(`/v1/requests/${encodeURIComponent(id)}/http/${encodeURIComponent(attemptId)}`, "GET", undefined, signal),
419
+ getHttpExchange: (id, attemptId, query = {}, signal) => {
420
+ return this.#call(`/v1/requests/${encodeURIComponent(id)}/http/${encodeURIComponent(attemptId)}${queryString(query)}`, "GET", undefined, signal);
421
+ },
399
422
  getHttpBody: (id, attemptId, query, signal) => this.#call(`/v1/requests/${encodeURIComponent(id)}/http/${encodeURIComponent(attemptId)}/body${queryString(query)}`, "GET", undefined, signal)
400
423
  };
401
424
  }
@@ -418,7 +441,7 @@ class RequestClient {
418
441
  }
419
442
  }
420
443
 
421
- // ../../packages/sdk/src/index.ts
444
+ // src/index.ts
422
445
  function queryString2(values) {
423
446
  const params = new URLSearchParams;
424
447
  for (const [key, value] of Object.entries(values))
@@ -462,6 +485,9 @@ class Constellation extends RequestClient {
462
485
  }
463
486
  return response.status === 204 ? undefined : response.json();
464
487
  }
488
+ discover(signal) {
489
+ return this.#call("/v1/discover", "GET", undefined, signal);
490
+ }
465
491
  get management() {
466
492
  return {
467
493
  registry: {
@@ -478,26 +504,39 @@ class Constellation extends RequestClient {
478
504
  }
479
505
  get telemetry() {
480
506
  const requestPath = (id) => `/v1/telemetry/requests/${encodeURIComponent(id)}`;
507
+ const read = (path, options = {}, extra = {}) => {
508
+ const value = options;
509
+ return this.#call(`${path}${queryString2({ ...extra, include: value.include })}`, "GET", undefined, value.signal);
510
+ };
481
511
  return {
482
512
  requests: {
483
513
  list: (query = {}, signal) => this.#call(`/v1/telemetry/requests${queryString2(query)}`, "GET", undefined, signal),
484
- get: (id, signal) => this.#call(requestPath(id), "GET", undefined, signal),
485
- getSummary: (id, signal) => this.#call(`${requestPath(id)}?summary=true`, "GET", undefined, signal),
486
- listEvents: (id, after = 0, signal) => this.#call(`${requestPath(id)}/events${queryString2({ after })}`, "GET", undefined, signal),
514
+ get: (id, options = {}) => read(requestPath(id), options),
515
+ getSummary: (id, options = {}) => read(requestPath(id), options, { summary: "true" }),
516
+ getTimings: (id, signal) => this.#call(`${requestPath(id)}/timings`, "GET", undefined, signal),
517
+ listEvents: (id, after = 0, options = {}) => read(`${requestPath(id)}/events`, options, { after }),
487
518
  listRecords: (id, kind, query = {}, signal) => this.#call(`${requestPath(id)}/records/${kind}${queryString2(query)}`, "GET", undefined, signal),
488
- getTimeline: (id, options = {}) => this.#call(`${requestPath(id)}/timeline${queryString2({ requestId: options.requestId })}`, "GET", undefined, options.signal),
489
- getHttpExchange: (id, attemptId, signal) => this.#call(`${requestPath(id)}/http/${encodeURIComponent(attemptId)}`, "GET", undefined, signal),
519
+ getTimeline: (id, options = {}) => read(`${requestPath(id)}/timeline`, options, { requestId: options.requestId }),
520
+ getHttpExchange: (id, attemptId, options = {}) => {
521
+ const value = options;
522
+ return read(`${requestPath(id)}/http/${encodeURIComponent(attemptId)}`, value, { offset: value.offset, limit: value.limit });
523
+ },
490
524
  getHttpBody: (id, attemptId, query, signal) => this.#call(`${requestPath(id)}/http/${encodeURIComponent(attemptId)}/body${queryString2(query)}`, "GET", undefined, signal)
491
525
  },
492
526
  system: {
493
- get: (signal) => this.#call("/v1/telemetry/system", "GET", undefined, signal),
527
+ get: (options = {}) => read("/v1/telemetry/system", options),
494
528
  listHistory: (query = {}, signal) => this.#call(`/v1/telemetry/system/history${queryString2(query)}`, "GET", undefined, signal),
495
- getComponent: (component, signal) => this.#call(`/v1/telemetry/system/${encodeURIComponent(component)}`, "GET", undefined, signal)
529
+ getComponent: (component, options = {}) => {
530
+ const value = options;
531
+ return read(`/v1/telemetry/system/${encodeURIComponent(component)}`, value, { offset: value.offset, status: value.status, statusNot: value.statusNot, q: value.q });
532
+ }
496
533
  },
497
534
  observability: {
498
535
  get: (query = {}, signal) => this.#call(`/v1/telemetry/observability${queryString2(query)}`, "GET", undefined, signal),
499
536
  getSeries: (query, signal) => this.#call(`/v1/telemetry/observability/series${queryString2(query)}`, "GET", undefined, signal),
500
- getTiming: (query = {}, signal) => this.#call(`/v1/telemetry/observability/timing${queryString2(query)}`, "GET", undefined, signal)
537
+ getTiming: (query = {}, signal) => this.#call(`/v1/telemetry/observability/timing${queryString2(query)}`, "GET", undefined, signal),
538
+ getTraffic: (query = {}, signal) => this.#call(`/v1/telemetry/observability/traffic${queryString2(query)}`, "GET", undefined, signal),
539
+ getBilling: (query = {}, signal) => this.#call(`/v1/telemetry/observability/billing${queryString2(query)}`, "GET", undefined, signal)
501
540
  },
502
541
  jobs: {
503
542
  listHistory: (query = {}, signal) => this.#call(`/v1/telemetry/jobs/history${queryString2(query)}`, "GET", undefined, signal)
@@ -0,0 +1,6 @@
1
+ /** Error telemetry deliberately omits stack traces and arbitrary object fields. */
2
+ export declare function callerErrorDetails(error: unknown): {
3
+ name: string;
4
+ message: string;
5
+ code?: string;
6
+ };
@@ -91,6 +91,9 @@ export type RequestRecord = {
91
91
  resolution: Json;
92
92
  rules: Json;
93
93
  createdAt: string;
94
+ receivedAt: string | null;
95
+ queuedAt: string | null;
96
+ claimedAt: string | null;
94
97
  endedAt: string | null;
95
98
  deadline: string;
96
99
  };
@@ -194,7 +197,7 @@ export type TimelineRow = {
194
197
  id: string;
195
198
  requestId: string;
196
199
  parentId: string | null;
197
- kind: "request" | "step" | "attempt" | "input" | "span" | "phase" | "http_phase";
200
+ kind: "request" | "step" | "attempt" | "input" | "span" | "phase" | "http_phase" | "delivery";
198
201
  label: string;
199
202
  status: string;
200
203
  start: string;
@@ -327,6 +330,55 @@ export declare class ConstellationError extends Error {
327
330
  constructor(status: number, code: string, message: string);
328
331
  }
329
332
  export declare function uuid7(): string;
333
+ /** Provider-reported token counts. Missing usage is unknown, not zero. */
334
+ export type TokenUsage = {
335
+ inputTokens?: number;
336
+ outputTokens?: number;
337
+ cacheReadTokens?: number;
338
+ cacheWriteTokens?: number;
339
+ reasoningTokens?: number;
340
+ partial?: boolean;
341
+ };
342
+ export type TimingInterval = {
343
+ id: string;
344
+ requestId: string;
345
+ parentId?: string | null;
346
+ start: string;
347
+ end: string | null;
348
+ durationMs: number | null;
349
+ kind?: string;
350
+ name?: string;
351
+ source?: string;
352
+ label?: string;
353
+ origin?: "recorded" | "derived";
354
+ derivedFrom?: string[];
355
+ providerId?: string;
356
+ actualModel?: string;
357
+ offeringId?: string;
358
+ committed?: boolean;
359
+ fallback?: boolean;
360
+ status?: string;
361
+ ttftMs?: number | null;
362
+ ttfbMs?: number | null;
363
+ reasoningMs?: number | null;
364
+ outputMs?: number | null;
365
+ httpStatus?: number | null;
366
+ };
367
+ export type RequestTimings = {
368
+ requestId: string;
369
+ totalMs: number | null;
370
+ admissionMs: number | null;
371
+ queueMs: number | null;
372
+ workerPreparationMs: number | null;
373
+ attemptMs: number | null;
374
+ callerWaitMs: number | null;
375
+ phases: TimingInterval[];
376
+ attempts: TimingInterval[];
377
+ callerWaits: TimingInterval[];
378
+ asOf: string;
379
+ complete: boolean;
380
+ truncated: boolean;
381
+ };
330
382
  export type RequestRecordsQuery = {
331
383
  id?: string;
332
384
  q?: string;
@@ -393,6 +445,7 @@ export declare class RequestClient {
393
445
  }>;
394
446
  get: (id: string, signal?: AbortSignal) => Promise<Inspection>;
395
447
  getSummary: (id: string, signal?: AbortSignal) => Promise<Inspection>;
448
+ getTimings: (id: string, signal?: AbortSignal) => Promise<RequestTimings>;
396
449
  list: (query?: RequestListQuery, signal?: AbortSignal) => Promise<{
397
450
  items: RequestRecord[];
398
451
  total: number;
@@ -417,7 +470,10 @@ export declare class RequestClient {
417
470
  requestId?: string;
418
471
  signal?: AbortSignal;
419
472
  }) => Promise<Timeline>;
420
- getHttpExchange: (id: string, attemptId: string, signal?: AbortSignal) => Promise<Json>;
473
+ getHttpExchange: (id: string, attemptId: string, query?: {
474
+ offset?: number;
475
+ limit?: number;
476
+ }, signal?: AbortSignal) => Promise<Json>;
421
477
  getHttpBody: (id: string, attemptId: string, query: {
422
478
  direction: "request" | "response";
423
479
  offset?: number;
@@ -1,7 +1,97 @@
1
1
  /** External server SDK. Operator APIs and cookie sessions are internal-only clients. */
2
- import { RequestClient, type WebhookEvent, type Json, type Page, type PageQuery, type ModelResolution, type RequestRecord, type Inspection, type RequestEvent, type RecordTypes, type Timeline } from "../../client-core/src/index";
2
+ import { RequestClient, type WebhookEvent, type Json, type Page, type PageQuery, type ModelResolution, type RequestRecord, type RequestEvent, type RecordTypes, type Timeline, type TimelineRow, type RequestListQuery, type RequestRecordsQuery, type RequestTimings, type TokenUsage } from "../../client-core/src/index";
3
3
  export { ConstellationError, uuid7 } from "../../client-core/src/index";
4
- export type { Json, Tool, ToolCall, Message, RequestEventModes, RequestInput, Status, RequestRecord, Step, Attempt, PreparedStep, PendingInput, Span, TimelineRow, Timeline, Log, Inspection, RecordTypes, InputResponse, InputHandlers, RequestEvent, Page, PageQuery, ModelScope, ModelResolution, WebhookEvent, RequestRecordsQuery, RequestListQuery, StartSpanOptions } from "../../client-core/src/index";
4
+ export type { Json, Tool, ToolCall, Message, RequestEventModes, RequestInput, RequestTimings, TimingInterval, TokenUsage, Status, RequestRecord, Step, Attempt, PreparedStep, PendingInput, Span, TimelineRow, Timeline, Log, Inspection, RecordTypes, InputResponse, InputHandlers, RequestEvent, Page, PageQuery, ModelScope, ModelResolution, WebhookEvent, RequestRecordsQuery, RequestListQuery, StartSpanOptions } from "../../client-core/src/index";
5
+ /** OpenAPI contract filtered to this key's permissions and scope. */
6
+ export type DiscoveryDocument = {
7
+ openapi: string;
8
+ info: {
9
+ title: string;
10
+ version: string;
11
+ description?: string;
12
+ };
13
+ paths: Record<string, Record<string, Json>>;
14
+ components: {
15
+ schemas: Record<string, Json>;
16
+ securitySchemes: Record<string, Json>;
17
+ };
18
+ "x-constellation-access": {
19
+ permissions: string[];
20
+ workspaceId: string | null;
21
+ userId: string | null;
22
+ };
23
+ };
24
+ /** Telemetry excludes request/log/HTTP content unless explicitly requested. No additional permission is required. */
25
+ export type TelemetryPage<T> = Page<T> & {
26
+ metadataOnly?: true;
27
+ };
28
+ export type TelemetryQuery = {
29
+ include?: "content";
30
+ };
31
+ export type TelemetryReadOptions = TelemetryQuery & {
32
+ signal?: AbortSignal;
33
+ };
34
+ export type PaginationQuery = {
35
+ offset?: number;
36
+ limit?: number;
37
+ };
38
+ export type OperationsQuery = {
39
+ offset?: number;
40
+ status?: string;
41
+ statusNot?: string;
42
+ q?: string;
43
+ };
44
+ export type ObservabilityQuery = PaginationQuery & {
45
+ hours?: 1 | 24 | 168;
46
+ providerId?: string;
47
+ modelId?: string;
48
+ upstream?: string;
49
+ q?: string;
50
+ };
51
+ export type LogSearchQuery = PaginationQuery & {
52
+ q?: string;
53
+ level?: "trace" | "debug" | "info" | "warn" | "error";
54
+ levelNot?: "trace" | "debug" | "info" | "warn" | "error";
55
+ target?: string;
56
+ targetNot?: string;
57
+ requestId?: string;
58
+ requestIdNot?: string;
59
+ from?: string;
60
+ to?: string;
61
+ };
62
+ type OptionalContent<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
63
+ export type TelemetryRequest = OptionalContent<RequestRecord, "output" | "error" | "reason" | "resolution" | "rules">;
64
+ export type TelemetryRecords = {
65
+ steps: OptionalContent<RecordTypes["steps"], "input" | "output" | "resolution" | "rules" | "customerPrice">;
66
+ attempts: OptionalContent<RecordTypes["attempts"], "endpoint" | "parameters" | "supplierPrice" | "customerPrice" | "error">;
67
+ inputs: Partial<RecordTypes["inputs"]> & {
68
+ id: string;
69
+ requestId: string;
70
+ };
71
+ spans: Partial<RecordTypes["spans"]> & {
72
+ id: string;
73
+ requestId: string;
74
+ };
75
+ logs: OptionalContent<RecordTypes["logs"], "message" | "attributes">;
76
+ };
77
+ export type TelemetryTimeline = Omit<Timeline, "rows"> & {
78
+ metadataOnly?: true;
79
+ rows: (Omit<TimelineRow, "label"> & {
80
+ label?: string;
81
+ })[];
82
+ };
83
+ export type TelemetryInspection = {
84
+ metadataOnly?: true;
85
+ request: TelemetryRequest;
86
+ usage?: TokenUsage;
87
+ input?: Json;
88
+ effectiveInput?: Json;
89
+ steps: TelemetryRecords["steps"][];
90
+ attempts: TelemetryRecords["attempts"][];
91
+ inputs: TelemetryRecords["inputs"][];
92
+ spans: TelemetryRecords["spans"][];
93
+ logs: TelemetryRecords["logs"][];
94
+ };
5
95
  export declare class Constellation extends RequestClient {
6
96
  #private;
7
97
  constructor(options: {
@@ -10,6 +100,8 @@ export declare class Constellation extends RequestClient {
10
100
  fetch?: typeof fetch;
11
101
  timeoutMs?: number;
12
102
  });
103
+ /** Discover HTTP operations available to this bearer key. */
104
+ discover(signal?: AbortSignal): Promise<DiscoveryDocument>;
13
105
  /** Registry authoring only; keys, credentials and capacity controls are internal. */
14
106
  get management(): {
15
107
  registry: {
@@ -20,7 +112,7 @@ export declare class Constellation extends RequestClient {
20
112
  catalog: Json;
21
113
  }, signal?: AbortSignal) => Promise<Json>;
22
114
  applyChanges: (changes: Json[], signal?: AbortSignal) => Promise<Json>;
23
- listHistory: (kind: string, id: string, query?: PageQuery, signal?: AbortSignal) => Promise<Page<Json>>;
115
+ listHistory: (kind: string, id: string, query?: PaginationQuery, signal?: AbortSignal) => Promise<Page<Json>>;
24
116
  rollback: (kind: string, id: string, input: {
25
117
  toVersion: number;
26
118
  expectedVersion: number;
@@ -32,62 +124,84 @@ export declare class Constellation extends RequestClient {
32
124
  }, signal?: AbortSignal) => Promise<Json>;
33
125
  };
34
126
  };
35
- /** Read-only operational endpoints require a telemetry key. */
127
+ /** Request reads enforce key scope; global operational reads require an unscoped telemetry key. Metadata is the default. */
36
128
  get telemetry(): {
37
129
  requests: {
38
- list: (query?: PageQuery, signal?: AbortSignal) => Promise<Page<RequestRecord>>;
39
- get: (id: string, signal?: AbortSignal) => Promise<Inspection>;
40
- getSummary: (id: string, signal?: AbortSignal) => Promise<Inspection>;
41
- listEvents: (id: string, after?: number, signal?: AbortSignal) => Promise<{
130
+ list: (query?: RequestListQuery & TelemetryQuery, signal?: AbortSignal) => Promise<TelemetryPage<TelemetryRequest>>;
131
+ get: (id: string, options?: TelemetryReadOptions) => Promise<TelemetryInspection>;
132
+ getSummary: (id: string, options?: TelemetryReadOptions) => Promise<TelemetryInspection>;
133
+ getTimings: (id: string, signal?: AbortSignal) => Promise<RequestTimings>;
134
+ listEvents: (id: string, after?: number, options?: TelemetryReadOptions) => Promise<{
42
135
  items: RequestEvent[];
136
+ metadataOnly?: true;
43
137
  }>;
44
- listRecords: <K extends keyof RecordTypes>(id: string, kind: K, query?: PageQuery, signal?: AbortSignal) => Promise<Page<RecordTypes[K]>>;
45
- getTimeline: (id: string, options?: {
138
+ listRecords: <K extends keyof RecordTypes>(id: string, kind: K, query?: RequestRecordsQuery & TelemetryQuery, signal?: AbortSignal) => Promise<TelemetryPage<TelemetryRecords[K]>>;
139
+ getTimeline: (id: string, options?: TelemetryReadOptions & {
46
140
  requestId?: string;
47
- signal?: AbortSignal;
48
- }) => Promise<Timeline>;
49
- getHttpExchange: (id: string, attemptId: string, signal?: AbortSignal) => Promise<Json>;
50
- getHttpBody: (id: string, attemptId: string, query: {
141
+ }) => Promise<TelemetryTimeline>;
142
+ getHttpExchange: (id: string, attemptId: string, options?: TelemetryReadOptions & PaginationQuery) => Promise<Json>;
143
+ getHttpBody: (id: string, attemptId: string, query: TelemetryQuery & {
51
144
  direction: "request" | "response";
52
145
  offset?: number;
53
146
  limit?: number;
54
147
  }, signal?: AbortSignal) => Promise<Json>;
55
148
  };
56
149
  system: {
57
- get: (signal?: AbortSignal) => Promise<Json>;
58
- listHistory: (query?: {
150
+ get: (options?: TelemetryReadOptions) => Promise<Json>;
151
+ listHistory: (query?: TelemetryQuery & {
59
152
  hours?: 1 | 24 | 168;
60
153
  }, signal?: AbortSignal) => Promise<Json>;
61
- getComponent: (component: string, signal?: AbortSignal) => Promise<Json>;
154
+ getComponent: (component: string, options?: TelemetryReadOptions & OperationsQuery) => Promise<Json>;
62
155
  };
63
156
  observability: {
64
- get: (query?: PageQuery, signal?: AbortSignal) => Promise<Json>;
65
- getSeries: (query: {
66
- source: "local" | "gateway";
157
+ get: (query?: ObservabilityQuery & TelemetryQuery, signal?: AbortSignal) => Promise<Json>;
158
+ getSeries: (query: TelemetryQuery & {
67
159
  hours?: 1 | 24 | 168;
68
- providerId?: string;
69
160
  modelId?: string;
161
+ } & ({
162
+ source: "local";
163
+ providerId?: string;
164
+ upstream?: never;
165
+ } | {
166
+ source: "gateway";
167
+ upstream?: string;
168
+ providerId?: never;
169
+ }), signal?: AbortSignal) => Promise<Json>;
170
+ getTiming: (query?: TelemetryQuery & {
171
+ hours?: 1 | 24 | 168;
70
172
  }, signal?: AbortSignal) => Promise<Json>;
71
- getTiming: (query?: {
173
+ getTraffic: (query?: TelemetryQuery & {
72
174
  hours?: 1 | 24 | 168;
73
175
  }, signal?: AbortSignal) => Promise<Json>;
176
+ getBilling: (query?: PaginationQuery & TelemetryQuery & {
177
+ hours?: 1 | 24 | 168 | 720;
178
+ providerId?: string;
179
+ modelId?: string;
180
+ groupBy?: "provider" | "model";
181
+ }, signal?: AbortSignal) => Promise<Json>;
74
182
  };
75
183
  jobs: {
76
- listHistory: (query?: PageQuery, signal?: AbortSignal) => Promise<Page<Json>>;
184
+ listHistory: (query?: OperationsQuery & TelemetryQuery, signal?: AbortSignal) => Promise<Json>;
77
185
  };
78
186
  notifications: {
79
- list: (query?: PageQuery & {
187
+ list: (query?: TelemetryQuery & {
188
+ offset?: number;
80
189
  status?: "active" | "resolved";
81
- }, signal?: AbortSignal) => Promise<Page<Json>>;
82
- get: (id: string, query?: PageQuery, signal?: AbortSignal) => Promise<Json>;
83
- listEvents: (query?: {
190
+ }, signal?: AbortSignal) => Promise<Json>;
191
+ get: (id: string, query?: TelemetryQuery & {
192
+ offset?: number;
193
+ }, signal?: AbortSignal) => Promise<Json>;
194
+ listEvents: (query?: TelemetryQuery & {
84
195
  after?: number;
85
196
  }, signal?: AbortSignal) => Promise<Json>;
86
197
  };
87
198
  logs: {
88
- searchSystem: (query?: PageQuery, signal?: AbortSignal) => Promise<Page<Json>>;
89
- searchRequests: (query?: PageQuery, signal?: AbortSignal) => Promise<Page<Json>>;
90
- searchAudit: (query?: PageQuery, signal?: AbortSignal) => Promise<Page<Json>>;
199
+ searchSystem: (query?: LogSearchQuery & TelemetryQuery, signal?: AbortSignal) => Promise<Page<Json>>;
200
+ searchRequests: (query?: Omit<LogSearchQuery, "level" | "levelNot" | "target" | "targetNot"> & {
201
+ level?: "debug" | "info" | "warn" | "error";
202
+ levelNot?: "debug" | "info" | "warn" | "error";
203
+ } & TelemetryQuery, signal?: AbortSignal) => Promise<Page<Json>>;
204
+ searchAudit: (query?: Omit<LogSearchQuery, "requestId" | "requestIdNot"> & TelemetryQuery, signal?: AbortSignal) => Promise<Page<Json>>;
91
205
  };
92
206
  };
93
207
  get webhooks(): {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lionhummer/constellation",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "TypeScript client for durable model requests and caller events",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",