@oxyhq/contracts 0.27.0 → 0.28.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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +44 -1
- package/dist/cjs/inference/accountBilling.js +334 -0
- package/dist/cjs/inference/attribution.js +9 -4
- package/dist/cjs/inference/entitlement.js +217 -0
- package/dist/cjs/inference/errors.js +15 -0
- package/dist/cjs/inference/identifiers.js +11 -3
- package/dist/cjs/inference/money.js +43 -0
- package/dist/cjs/inference/usage.js +6 -0
- package/dist/cjs/inference/version.js +28 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/index.js +9 -0
- package/dist/esm/inference/accountBilling.js +331 -0
- package/dist/esm/inference/attribution.js +9 -4
- package/dist/esm/inference/entitlement.js +214 -0
- package/dist/esm/inference/errors.js +15 -0
- package/dist/esm/inference/identifiers.js +11 -3
- package/dist/esm/inference/money.js +43 -0
- package/dist/esm/inference/usage.js +6 -0
- package/dist/esm/inference/version.js +28 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/inference/accountBilling.d.ts +738 -0
- package/dist/types/inference/attribution.d.ts +9 -4
- package/dist/types/inference/entitlement.d.ts +519 -0
- package/dist/types/inference/errors.d.ts +21 -8
- package/dist/types/inference/identifiers.d.ts +11 -3
- package/dist/types/inference/money.d.ts +43 -0
- package/dist/types/inference/streamEvents.d.ts +14 -14
- package/dist/types/inference/usage.d.ts +6 -0
- package/dist/types/inference/version.d.ts +28 -0
- package/package.json +1 -1
|
@@ -35,6 +35,12 @@ const identifiers_1 = require("./identifiers");
|
|
|
35
35
|
* `quota_exceeded`, `byok_credential_invalid`), routing/permission policy
|
|
36
36
|
* (`policy_violation`, `commercial_permission_denied`, `no_route_available`),
|
|
37
37
|
* and the platform or its upstreams (everything from `deployment_unavailable`).
|
|
38
|
+
*
|
|
39
|
+
* The platform group is NOT uniformly retryable, and that is the point of
|
|
40
|
+
* `provider_credential_invalid` sitting in it: an upstream that refuses the
|
|
41
|
+
* PLATFORM's own credential fails every identical retry until an operator
|
|
42
|
+
* rotates a key, so classifying it as `provider_error` would send every client
|
|
43
|
+
* into a retry loop against a request that cannot succeed.
|
|
38
44
|
*/
|
|
39
45
|
exports.INFERENCE_ERROR_CODES = [
|
|
40
46
|
'invalid_request',
|
|
@@ -61,6 +67,7 @@ exports.INFERENCE_ERROR_CODES = [
|
|
|
61
67
|
'provider_error',
|
|
62
68
|
'provider_timeout',
|
|
63
69
|
'provider_overloaded',
|
|
70
|
+
'provider_credential_invalid',
|
|
64
71
|
'service_unavailable',
|
|
65
72
|
'internal_error',
|
|
66
73
|
];
|
|
@@ -73,6 +80,13 @@ exports.inferenceErrorCodeSchema = zod_1.z.enum(exports.INFERENCE_ERROR_CODES);
|
|
|
73
80
|
* names, while a quota is an account-level ceiling that only a human raises.
|
|
74
81
|
* `cancelled` is here because the caller already withdrew the request; a client
|
|
75
82
|
* that retries it is contradicting its own cancellation.
|
|
83
|
+
*
|
|
84
|
+
* `byok_credential_invalid` and `provider_credential_invalid` are the same
|
|
85
|
+
* failure seen from the two sides of the BYOK boundary — the customer's own
|
|
86
|
+
* upstream credential and the platform's — and they are two codes rather than
|
|
87
|
+
* one because only the first names an action the customer can take. Both are
|
|
88
|
+
* non-retryable for the same reason: a credential an upstream has refused keeps
|
|
89
|
+
* being refused until somebody replaces it.
|
|
76
90
|
*/
|
|
77
91
|
exports.NON_RETRYABLE_INFERENCE_ERROR_CODES = [
|
|
78
92
|
'invalid_request',
|
|
@@ -94,6 +108,7 @@ exports.NON_RETRYABLE_INFERENCE_ERROR_CODES = [
|
|
|
94
108
|
'no_route_available',
|
|
95
109
|
'upstream_content_filtered',
|
|
96
110
|
'cancelled',
|
|
111
|
+
'provider_credential_invalid',
|
|
97
112
|
];
|
|
98
113
|
const NON_RETRYABLE_CODE_SET = new Set(exports.NON_RETRYABLE_INFERENCE_ERROR_CODES);
|
|
99
114
|
/**
|
|
@@ -57,9 +57,17 @@ exports.oxyApplicationIdSchema = zod_1.z.string().min(1).max(64);
|
|
|
57
57
|
/** An Oxy `ApplicationCredential._id` — the credential used for this request. */
|
|
58
58
|
exports.oxyCredentialIdSchema = zod_1.z.string().min(1).max(64);
|
|
59
59
|
/**
|
|
60
|
-
* A request id
|
|
61
|
-
*
|
|
62
|
-
*
|
|
60
|
+
* A request id allocated by the Oxy EDGE, at admission and BEFORE
|
|
61
|
+
* authentication, so that a request rejected for a bad credential is as
|
|
62
|
+
* traceable as one that was served (ADR 0007, and step 1 of ADR 0010's edge
|
|
63
|
+
* order). It is required on the inbound envelope, which is what makes the data
|
|
64
|
+
* plane a consumer of this id rather than its source: the data plane echoes it
|
|
65
|
+
* on every stream event, on the usage report and on anything it can be asked
|
|
66
|
+
* about later.
|
|
67
|
+
*
|
|
68
|
+
* Correlates the Oxy edge, the data plane, the financial ledger and the
|
|
69
|
+
* customer-visible receipt, so it appears on every stream event and every
|
|
70
|
+
* ledger record.
|
|
63
71
|
*/
|
|
64
72
|
exports.requestIdSchema = zod_1.z.string().min(1).max(128);
|
|
65
73
|
/**
|
|
@@ -88,6 +88,49 @@ exports.moneySchema = zod_1.z
|
|
|
88
88
|
/**
|
|
89
89
|
* The closed set of units inference is metered in.
|
|
90
90
|
*
|
|
91
|
+
* **The units PARTITION a request: every unit counts material no other unit
|
|
92
|
+
* counts.** `cached_input_tokens` is not part of `input_tokens`, and
|
|
93
|
+
* `reasoning_tokens` is not part of `output_tokens` — they are siblings, not
|
|
94
|
+
* subsets. A request whose 10 000-token prompt was served 9 000 tokens from
|
|
95
|
+
* cache is reported as `input_tokens: 1000` beside `cached_input_tokens: 9000`,
|
|
96
|
+
* never as `input_tokens: 10000` beside it.
|
|
97
|
+
*
|
|
98
|
+
* That belongs to the definition rather than to a convention somewhere else,
|
|
99
|
+
* because settlement applies a price to EVERY reported unit and sums them
|
|
100
|
+
* (`inferenceLedger.service.ts`'s `computeCharge`). Under the partition rule
|
|
101
|
+
* that sum IS the request's cost, and a cached token can carry its own — lower
|
|
102
|
+
* — price. Under the nested reading the same sum charges the cached and
|
|
103
|
+
* reasoning tokens twice: once inside their parent and once on their own line.
|
|
104
|
+
* It fails silently, because every total still looks plausible and the receipt
|
|
105
|
+
* is still internally consistent, and on a reasoning model the reasoning tokens
|
|
106
|
+
* can dominate the completion, so the error is not marginal.
|
|
107
|
+
*
|
|
108
|
+
* **Every OpenAI-compatible provider reports the other way round**:
|
|
109
|
+
* `prompt_tokens` INCLUDES `prompt_tokens_details.cached_tokens`, and
|
|
110
|
+
* `completion_tokens` INCLUDES `completion_tokens_details.reasoning_tokens`.
|
|
111
|
+
* Normalising is the data plane's job and it is subtraction:
|
|
112
|
+
*
|
|
113
|
+
* ```text
|
|
114
|
+
* input_tokens = prompt_tokens - prompt_tokens_details.cached_tokens
|
|
115
|
+
* output_tokens = completion_tokens - completion_tokens_details.reasoning_tokens
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* No refinement in this package can enforce it, and saying so is part of the
|
|
119
|
+
* rule: a nested report and a disjoint one are the same four non-negative
|
|
120
|
+
* integers, so no predicate over a single report can tell them apart. The two
|
|
121
|
+
* structural guards that DO exist — refining `cached <= input` and
|
|
122
|
+
* `reasoning <= output`, or deriving the parents instead of reporting them —
|
|
123
|
+
* both encode the nested reading, which is the one this rule rejects. What IS
|
|
124
|
+
* enforceable is the arithmetic that depends on the rule, and that is where the
|
|
125
|
+
* enforcement lives — `inferenceLedger.service.test.ts` prices a report in
|
|
126
|
+
* which cached and reasoning tokens are both non-zero and asserts the exact
|
|
127
|
+
* total, which the nested reading cannot produce.
|
|
128
|
+
*
|
|
129
|
+
* Where the public surface has to speak a nested dialect, the sum is put back
|
|
130
|
+
* at the boundary rather than the internal reading being bent to it
|
|
131
|
+
* (`routes/inferenceEdge.ts` renders `prompt_tokens` as
|
|
132
|
+
* `input_tokens + cached_input_tokens`).
|
|
133
|
+
*
|
|
91
134
|
* Time is carried in integer MILLISECONDS rather than seconds so that no unit
|
|
92
135
|
* quantity is ever fractional: a 12.5-second transcription is `12500`, exactly,
|
|
93
136
|
* and the "units are integers" rule holds for every modality instead of holding
|
|
@@ -131,6 +131,12 @@ exports.inferenceRequestOutcomeSchema = zod_1.z.enum([
|
|
|
131
131
|
* `usageSource` is load-bearing when a provider returns no usage at all: the
|
|
132
132
|
* report still arrives, marked `estimated`, so settlement can apply the
|
|
133
133
|
* estimation policy knowingly instead of treating a reconstruction as fact.
|
|
134
|
+
*
|
|
135
|
+
* `units` is a PARTITION of what the request consumed, not a set of totals with
|
|
136
|
+
* details hanging off them — see `USAGE_UNITS` in `money.ts`. Reporting a provider's
|
|
137
|
+
* nested `prompt_tokens`/`completion_tokens` verbatim charges the cached and
|
|
138
|
+
* reasoning tokens twice, so subtracting the children out is part of what
|
|
139
|
+
* "normalized" means in this shape's name.
|
|
134
140
|
*/
|
|
135
141
|
exports.normalizedUsageReportSchema = zod_1.z
|
|
136
142
|
.object({
|
|
@@ -35,6 +35,34 @@
|
|
|
35
35
|
* field is additive and does not bump it, because a consumer on the previous
|
|
36
36
|
* version parses the message correctly and simply does not read the new field.
|
|
37
37
|
*
|
|
38
|
+
* ## Which shapes reject an unknown field
|
|
39
|
+
*
|
|
40
|
+
* That last rule is why the shapes EXCHANGED WITH THE DATA PLANE are not
|
|
41
|
+
* `.strict()` at their top level — the request envelope, the four usage records,
|
|
42
|
+
* the stream events, the error body, the catalogue descriptors, the price
|
|
43
|
+
* version. The split is a decision rather than an omission: `.strict()` and
|
|
44
|
+
* "adding an optional field is additive" cannot both hold on one shape, because
|
|
45
|
+
* a producer one minor version ahead would have its whole message REFUSED
|
|
46
|
+
* rather than its new field ignored. For a usage report that means a request
|
|
47
|
+
* already served upstream can never be settled and Oxy absorbs its cost, which
|
|
48
|
+
* is a worse failure than the one strictness would have caught.
|
|
49
|
+
*
|
|
50
|
+
* Their LEAVES are strict, and that is where the protection lives: a stripped
|
|
51
|
+
* field is the worse outcome exactly where it would be a leak or a second
|
|
52
|
+
* source of truth, because it disappears at this parse and survives in the
|
|
53
|
+
* producer, which is where somebody eventually reads it. So
|
|
54
|
+
* `clientRequestMetadataSchema` (no IP, ever), `moneySchema` (no convenience
|
|
55
|
+
* float beside the exact decimal), `providerErrorPassthroughSchema` (no
|
|
56
|
+
* upstream request or headers beside the message), `usageQuantitySchema` and
|
|
57
|
+
* `unitPriceSchema` all refuse an unknown field, while the envelope carrying
|
|
58
|
+
* them tolerates an additive one.
|
|
59
|
+
*
|
|
60
|
+
* A shape Oxy does NOT exchange with the data plane is strict at its top level
|
|
61
|
+
* too, since nothing there can run ahead of this package:
|
|
62
|
+
* `providerConnectionSchema`, where an unknown field is how a BYOK credential
|
|
63
|
+
* escapes, and the billing and entitlement records, where one is a second
|
|
64
|
+
* number beside an exact amount.
|
|
65
|
+
*
|
|
38
66
|
* Decided in: docs/adr/0006-oxy-relay-boundary.md, docs/adr/0010-public-api-compatibility.md.
|
|
39
67
|
*/
|
|
40
68
|
Object.defineProperty(exports, "__esModule", { value: true });
|