@sentropic/llm-mesh 0.28.0 → 0.28.1

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.
Files changed (140) hide show
  1. package/README.md +92 -0
  2. package/dist/capabilities.d.ts +3 -0
  3. package/dist/capabilities.d.ts.map +1 -1
  4. package/dist/capabilities.js.map +1 -1
  5. package/dist/catalog.d.ts +134 -1
  6. package/dist/catalog.d.ts.map +1 -1
  7. package/dist/catalog.js +15 -0
  8. package/dist/catalog.js.map +1 -1
  9. package/dist/decision/adapter-result.d.ts +6 -0
  10. package/dist/decision/adapter-result.d.ts.map +1 -0
  11. package/dist/decision/adapter-result.js +148 -0
  12. package/dist/decision/adapter-result.js.map +1 -0
  13. package/dist/decision/adapter.d.ts +58 -0
  14. package/dist/decision/adapter.d.ts.map +1 -0
  15. package/dist/decision/adapter.js +70 -0
  16. package/dist/decision/adapter.js.map +1 -0
  17. package/dist/decision/admission.d.ts +23 -0
  18. package/dist/decision/admission.d.ts.map +1 -0
  19. package/dist/decision/admission.js +115 -0
  20. package/dist/decision/admission.js.map +1 -0
  21. package/dist/decision/budget.d.ts +60 -0
  22. package/dist/decision/budget.d.ts.map +1 -0
  23. package/dist/decision/budget.js +2 -0
  24. package/dist/decision/budget.js.map +1 -0
  25. package/dist/decision/client.d.ts +23 -0
  26. package/dist/decision/client.d.ts.map +1 -0
  27. package/dist/decision/client.js +836 -0
  28. package/dist/decision/client.js.map +1 -0
  29. package/dist/decision/criterion.d.ts +5 -0
  30. package/dist/decision/criterion.d.ts.map +1 -0
  31. package/dist/decision/criterion.js +54 -0
  32. package/dist/decision/criterion.js.map +1 -0
  33. package/dist/decision/deadline.d.ts +8 -0
  34. package/dist/decision/deadline.d.ts.map +1 -0
  35. package/dist/decision/deadline.js +56 -0
  36. package/dist/decision/deadline.js.map +1 -0
  37. package/dist/decision/descriptor-validation.d.ts +5 -0
  38. package/dist/decision/descriptor-validation.d.ts.map +1 -0
  39. package/dist/decision/descriptor-validation.js +99 -0
  40. package/dist/decision/descriptor-validation.js.map +1 -0
  41. package/dist/decision/descriptor.d.ts +81 -0
  42. package/dist/decision/descriptor.d.ts.map +1 -0
  43. package/dist/decision/descriptor.js +36 -0
  44. package/dist/decision/descriptor.js.map +1 -0
  45. package/dist/decision/dispatch.d.ts +11 -0
  46. package/dist/decision/dispatch.d.ts.map +1 -0
  47. package/dist/decision/dispatch.js +56 -0
  48. package/dist/decision/dispatch.js.map +1 -0
  49. package/dist/decision/errors.d.ts +43 -0
  50. package/dist/decision/errors.d.ts.map +1 -0
  51. package/dist/decision/errors.js +47 -0
  52. package/dist/decision/errors.js.map +1 -0
  53. package/dist/decision/execution.d.ts +31 -0
  54. package/dist/decision/execution.d.ts.map +1 -0
  55. package/dist/decision/execution.js +79 -0
  56. package/dist/decision/execution.js.map +1 -0
  57. package/dist/decision/host-options.d.ts +26 -0
  58. package/dist/decision/host-options.d.ts.map +1 -0
  59. package/dist/decision/host-options.js +2 -0
  60. package/dist/decision/host-options.js.map +1 -0
  61. package/dist/decision/host.d.ts +14 -0
  62. package/dist/decision/host.d.ts.map +1 -0
  63. package/dist/decision/host.js +6 -0
  64. package/dist/decision/host.js.map +1 -0
  65. package/dist/decision/index.d.ts +12 -0
  66. package/dist/decision/index.d.ts.map +1 -0
  67. package/dist/decision/index.js +3 -0
  68. package/dist/decision/index.js.map +1 -0
  69. package/dist/decision/jev-codec.d.ts +30 -0
  70. package/dist/decision/jev-codec.d.ts.map +1 -0
  71. package/dist/decision/jev-codec.js +51 -0
  72. package/dist/decision/jev-codec.js.map +1 -0
  73. package/dist/decision/jev-response.d.ts +7 -0
  74. package/dist/decision/jev-response.d.ts.map +1 -0
  75. package/dist/decision/jev-response.js +42 -0
  76. package/dist/decision/jev-response.js.map +1 -0
  77. package/dist/decision/jev-verdict.d.ts +14 -0
  78. package/dist/decision/jev-verdict.d.ts.map +1 -0
  79. package/dist/decision/jev-verdict.js +71 -0
  80. package/dist/decision/jev-verdict.js.map +1 -0
  81. package/dist/decision/policy.d.ts +11 -0
  82. package/dist/decision/policy.d.ts.map +1 -0
  83. package/dist/decision/policy.js +33 -0
  84. package/dist/decision/policy.js.map +1 -0
  85. package/dist/decision/pricing.d.ts +40 -0
  86. package/dist/decision/pricing.d.ts.map +1 -0
  87. package/dist/decision/pricing.js +65 -0
  88. package/dist/decision/pricing.js.map +1 -0
  89. package/dist/decision/raw.d.ts +7 -0
  90. package/dist/decision/raw.d.ts.map +1 -0
  91. package/dist/decision/raw.js +53 -0
  92. package/dist/decision/raw.js.map +1 -0
  93. package/dist/decision/receipt.d.ts +120 -0
  94. package/dist/decision/receipt.d.ts.map +1 -0
  95. package/dist/decision/receipt.js +58 -0
  96. package/dist/decision/receipt.js.map +1 -0
  97. package/dist/decision/request-policy.d.ts +3 -0
  98. package/dist/decision/request-policy.d.ts.map +1 -0
  99. package/dist/decision/request-policy.js +19 -0
  100. package/dist/decision/request-policy.js.map +1 -0
  101. package/dist/decision/request.d.ts +85 -0
  102. package/dist/decision/request.d.ts.map +1 -0
  103. package/dist/decision/request.js +49 -0
  104. package/dist/decision/request.js.map +1 -0
  105. package/dist/decision/service.d.ts +39 -0
  106. package/dist/decision/service.d.ts.map +1 -0
  107. package/dist/decision/service.js +138 -0
  108. package/dist/decision/service.js.map +1 -0
  109. package/dist/decision/structured.d.ts +125 -0
  110. package/dist/decision/structured.d.ts.map +1 -0
  111. package/dist/decision/structured.js +250 -0
  112. package/dist/decision/structured.js.map +1 -0
  113. package/dist/decision/validate-result.d.ts +8 -0
  114. package/dist/decision/validate-result.d.ts.map +1 -0
  115. package/dist/decision/validate-result.js +91 -0
  116. package/dist/decision/validate-result.js.map +1 -0
  117. package/dist/decision/validation-context.d.ts +55 -0
  118. package/dist/decision/validation-context.d.ts.map +1 -0
  119. package/dist/decision/validation-context.js +134 -0
  120. package/dist/decision/validation-context.js.map +1 -0
  121. package/dist/decision/validation.d.ts +19 -0
  122. package/dist/decision/validation.d.ts.map +1 -0
  123. package/dist/decision/validation.js +86 -0
  124. package/dist/decision/validation.js.map +1 -0
  125. package/dist/decision/verdict.d.ts +81 -0
  126. package/dist/decision/verdict.d.ts.map +1 -0
  127. package/dist/decision/verdict.js +140 -0
  128. package/dist/decision/verdict.js.map +1 -0
  129. package/dist/providers.d.ts +4 -3
  130. package/dist/providers.d.ts.map +1 -1
  131. package/dist/providers.js +2 -1
  132. package/dist/providers.js.map +1 -1
  133. package/dist/registry.d.ts +6 -0
  134. package/dist/registry.d.ts.map +1 -1
  135. package/dist/registry.js.map +1 -1
  136. package/dist/transport/jev.d.ts +23 -0
  137. package/dist/transport/jev.d.ts.map +1 -0
  138. package/dist/transport/jev.js +107 -0
  139. package/dist/transport/jev.js.map +1 -0
  140. package/package.json +13 -1
