@lionhummer/constellation 0.3.0 → 0.5.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 +61 -0
- package/dist/index.js +52 -13
- package/dist/types/client-core/src/error-details.d.ts +6 -0
- package/dist/types/client-core/src/index.d.ts +138 -5
- package/dist/types/sdk/src/index.d.ts +144 -30
- package/package.json +1 -1
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,60 @@ 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.
|
|
204
|
+
|
|
205
|
+
### Supplier cost, customer basis and margin
|
|
206
|
+
|
|
207
|
+
Each provider attempt records immutable `attributes.billing` on its Constellation `provider.call` span. The `step.usage_ready` event carries the same `billing` facts. Both are included in default telemetry metadata. `supplierPrice`/`supplierCost` record the selected supplier rates and usage cost. `customerPricing` identifies the model or offering basis, plan, scoped rule and adjustment; `customerBasisPrice`/`customerBasisCost` record the customer calculation before adjustment. `customerPrice`/`customerCost` record the final rates and charge. `grossMarginAmount` is charge minus supplier cost; `grossMarginPercent` divides it by charge. Unknown costs leave margins null, and a zero charge has a null margin percentage. These costs use provider-reported usage and captured schedules, not reconciled supplier invoices. Prices are USD per million tokens; costs are decimal USD strings.
|
|
208
|
+
|
|
209
|
+
Provider cost capture is optional: `billing.amountPointer` locates a provider-reported amount in response JSON and `unitsPerUsd` converts it to USD. `reportedSupplierCost` is retained only for analysis; it never changes supplier cost, customer basis, charges or margin. Supplier cost is calculated from reported token usage and captured supplier rates. `supplierCostDifference` is reported minus calculated cost when both are known. The offering selects `customerPriceBasis:model|offering`; plans apply the customer adjustment.
|
|
210
|
+
|
|
211
|
+
### Standard settings and headers
|
|
212
|
+
|
|
213
|
+
Use `parameters.reasoningEffort` for reasoning effort across providers. The model discovery schema defines its allowed values and other supported settings. Constellation translates fields and values for the selected offering. Required unsupported settings reject; `optionalParameters` permits declared omissions with warnings.
|
|
214
|
+
|
|
215
|
+
The standard Reasoning Effort vocabulary is `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`; Verbosity is `low`, `medium`, or `high`; Service Tier is `auto`, `default`, `flex`, or `priority`. Discovery lists the values accessible to your key and eligible routes. A model’s standard definitions cannot be renamed or given additional values; custom parameters have separately authored definitions. Provider wire names and values are translated internally.
|
|
216
|
+
|
|
217
|
+
For cache diagnostics, send `cache: { mode: "automatic", diagnostics: true }` on the first step. `providerResponseId` appears on attempts and in the `afterModel` checkpoint payload. Use that upstream ID as a later step’s `cache.comparisonId`, which also enables diagnostics. A successful cache hit may return no diagnostic payload. Telemetry exposes the response ID by default; raw `cacheDiagnostics` requires `include: "content"`. Diagnostics and prewarm are offering capabilities: discover support before requesting them. Invalid TTLs or unsupported required cache settings fail rather than being silently dropped.
|
|
218
|
+
|
|
219
|
+
Send beta tokens as `headers: { "anthropic-beta": "your-beta-token" }`, not inside `parameters`. The provider connection must allow the header name. Unapproved, protected or malformed headers are dropped with warnings. A permitted header can still contain an upstream-unsupported beta token; the provider's own error remains visible. Cache diagnostics can add their required beta separately. Obvious may choose provider-specific prompt placement and cache boundaries while using Constellation's standard cache request.
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
//
|
|
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,
|
|
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
|
-
//
|
|
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,
|
|
485
|
-
getSummary: (id,
|
|
486
|
-
|
|
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 = {}) =>
|
|
489
|
-
getHttpExchange: (id, attemptId,
|
|
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: (
|
|
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,
|
|
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)
|
|
@@ -29,6 +29,20 @@ export type Message = {
|
|
|
29
29
|
isError?: boolean;
|
|
30
30
|
}[];
|
|
31
31
|
};
|
|
32
|
+
/** Standard settings. The model discovery schema describes supported values and extensions. */
|
|
33
|
+
export type InferenceParameters = Record<string, Json> & {
|
|
34
|
+
reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
35
|
+
verbosity?: "low" | "medium" | "high";
|
|
36
|
+
temperature?: number;
|
|
37
|
+
topP?: number;
|
|
38
|
+
thinking?: Json;
|
|
39
|
+
toolChoice?: Json;
|
|
40
|
+
parallelToolCalls?: boolean;
|
|
41
|
+
toolStrict?: boolean;
|
|
42
|
+
responseFormat?: Json;
|
|
43
|
+
stopSequences?: string[];
|
|
44
|
+
serviceTier?: "auto" | "default" | "flex" | "priority";
|
|
45
|
+
};
|
|
32
46
|
type RequestFields = {
|
|
33
47
|
idempotencyKey: string;
|
|
34
48
|
externalId?: string;
|
|
@@ -39,12 +53,21 @@ type RequestFields = {
|
|
|
39
53
|
instructions?: string;
|
|
40
54
|
messages: Message[];
|
|
41
55
|
tools?: Tool[];
|
|
42
|
-
parameters?:
|
|
56
|
+
parameters?: InferenceParameters;
|
|
57
|
+
optionalParameters?: string[];
|
|
58
|
+
/** Only headers approved by the selected provider are forwarded; others produce warnings. */
|
|
59
|
+
headers?: Record<string, string>;
|
|
60
|
+
nativeContentPolicy?: "require" | "omitCompleted";
|
|
43
61
|
maxSteps?: number;
|
|
44
62
|
timeoutMs?: number;
|
|
45
63
|
maxOutputTokens?: number;
|
|
46
64
|
cache?: {
|
|
47
65
|
mode: "automatic" | "explicit";
|
|
66
|
+
ttl?: string;
|
|
67
|
+
prewarm?: boolean;
|
|
68
|
+
comparisonId?: string;
|
|
69
|
+
/** Request cache diagnostics, including a first-turn baseline without a comparison ID. */
|
|
70
|
+
diagnostics?: boolean;
|
|
48
71
|
points?: ({
|
|
49
72
|
target: "tools" | "instructions";
|
|
50
73
|
} | {
|
|
@@ -91,6 +114,9 @@ export type RequestRecord = {
|
|
|
91
114
|
resolution: Json;
|
|
92
115
|
rules: Json;
|
|
93
116
|
createdAt: string;
|
|
117
|
+
receivedAt: string | null;
|
|
118
|
+
queuedAt: string | null;
|
|
119
|
+
claimedAt: string | null;
|
|
94
120
|
endedAt: string | null;
|
|
95
121
|
deadline: string;
|
|
96
122
|
};
|
|
@@ -123,6 +149,8 @@ export type Attempt = {
|
|
|
123
149
|
providerId: string;
|
|
124
150
|
offeringId: string;
|
|
125
151
|
providerModel: string;
|
|
152
|
+
providerResponseId?: string | null;
|
|
153
|
+
cacheDiagnostics?: Json | null;
|
|
126
154
|
connectionKind: string;
|
|
127
155
|
endpoint: string;
|
|
128
156
|
fallback: boolean;
|
|
@@ -151,7 +179,11 @@ export type PreparedStep = {
|
|
|
151
179
|
instructions: string;
|
|
152
180
|
messages: Message[];
|
|
153
181
|
tools: Tool[];
|
|
154
|
-
parameters:
|
|
182
|
+
parameters: InferenceParameters;
|
|
183
|
+
optionalParameters?: string[];
|
|
184
|
+
/** Only headers approved by the selected provider are forwarded; others produce warnings. */
|
|
185
|
+
headers?: Record<string, string>;
|
|
186
|
+
nativeContentPolicy?: "require" | "omitCompleted";
|
|
155
187
|
maxOutputTokens: number;
|
|
156
188
|
cache: RequestInput["cache"] | null;
|
|
157
189
|
};
|
|
@@ -171,6 +203,8 @@ export type PendingInput = {
|
|
|
171
203
|
customerCost?: string | null;
|
|
172
204
|
supplierCost?: string | null;
|
|
173
205
|
customerPrice?: Json;
|
|
206
|
+
customerPricing?: CustomerPricing;
|
|
207
|
+
billing?: BillingFacts;
|
|
174
208
|
output?: Json;
|
|
175
209
|
};
|
|
176
210
|
claimId: string | null;
|
|
@@ -194,7 +228,7 @@ export type TimelineRow = {
|
|
|
194
228
|
id: string;
|
|
195
229
|
requestId: string;
|
|
196
230
|
parentId: string | null;
|
|
197
|
-
kind: "request" | "step" | "attempt" | "input" | "span" | "phase" | "http_phase";
|
|
231
|
+
kind: "request" | "step" | "attempt" | "input" | "span" | "phase" | "http_phase" | "delivery";
|
|
198
232
|
label: string;
|
|
199
233
|
status: string;
|
|
200
234
|
start: string;
|
|
@@ -304,7 +338,11 @@ export type ModelResolution = ModelScope & {
|
|
|
304
338
|
targetId: string;
|
|
305
339
|
inputTokens?: number;
|
|
306
340
|
outputTokens?: number;
|
|
307
|
-
parameters?:
|
|
341
|
+
parameters?: InferenceParameters;
|
|
342
|
+
optionalParameters?: string[];
|
|
343
|
+
/** Only headers approved by the selected provider are forwarded; others produce warnings. */
|
|
344
|
+
headers?: Record<string, string>;
|
|
345
|
+
nativeContentPolicy?: "require" | "omitCompleted";
|
|
308
346
|
};
|
|
309
347
|
export type WebhookEvent = {
|
|
310
348
|
requestId: string;
|
|
@@ -327,6 +365,97 @@ export declare class ConstellationError extends Error {
|
|
|
327
365
|
constructor(status: number, code: string, message: string);
|
|
328
366
|
}
|
|
329
367
|
export declare function uuid7(): string;
|
|
368
|
+
/** Provider-reported token counts. Missing usage is unknown, not zero. */
|
|
369
|
+
export type TokenUsage = {
|
|
370
|
+
inputTokens?: number;
|
|
371
|
+
outputTokens?: number;
|
|
372
|
+
cacheReadTokens?: number;
|
|
373
|
+
cacheWriteTokens?: number;
|
|
374
|
+
cacheWriteOneHourTokens?: number;
|
|
375
|
+
reasoningTokens?: number;
|
|
376
|
+
partial?: boolean;
|
|
377
|
+
};
|
|
378
|
+
/** USD per million tokens. The selected rates apply to the whole call. */
|
|
379
|
+
export type TokenPrice = {
|
|
380
|
+
input: string;
|
|
381
|
+
output: string;
|
|
382
|
+
cacheRead?: string | null;
|
|
383
|
+
cacheWrite?: string | null;
|
|
384
|
+
cacheWriteOneHour?: string | null;
|
|
385
|
+
tiers?: {
|
|
386
|
+
aboveInputTokens: number;
|
|
387
|
+
price: TokenPrice;
|
|
388
|
+
}[];
|
|
389
|
+
};
|
|
390
|
+
export type CustomerPricing = {
|
|
391
|
+
basis: "model" | "offering";
|
|
392
|
+
basisTargetId: string;
|
|
393
|
+
basisPrice?: TokenPrice;
|
|
394
|
+
planId: string | null;
|
|
395
|
+
pricingRuleId: string | null;
|
|
396
|
+
adjustment: {
|
|
397
|
+
mode: "margin" | "markup" | "discount";
|
|
398
|
+
percent: string;
|
|
399
|
+
};
|
|
400
|
+
};
|
|
401
|
+
/** Costs use captured rates; provider-reported amounts are analysis-only. */
|
|
402
|
+
export type BillingFacts = {
|
|
403
|
+
totalInputTokens: number | null;
|
|
404
|
+
supplierPrice: TokenPrice | null;
|
|
405
|
+
supplierCost: string | null;
|
|
406
|
+
calculatedSupplierCost: string | null;
|
|
407
|
+
reportedSupplierCost: string | null;
|
|
408
|
+
supplierCostSource: "calculated" | "unknown";
|
|
409
|
+
supplierCostDifference: string | null;
|
|
410
|
+
customerPricing: CustomerPricing;
|
|
411
|
+
customerBasisPrice: TokenPrice | null;
|
|
412
|
+
customerBasisCost: string | null;
|
|
413
|
+
customerBasisSource: "calculated" | "unknown" | "model_schedule";
|
|
414
|
+
customerPrice: TokenPrice | null;
|
|
415
|
+
customerCost: string | null;
|
|
416
|
+
grossMarginAmount: string | null;
|
|
417
|
+
grossMarginPercent: string | null;
|
|
418
|
+
};
|
|
419
|
+
export type TimingInterval = {
|
|
420
|
+
id: string;
|
|
421
|
+
requestId: string;
|
|
422
|
+
parentId?: string | null;
|
|
423
|
+
start: string;
|
|
424
|
+
end: string | null;
|
|
425
|
+
durationMs: number | null;
|
|
426
|
+
kind?: string;
|
|
427
|
+
name?: string;
|
|
428
|
+
source?: string;
|
|
429
|
+
label?: string;
|
|
430
|
+
origin?: "recorded" | "derived";
|
|
431
|
+
derivedFrom?: string[];
|
|
432
|
+
providerId?: string;
|
|
433
|
+
actualModel?: string;
|
|
434
|
+
offeringId?: string;
|
|
435
|
+
committed?: boolean;
|
|
436
|
+
fallback?: boolean;
|
|
437
|
+
status?: string;
|
|
438
|
+
ttftMs?: number | null;
|
|
439
|
+
ttfbMs?: number | null;
|
|
440
|
+
reasoningMs?: number | null;
|
|
441
|
+
outputMs?: number | null;
|
|
442
|
+
httpStatus?: number | null;
|
|
443
|
+
};
|
|
444
|
+
export type RequestTimings = {
|
|
445
|
+
requestId: string;
|
|
446
|
+
totalMs: number | null;
|
|
447
|
+
admissionMs: number | null;
|
|
448
|
+
queueMs: number | null;
|
|
449
|
+
workerPreparationMs: number | null;
|
|
450
|
+
attemptMs: number | null;
|
|
451
|
+
callerWaitMs: number | null;
|
|
452
|
+
phases: TimingInterval[];
|
|
453
|
+
attempts: TimingInterval[];
|
|
454
|
+
callerWaits: TimingInterval[];
|
|
455
|
+
asOf: string;
|
|
456
|
+
complete: boolean;
|
|
457
|
+
truncated: boolean;
|
|
458
|
+
};
|
|
330
459
|
export type RequestRecordsQuery = {
|
|
331
460
|
id?: string;
|
|
332
461
|
q?: string;
|
|
@@ -393,6 +522,7 @@ export declare class RequestClient {
|
|
|
393
522
|
}>;
|
|
394
523
|
get: (id: string, signal?: AbortSignal) => Promise<Inspection>;
|
|
395
524
|
getSummary: (id: string, signal?: AbortSignal) => Promise<Inspection>;
|
|
525
|
+
getTimings: (id: string, signal?: AbortSignal) => Promise<RequestTimings>;
|
|
396
526
|
list: (query?: RequestListQuery, signal?: AbortSignal) => Promise<{
|
|
397
527
|
items: RequestRecord[];
|
|
398
528
|
total: number;
|
|
@@ -417,7 +547,10 @@ export declare class RequestClient {
|
|
|
417
547
|
requestId?: string;
|
|
418
548
|
signal?: AbortSignal;
|
|
419
549
|
}) => Promise<Timeline>;
|
|
420
|
-
getHttpExchange: (id: string, attemptId: string,
|
|
550
|
+
getHttpExchange: (id: string, attemptId: string, query?: {
|
|
551
|
+
offset?: number;
|
|
552
|
+
limit?: number;
|
|
553
|
+
}, signal?: AbortSignal) => Promise<Json>;
|
|
421
554
|
getHttpBody: (id: string, attemptId: string, query: {
|
|
422
555
|
direction: "request" | "response";
|
|
423
556
|
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
|
|
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 { InferenceParameters, Json, Tool, ToolCall, Message, RequestEventModes, RequestInput, RequestTimings, TimingInterval, TokenUsage, TokenPrice, CustomerPricing, BillingFacts, 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?:
|
|
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
|
-
/**
|
|
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?:
|
|
39
|
-
get: (id: string,
|
|
40
|
-
getSummary: (id: string,
|
|
41
|
-
|
|
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?:
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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: (
|
|
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,
|
|
154
|
+
getComponent: (component: string, options?: TelemetryReadOptions & OperationsQuery) => Promise<Json>;
|
|
62
155
|
};
|
|
63
156
|
observability: {
|
|
64
|
-
get: (query?:
|
|
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
|
-
|
|
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?:
|
|
184
|
+
listHistory: (query?: OperationsQuery & TelemetryQuery, signal?: AbortSignal) => Promise<Json>;
|
|
77
185
|
};
|
|
78
186
|
notifications: {
|
|
79
|
-
list: (query?:
|
|
187
|
+
list: (query?: TelemetryQuery & {
|
|
188
|
+
offset?: number;
|
|
80
189
|
status?: "active" | "resolved";
|
|
81
|
-
}, signal?: AbortSignal) => Promise<
|
|
82
|
-
get: (id: string, query?:
|
|
83
|
-
|
|
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?:
|
|
89
|
-
searchRequests: (query?:
|
|
90
|
-
|
|
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(): {
|