@@ -0,0 +1,11 @@
1
+ import type { DecisionRequest } from './request.js';
2
+ import type { DecisionEvaluatorDescriptor } from './descriptor.js';
3
+ import type { DecisionErrorCode } from './errors.js';
4
+ export interface DecisionHostPolicy {
5
+ timeoutMs?: number;
6
+ maxCostMicroUsd?: string;
7
+ allowRaw?: boolean;
8
+ }
9
+ /** Capability/decision refusal precedes credential acquisition and financial admission. */
10
+ export declare function validateDecisionPolicy(request: DecisionRequest, descriptor: DecisionEvaluatorDescriptor, host?: DecisionHostPolicy): DecisionErrorCode | null;
11
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/decision/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrD,MAAM,WAAW,kBAAkB;IAAG,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE;AACxG,2FAA2F;AAC3F,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,2BAA2B,EACtG,IAAI,GAAE,kBAAuB,GAAG,iBAAiB,GAAG,IAAI,CAqBzD"}
@@ -0,0 +1,33 @@
1
+ import { encodeJevRequest } from './jev-codec.js';
2
+ /** Capability/decision refusal precedes credential acquisition and financial admission. */
3
+ export function validateDecisionPolicy(request, descriptor, host = {}) {
4
+ const encoded = encodeJevRequest(request, descriptor);
5
+ if (!encoded.ok)
6
+ return encoded.code;
7
+ const criterion = encoded.criterion;
8
+ if (descriptor.qualification.servedIdentity !== 'qualified')
9
+ return 'PROVIDER_UNAVAILABLE';
10
+ if (request.policy?.explanation === 'required' || request.decision?.kind === 'provider')
11
+ return 'CAPABILITY_UNSUPPORTED';
12
+ if (request.raw?.mode === 'allowlisted' && host.allowRaw !== true)
13
+ return 'CAPABILITY_UNSUPPORTED';
14
+ if (criterion.kind === 'choice' && criterion.options.some((option) => ['__proto__', 'constructor', 'prototype'].includes(option.id))) {
15
+ return 'CAPABILITY_UNSUPPORTED';
16
+ }
17
+ const rule = request.decision;
18
+ if (rule?.kind === 'threshold') {
19
+ if (criterion.kind === 'choice')
20
+ return 'CAPABILITY_UNSUPPORTED';
21
+ const max = criterion.kind === 'binary' ? 1 : criterion.levels.length - 1;
22
+ if (rule.value < 0 || rule.value > max)
23
+ return 'REQUEST_INVALID';
24
+ }
25
+ if (rule?.kind === 'labels') {
26
+ if (criterion.kind !== 'choice')
27
+ return 'CAPABILITY_UNSUPPORTED';
28
+ if (!rule.passing.every((label) => criterion.options.some((option) => option.id === label)))
29
+ return 'REQUEST_INVALID';
30
+ }
31
+ return null;
32
+ }
33
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/decision/policy.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlD,2FAA2F;AAC3F,MAAM,UAAU,sBAAsB,CAAC,OAAwB,EAAE,UAAuC,EACtG,OAA2B,EAAE;IAC7B,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACtD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC;IACrC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACpC,IAAI,UAAU,CAAC,aAAa,CAAC,cAAc,KAAK,WAAW;QAAE,OAAO,sBAAsB,CAAC;IAC3F,IAAI,OAAO,CAAC,MAAM,EAAE,WAAW,KAAK,UAAU,IAAI,OAAO,CAAC,QAAQ,EAAE,IAAI,KAAK,UAAU;QAAE,OAAO,wBAAwB,CAAC;IACzH,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,wBAAwB,CAAC;IACnG,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACrI,OAAO,wBAAwB,CAAC;IAClC,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC9B,IAAI,IAAI,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;QAC/B,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,wBAAwB,CAAC;QACjE,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1E,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,GAAG;YAAE,OAAO,iBAAiB,CAAC;IACnE,CAAC;IACD,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,wBAAwB,CAAC;QACjE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,iBAAiB,CAAC;IACxH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,40 @@
1
+ import type { DecisionRequest, MicroUsd } from './request.js';
2
+ import type { DecisionBackendProtocol, DecisionEvaluatorDescriptor } from './descriptor.js';
3
+ import type { DecisionCost, DecisionUsage } from './receipt.js';
4
+ /** Projection of the host's existing immutable provider/model price row. The
5
+ * optional authority/protocol cells bind a row to one price authority and
6
+ * backend protocol; present cells must match the descriptor (§3.2
7
+ * Accounting), so two authorities cannot share a revision silently. */
8
+ export interface DecisionPrice {
9
+ providerId: string;
10
+ modelId: string;
11
+ priceRevision: string;
12
+ inputMicroUsdPerMtok: MicroUsd;
13
+ outputMicroUsdPerMtok: MicroUsd;
14
+ minimumMicroUsd: MicroUsd;
15
+ identityMismatchPricing: 'requested-model' | 'requires-reconciliation';
16
+ authority: string;
17
+ protocol: DecisionBackendProtocol;
18
+ }
19
+ export interface DecisionQuote {
20
+ price: DecisionPrice;
21
+ reservedMicroUsd: MicroUsd;
22
+ }
23
+ export declare const isMicroUsd: (value: unknown) => value is string;
24
+ export declare function quoteDecision(request: DecisionRequest, descriptor: DecisionEvaluatorDescriptor, candidate: unknown, hostCap?: MicroUsd): {
25
+ ok: true;
26
+ quote: DecisionQuote;
27
+ } | {
28
+ ok: false;
29
+ code: 'PRICING_UNAVAILABLE' | 'BUDGET_BOUND_UNAVAILABLE' | 'BUDGET_EXHAUSTED';
30
+ };
31
+ /** Uncertain execution uses the reserve, never invented tokens or a zero charge.
32
+ * Any priced component whose usage is unknown keeps the settlement pending
33
+ * and charges at least the full reserve: known input spend never releases
34
+ * the unknown output liability. */
35
+ export declare function priceDecisionUsage(usage: DecisionUsage, quote: DecisionQuote, identityMismatch?: boolean): {
36
+ cost: DecisionCost;
37
+ pending: boolean;
38
+ overrun: boolean;
39
+ };
40
+ //# sourceMappingURL=pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/decision/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC5F,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIhE;;;uEAGuE;AACvE,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAC3D,oBAAoB,EAAE,QAAQ,CAAC;IAAC,qBAAqB,EAAE,QAAQ,CAAC;IAAC,eAAe,EAAE,QAAQ,CAAC;IAC3F,uBAAuB,EAAE,iBAAiB,GAAG,yBAAyB,CAAC;IACvE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,uBAAuB,CAAC;CACtD;AACD,MAAM,WAAW,aAAa;IAAG,KAAK,EAAE,aAAa,CAAC;IAAC,gBAAgB,EAAE,QAAQ,CAAA;CAAE;AACnF,eAAO,MAAM,UAAU,UAAW,OAAO,oBAAoF,CAAC;AAI9H,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,2BAA2B,EAAE,SAAS,EAAE,OAAO,EACjH,OAAO,CAAC,EAAE,QAAQ,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,qBAAqB,GAAG,0BAA0B,GAAG,kBAAkB,CAAA;CAAE,CA6BvJ;AAED;;;mCAGmC;AACnC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,gBAAgB,UAAQ,GACrG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAmB3D"}
@@ -0,0 +1,65 @@
1
+ import { freezeDecisionData } from './descriptor-validation.js';
2
+ import { hasOnlyKeys, isCorrelationId, isRecord, snapshotBoundedJson } from './validation.js';
3
+ export const isMicroUsd = (value) => typeof value === 'string' && /^(0|[1-9][0-9]*)$/.test(value);
4
+ const ceilRate = (tokens, rate) => (BigInt(tokens) * BigInt(rate) + 999999n) / 1000000n;
5
+ const minimum = (value, price) => value > BigInt(price.minimumMicroUsd) ? value : BigInt(price.minimumMicroUsd);
6
+ export function quoteDecision(request, descriptor, candidate, hostCap) {
7
+ const snapshot = snapshotBoundedJson(candidate);
8
+ const value = snapshot.ok ? snapshot.value : null;
9
+ if (!isRecord(value) || !hasOnlyKeys(value, ['providerId', 'modelId', 'priceRevision', 'inputMicroUsdPerMtok',
10
+ 'outputMicroUsdPerMtok', 'minimumMicroUsd', 'identityMismatchPricing', 'authority', 'protocol']) || value.providerId !== descriptor.evaluator.providerId
11
+ || value.modelId !== descriptor.wireModel || value.priceRevision !== descriptor.priceProtocol.revision
12
+ || !isCorrelationId(value.priceRevision)
13
+ || !isMicroUsd(value.inputMicroUsdPerMtok) || !isMicroUsd(value.outputMicroUsdPerMtok) || !isMicroUsd(value.minimumMicroUsd)
14
+ || !['requested-model', 'requires-reconciliation'].some((v) => v === value.identityMismatchPricing)
15
+ || value.authority !== descriptor.priceProtocol.authority
16
+ || value.protocol !== (descriptor.protocol ?? 'jev-native'))
17
+ return { ok: false, code: 'PRICING_UNAVAILABLE' };
18
+ const price = freezeDecisionData(value);
19
+ if (descriptor.qualification.billingBound !== 'qualified')
20
+ return { ok: false, code: 'BUDGET_BOUND_UNAVAILABLE' };
21
+ const isJev = (descriptor.protocol ?? 'jev-native') === 'jev-native';
22
+ // JEV has no qualified output liability bound. A nonzero output rate cannot be reserved.
23
+ if (isJev && price.outputMicroUsdPerMtok !== '0')
24
+ return { ok: false, code: 'BUDGET_BOUND_UNAVAILABLE' };
25
+ // Non-JEV protocols price output work, so quoting requires the descriptor's
26
+ // enforced output/reasoning bound. Without it no finite liability exists.
27
+ const outputBound = descriptor.maxBillableOutputTokens;
28
+ if (!isJev && (typeof outputBound !== 'number' || !Number.isSafeInteger(outputBound) || outputBound < 1)) {
29
+ return { ok: false, code: 'BUDGET_BOUND_UNAVAILABLE' };
30
+ }
31
+ const inputReserve = ceilRate(descriptor.maxBillableInputTokens, price.inputMicroUsdPerMtok);
32
+ const outputReserve = isJev ? 0n : ceilRate(descriptor.maxBillableOutputTokens, price.outputMicroUsdPerMtok);
33
+ const reserve = minimum(inputReserve + outputReserve, price);
34
+ const caps = [hostCap, request.policy?.budget?.maxCostMicroUsd].filter((v) => v !== undefined);
35
+ if (caps.some((cap) => !isMicroUsd(cap)))
36
+ return { ok: false, code: 'PRICING_UNAVAILABLE' };
37
+ if (caps.some((cap) => reserve > BigInt(cap)))
38
+ return { ok: false, code: 'BUDGET_EXHAUSTED' };
39
+ return { ok: true, quote: freezeDecisionData({ price, reservedMicroUsd: reserve.toString() }) };
40
+ }
41
+ /** Uncertain execution uses the reserve, never invented tokens or a zero charge.
42
+ * Any priced component whose usage is unknown keeps the settlement pending
43
+ * and charges at least the full reserve: known input spend never releases
44
+ * the unknown output liability. */
45
+ export function priceDecisionUsage(usage, quote, identityMismatch = false) {
46
+ const input = usage.tokens.input;
47
+ const output = usage.tokens.output;
48
+ const applicable = !identityMismatch || quote.price.identityMismatchPricing === 'requested-model';
49
+ const inputKnown = input.source === 'provider' && applicable;
50
+ const outputKnown = inputKnown && output.source === 'provider';
51
+ const inputPriced = quote.price.inputMicroUsdPerMtok !== '0';
52
+ const outputPriced = quote.price.outputMicroUsdPerMtok !== '0';
53
+ const pricedUnknown = (inputPriced && !inputKnown) || (outputPriced && !outputKnown);
54
+ const inputAmount = inputKnown ? ceilRate(input.value, quote.price.inputMicroUsdPerMtok) : 0n;
55
+ const outputAmount = outputKnown ? ceilRate(output.value, quote.price.outputMicroUsdPerMtok) : 0n;
56
+ const computed = inputKnown || outputKnown ? minimum(inputAmount + outputAmount, quote.price) : BigInt(quote.reservedMicroUsd);
57
+ const reserved = BigInt(quote.reservedMicroUsd);
58
+ const amount = pricedUnknown && computed < reserved ? reserved : computed;
59
+ const fullyUnknown = !inputKnown && !outputKnown;
60
+ return { cost: { status: 'estimated', amountMicroUsd: amount.toString(),
61
+ source: fullyUnknown || pricedUnknown ? 'reserved-liability' : 'reported-usage-times-rate',
62
+ priceRevision: quote.price.priceRevision, rounding: 'ceil-micro-usd' },
63
+ pending: pricedUnknown, overrun: amount > reserved };
64
+ }
65
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/decision/pricing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { DecisionRequest } from './request.js';
2
+ import type { DecisionVerdict } from './verdict.js';
3
+ /** Drop whole optional native fields to fit; never truncate the typed verdict. */
4
+ export declare function makeJevProviderRaw(native: unknown, request: DecisionRequest): DecisionVerdict['providerRaw'];
5
+ /** Raw remains optional, bounded and tied to the already validated native evidence. */
6
+ export declare function parseJevProviderRaw(candidate: unknown, native: unknown, request: DecisionRequest): DecisionVerdict['providerRaw'] | null;
7
+ //# sourceMappingURL=raw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/decision/raw.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAQ,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpD,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAAC,aAAa,CAAC,CAa5G;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAAC,aAAa,CAAC,GAAG,IAAI,CAkBxI"}
@@ -0,0 +1,53 @@
1
+ import { hasOnlyKeys, isRecord, snapshotBoundedJson } from './validation.js';
2
+ const fields = ['noul', 'score', 'choice', 'probabilities', 'confidence'];
3
+ const bytes = (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength;
4
+ const limit = (request) => Math.min(16384, request.raw?.maxBytes ?? 16384);
5
+ /** Drop whole optional native fields to fit; never truncate the typed verdict. */
6
+ export function makeJevProviderRaw(native, request) {
7
+ if (request.raw?.mode !== 'allowlisted' || limit(request) < 2)
8
+ return undefined;
9
+ const snapshot = snapshotBoundedJson(native);
10
+ if (!snapshot.ok || !isRecord(snapshot.value))
11
+ return undefined;
12
+ const data = {};
13
+ let truncated = false;
14
+ for (const field of fields) {
15
+ if (!Object.hasOwn(snapshot.value, field))
16
+ continue;
17
+ const next = { ...data, [field]: snapshot.value[field] };
18
+ if (bytes(next) > limit(request)) {
19
+ truncated = true;
20
+ continue;
21
+ }
22
+ data[field] = snapshot.value[field];
23
+ }
24
+ return { data, bytes: bytes(data), truncated };
25
+ }
26
+ /** Raw remains optional, bounded and tied to the already validated native evidence. */
27
+ export function parseJevProviderRaw(candidate, native, request) {
28
+ const snapshot = snapshotBoundedJson(candidate);
29
+ if (request.raw?.mode !== 'allowlisted' || !snapshot.ok || !isRecord(snapshot.value) || !isRecord(native))
30
+ return null;
31
+ const value = snapshot.value;
32
+ if (!hasOnlyKeys(value, ['data', 'bytes', 'truncated']) || !isRecord(value.data) || !hasOnlyKeys(value.data, fields)
33
+ || typeof value.truncated !== 'boolean' || value.bytes !== bytes(value.data) || bytes(value.data) > limit(request))
34
+ return null;
35
+ const rawData = value.data;
36
+ for (const [field, data] of Object.entries(rawData)) {
37
+ if (!Object.hasOwn(native, field))
38
+ return null;
39
+ const expected = native[field];
40
+ if (isRecord(data) && isRecord(expected)) {
41
+ if (Object.keys(data).length !== Object.keys(expected).length
42
+ || !Object.keys(data).every((key) => data[key] === expected[key]))
43
+ return null;
44
+ }
45
+ else if (data !== native[field])
46
+ return null;
47
+ }
48
+ const omitted = fields.some((field) => Object.hasOwn(native, field) && !Object.hasOwn(rawData, field));
49
+ if (value.truncated !== omitted)
50
+ return null;
51
+ return { data: value.data, bytes: value.bytes, truncated: value.truncated };
52
+ }
53
+ //# sourceMappingURL=raw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw.js","sourceRoot":"","sources":["../../src/decision/raw.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ import type { DecisionError, DecisionErrorCode } from './errors.js';
2
+ import type { EvaluatorRef, DecisionRequest, MicroUsd } from './request.js';
3
+ import type { DecisionVerdict } from './verdict.js';
4
+ export type TokenCounter = {
5
+ value: number;
6
+ source: 'provider';
7
+ } | {
8
+ value: null;
9
+ source: 'not-reported';
10
+ };
11
+ export type TotalTokenCounter = TokenCounter | {
12
+ value: number;
13
+ source: 'derived-sum';
14
+ };
15
+ export interface DecisionUsage {
16
+ tokens: {
17
+ input: TokenCounter;
18
+ output: TokenCounter;
19
+ total: TotalTokenCounter;
20
+ };
21
+ evaluatorCalls: number | null;
22
+ explanations: number | null;
23
+ }
24
+ export type DecisionCost = {
25
+ status: 'actual';
26
+ amountMicroUsd: MicroUsd;
27
+ source: 'provider';
28
+ priceRevision?: string;
29
+ rounding: 'ceil-micro-usd';
30
+ } | {
31
+ status: 'estimated';
32
+ amountMicroUsd: MicroUsd;
33
+ source: 'reported-usage-times-rate' | 'call-rate' | 'reserved-liability';
34
+ priceRevision: string;
35
+ rounding: 'ceil-micro-usd';
36
+ } | {
37
+ status: 'not-incurred';
38
+ amountMicroUsd: '0';
39
+ source: 'no-dispatch';
40
+ };
41
+ export interface RetentionReceipt {
42
+ status: 'non-zdr' | 'unknown' | 'not-evaluated';
43
+ basis: 'published-policy' | 'none';
44
+ evidenceRefs: readonly string[];
45
+ retentionDays: number | null;
46
+ gap?: 'unknown (source-gap)';
47
+ }
48
+ export interface DecisionReceipt {
49
+ schemaVersion: 1;
50
+ callId: string;
51
+ correlationId: string;
52
+ evaluator: EvaluatorRef | null;
53
+ servedEvaluator: EvaluatorRef | null;
54
+ servedModelId: string | null;
55
+ providerRequestId?: string;
56
+ startedAt: string;
57
+ finishedAt: string;
58
+ latencyMs: number;
59
+ providerLatencyMs?: number;
60
+ /** Durable marker dispatch state; 'unknown' on ambiguous marker failure before provider call. */
61
+ dispatch: 'not-started' | 'started' | 'completed' | 'unknown';
62
+ /** Number of provider invocation attempts (0 if marking failed before provider dispatch). */
63
+ attempts: 0 | 1;
64
+ usage: DecisionUsage;
65
+ cost: DecisionCost;
66
+ retention: RetentionReceipt;
67
+ budget: {
68
+ state: 'not-admitted' | 'released' | 'settled' | 'pending-reconciliation';
69
+ reservedMicroUsd?: MicroUsd;
70
+ overrun: boolean;
71
+ };
72
+ outcome: 'verdict' | 'error';
73
+ errorCode?: DecisionErrorCode;
74
+ }
75
+ export type DecisionResult = {
76
+ kind: 'verdict';
77
+ ok: true;
78
+ verdict: DecisionVerdict;
79
+ receipt: DecisionReceipt;
80
+ } | {
81
+ kind: 'error';
82
+ ok: false;
83
+ error: DecisionError;
84
+ receipt: DecisionReceipt;
85
+ };
86
+ export interface DecisionClient {
87
+ decide(request: DecisionRequest, options?: {
88
+ signal?: AbortSignal;
89
+ }): Promise<DecisionResult>;
90
+ }
91
+ export interface DecisionConnectionFailure {
92
+ kind: 'connection-failure';
93
+ ok: false;
94
+ error: DecisionError & {
95
+ code: 'MESH_UNAVAILABLE' | 'TRANSPORT_FAILED' | 'TIMEOUT' | 'CANCELLED';
96
+ };
97
+ receipt: null;
98
+ usage: DecisionUsage;
99
+ callStatus: 'not-sent' | 'unknown';
100
+ correlationId: string;
101
+ }
102
+ export interface RemoteDecisionClient {
103
+ decide(request: DecisionRequest, options?: {
104
+ signal?: AbortSignal;
105
+ }): Promise<DecisionResult | DecisionConnectionFailure>;
106
+ }
107
+ /** Unknown counters stay null even when no dispatch proves zero evaluator calls. */
108
+ export declare function unreportedDecisionUsage(execution: 'not-dispatched' | 'unknown'): DecisionUsage;
109
+ /** Correlation is metadata, never financial idempotency or caller authority. */
110
+ export declare function resolveDecisionCorrelationId(value: string | undefined, generate?: () => string): string | null;
111
+ /** Each counter has independent provenance; only a safe, known total can be derived. */
112
+ export declare function parseDecisionUsage(candidate: unknown): DecisionUsage | null;
113
+ export declare function normalizeDecisionUsage(reported: {
114
+ inputTokens?: number | null;
115
+ outputTokens?: number | null;
116
+ totalTokens?: number | null;
117
+ evaluatorCalls: number | null;
118
+ explanations: number | null;
119
+ }): DecisionUsage | null;
120
+ //# sourceMappingURL=receipt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipt.d.ts","sourceRoot":"","sources":["../../src/decision/receipt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { hasOnlyKeys, isCorrelationId, isRecord, snapshotBoundedJson } from './validation.js';
2
+ /** Unknown counters stay null even when no dispatch proves zero evaluator calls. */
3
+ export function unreportedDecisionUsage(execution) {
4
+ return { tokens: { input: { value: null, source: 'not-reported' },
5
+ output: { value: null, source: 'not-reported' }, total: { value: null, source: 'not-reported' } },
6
+ evaluatorCalls: execution === 'not-dispatched' ? 0 : null,
7
+ explanations: execution === 'not-dispatched' ? 0 : null };
8
+ }
9
+ /** Correlation is metadata, never financial idempotency or caller authority. */
10
+ export function resolveDecisionCorrelationId(value, generate = () => globalThis.crypto.randomUUID()) {
11
+ const candidate = value === undefined ? generate() : value;
12
+ return isCorrelationId(candidate) ? candidate : null;
13
+ }
14
+ const isCount = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
15
+ function isCounter(value, total) {
16
+ return isRecord(value) && hasOnlyKeys(value, ['value', 'source'])
17
+ && (value.source === 'not-reported' ? value.value === null
18
+ : (value.source === 'provider' || (total && value.source === 'derived-sum')) && isCount(value.value));
19
+ }
20
+ /** Each counter has independent provenance; only a safe, known total can be derived. */
21
+ export function parseDecisionUsage(candidate) {
22
+ const snapshot = snapshotBoundedJson(candidate);
23
+ if (!snapshot.ok)
24
+ return null;
25
+ const value = snapshot.value;
26
+ if (!isRecord(value) || !hasOnlyKeys(value, ['tokens', 'evaluatorCalls', 'explanations'])
27
+ || !isRecord(value.tokens) || !hasOnlyKeys(value.tokens, ['input', 'output', 'total'])
28
+ || !isCounter(value.tokens.input, false) || !isCounter(value.tokens.output, false)
29
+ || !isCounter(value.tokens.total, true)
30
+ || (value.evaluatorCalls !== null && !isCount(value.evaluatorCalls))
31
+ || (value.explanations !== null && !isCount(value.explanations)))
32
+ return null;
33
+ const usage = value;
34
+ const { input, output, total } = usage.tokens;
35
+ if (total.source === 'derived-sum') {
36
+ if (input.source !== 'provider' || output.source !== 'provider')
37
+ return null;
38
+ const sum = input.value + output.value;
39
+ if (!isCount(sum) || total.value !== sum)
40
+ return null;
41
+ }
42
+ return { tokens: { input: { ...input }, output: { ...output }, total: { ...total } },
43
+ evaluatorCalls: usage.evaluatorCalls, explanations: usage.explanations };
44
+ }
45
+ export function normalizeDecisionUsage(reported) {
46
+ const counter = (value) => value == null
47
+ ? { value: null, source: 'not-reported' } : { value, source: 'provider' };
48
+ const input = counter(reported.inputTokens);
49
+ const output = counter(reported.outputTokens);
50
+ const total = reported.totalTokens != null
51
+ ? { value: reported.totalTokens, source: 'provider' }
52
+ : input.source === 'provider' && output.source === 'provider'
53
+ ? { value: input.value + output.value, source: 'derived-sum' }
54
+ : { value: null, source: 'not-reported' };
55
+ return parseDecisionUsage({ tokens: { input, output, total }, evaluatorCalls: reported.evaluatorCalls,
56
+ explanations: reported.explanations });
57
+ }
58
+ //# sourceMappingURL=receipt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipt.js","sourceRoot":"","sources":["../../src/decision/receipt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function isRequestPolicy(value: unknown): boolean;
2
+ export declare function isRawPolicy(value: unknown): boolean;
3
+ //# sourceMappingURL=request-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-policy.d.ts","sourceRoot":"","sources":["../../src/decision/request-policy.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOvD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKnD"}
@@ -0,0 +1,19 @@
1
+ import { has, hasOnlyKeys, isMicroUsd, isRecord, DECISION_MAX_RAW_BYTES } from './validation.js';
2
+ export function isRequestPolicy(value) {
3
+ if (!isRecord(value) || !hasOnlyKeys(value, ['budget', 'timeoutMs', 'explanation']))
4
+ return false;
5
+ if (has(value, 'budget') && (!isRecord(value.budget)
6
+ || !hasOnlyKeys(value.budget, ['maxCostMicroUsd']) || !isMicroUsd(value.budget.maxCostMicroUsd)))
7
+ return false;
8
+ if (has(value, 'timeoutMs') && (typeof value.timeoutMs !== 'number'
9
+ || !Number.isSafeInteger(value.timeoutMs) || value.timeoutMs < 1 || value.timeoutMs > 60_000))
10
+ return false;
11
+ return !has(value, 'explanation') || ['none', 'if-available', 'required'].some((v) => v === value.explanation);
12
+ }
13
+ export function isRawPolicy(value) {
14
+ return isRecord(value) && hasOnlyKeys(value, ['mode', 'maxBytes'])
15
+ && (value.mode === 'none' || value.mode === 'allowlisted')
16
+ && (!has(value, 'maxBytes') || (typeof value.maxBytes === 'number'
17
+ && Number.isSafeInteger(value.maxBytes) && value.maxBytes >= 0 && value.maxBytes <= DECISION_MAX_RAW_BYTES));
18
+ }
19
+ //# sourceMappingURL=request-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-policy.js","sourceRoot":"","sources":["../../src/decision/request-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEjG,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAClG,IAAI,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;WAC/C,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACjH,IAAI,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;WAC9D,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9G,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,WAAW,CAAC,CAAC;AACjH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;WAC7D,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC;WACvD,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;eAC7D,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,IAAI,sBAAsB,CAAC,CAAC,CAAC;AACnH,CAAC"}
@@ -0,0 +1,85 @@
1
+ import type { ProviderId } from '../providers.js';
2
+ export type Json = null | boolean | number | string | readonly Json[] | {
3
+ readonly [key: string]: Json;
4
+ };
5
+ /** Canonical nonnegative integer decimal micro-USD, never floating point. */
6
+ export type MicroUsd = string;
7
+ export interface EvaluatorRef {
8
+ providerId: ProviderId;
9
+ evaluatorId: string;
10
+ revision: string;
11
+ }
12
+ export interface DecisionInputs {
13
+ input?: Json;
14
+ output?: Json;
15
+ context?: readonly Json[];
16
+ reference?: Json;
17
+ state?: Json;
18
+ }
19
+ export type DecisionCriterion = {
20
+ kind: 'binary';
21
+ instructions: string;
22
+ criteria?: {
23
+ true: string;
24
+ false: string;
25
+ };
26
+ } | {
27
+ kind: 'graded';
28
+ instructions: string;
29
+ direction: 'higher-is-better' | 'lower-is-better' | 'unordered';
30
+ levels: readonly {
31
+ label: string;
32
+ description: string;
33
+ }[];
34
+ } | {
35
+ kind: 'choice';
36
+ instructions: string;
37
+ options: readonly {
38
+ id: string;
39
+ description: string;
40
+ }[];
41
+ } | {
42
+ kind: 'registered';
43
+ criteriaId: string;
44
+ revision: string;
45
+ };
46
+ export type DecisionRule = {
47
+ kind: 'provider';
48
+ } | {
49
+ kind: 'threshold';
50
+ field: 'score';
51
+ op: 'gte' | 'lte';
52
+ value: number;
53
+ } | {
54
+ kind: 'labels';
55
+ passing: readonly string[];
56
+ };
57
+ export interface DecisionRequest {
58
+ schemaVersion: 1;
59
+ evaluator: EvaluatorRef;
60
+ inputs: DecisionInputs;
61
+ criterion: DecisionCriterion;
62
+ decision?: DecisionRule;
63
+ policy?: {
64
+ budget?: {
65
+ maxCostMicroUsd: MicroUsd;
66
+ };
67
+ timeoutMs?: number;
68
+ explanation?: 'none' | 'if-available' | 'required';
69
+ };
70
+ raw?: {
71
+ mode: 'none' | 'allowlisted';
72
+ maxBytes?: number;
73
+ };
74
+ correlationId?: string;
75
+ }
76
+ export type DecisionRequestParseResult = {
77
+ ok: true;
78
+ request: DecisionRequest;
79
+ } | {
80
+ ok: false;
81
+ code: 'REQUEST_INVALID' | 'CAPABILITY_UNSUPPORTED' | 'PROVIDER_UNKNOWN';
82
+ };
83
+ /** Pure preflight parsing: capabilities and descriptor revisions remain service-owned. */
84
+ export declare function parseDecisionRequest(value: unknown): DecisionRequestParseResult;
85
+ //# sourceMappingURL=request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/decision/request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMlD,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,IAAI,EAAE,GACjE;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AACrC,6EAA6E;AAC7E,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,OAAO,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,KAAK,CAAC,EAAE,IAAI,CAAC;CACd;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACpF;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IACrC,SAAS,EAAE,kBAAkB,GAAG,iBAAiB,GAAG,WAAW,CAAC;IAChE,MAAM,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IACrC,OAAO,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,CAAC,CAAC;IACjB,SAAS,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE;YAAE,eAAe,EAAE,QAAQ,CAAA;SAAE,CAAC;QACvC,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,UAAU,CAAC;KACpD,CAAC;IACF,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,iBAAiB,GAAG,wBAAwB,GAAG,kBAAkB,CAAA;CAAE,CAAC;AAE3F,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAkC/E"}
@@ -0,0 +1,49 @@
1
+ import { isProviderId } from '../providers.js';
2
+ import { isDecisionCriterion, isDecisionRule } from './criterion.js';
3
+ import { isRawPolicy, isRequestPolicy } from './request-policy.js';
4
+ import { has, hasOnlyKeys, isCorrelationId, isRecord, isText, snapshotBoundedJson } from './validation.js';
5
+ /** Pure preflight parsing: capabilities and descriptor revisions remain service-owned. */
6
+ export function parseDecisionRequest(value) {
7
+ const invalid = { ok: false, code: 'REQUEST_INVALID' };
8
+ const snapshot = snapshotBoundedJson(value);
9
+ if (!snapshot.ok)
10
+ return invalid;
11
+ value = snapshot.value;
12
+ if (!isRecord(value))
13
+ return invalid;
14
+ // Unsupported retention policy takes precedence over ordinary extra-property errors.
15
+ if (isRecord(value.policy) && has(value.policy, 'zdr')) {
16
+ return { ok: false, code: 'CAPABILITY_UNSUPPORTED' };
17
+ }
18
+ if (!hasOnlyKeys(value, ['schemaVersion', 'evaluator', 'inputs', 'criterion', 'decision', 'policy', 'raw', 'correlationId'])
19
+ || value.schemaVersion !== 1 || !isRecord(value.evaluator)
20
+ || !hasOnlyKeys(value.evaluator, ['providerId', 'evaluatorId', 'revision'])
21
+ || !isText(value.evaluator.providerId) || !isText(value.evaluator.evaluatorId)
22
+ || !isText(value.evaluator.revision) || !isRecord(value.inputs)
23
+ || !hasOnlyKeys(value.inputs, ['input', 'output', 'context', 'reference', 'state'])
24
+ || (!has(value.inputs, 'output') && !has(value.inputs, 'state'))
25
+ || (has(value.inputs, 'context') && !Array.isArray(value.inputs.context)))
26
+ return invalid;
27
+ const criterion = value.criterion;
28
+ if (!isDecisionCriterion(criterion))
29
+ return invalid;
30
+ if (has(value, 'decision')) {
31
+ const decision = value.decision;
32
+ if (!isDecisionRule(decision))
33
+ return invalid;
34
+ if (decision.kind === 'labels' && criterion.kind !== 'registered') {
35
+ const labels = criterion.kind === 'choice' ? criterion.options.map((v) => v.id)
36
+ : criterion.kind === 'graded' ? criterion.levels.map((v) => v.label) : [];
37
+ if (!decision.passing.every((label) => labels.includes(label)))
38
+ return invalid;
39
+ }
40
+ }
41
+ if ((has(value, 'policy') && !isRequestPolicy(value.policy))
42
+ || (has(value, 'raw') && !isRawPolicy(value.raw))
43
+ || (has(value, 'correlationId') && !isCorrelationId(value.correlationId)))
44
+ return invalid;
45
+ if (!isProviderId(value.evaluator.providerId))
46
+ return { ok: false, code: 'PROVIDER_UNKNOWN' };
47
+ return { ok: true, request: value };
48
+ }
49
+ //# sourceMappingURL=request.js.map