@bivelio/savings-layer 0.3.0 → 0.3.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.
- package/README.md +4 -2
- package/dist/index.d.ts +543 -35
- package/dist/index.js +23 -23
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,26 @@ declare class SavingsLedger {
|
|
|
78
78
|
discoveryInput: number;
|
|
79
79
|
/** OUTPUT of the discovery probe. Our cost, kept out of the baseline. */
|
|
80
80
|
discoveryOutput: number;
|
|
81
|
+
/**
|
|
82
|
+
* Already-priced cost of a call the model cascade made to a cheaper model
|
|
83
|
+
* whose answer was NOT served. Added to `actual`, never to the baseline.
|
|
84
|
+
*/
|
|
85
|
+
extraCostUsd: number;
|
|
86
|
+
/** Input tokens of that call. Published by the pipeline, not priced here. */
|
|
87
|
+
cascadeInput: number;
|
|
88
|
+
/** Output tokens of that call. Published by the pipeline, not priced here. */
|
|
89
|
+
cascadeOutput: number;
|
|
90
|
+
/**
|
|
91
|
+
* Record a call to the cheap model that did not produce the served answer:
|
|
92
|
+
* the one discarded on an escalation, or a shadow-mode sample.
|
|
93
|
+
*
|
|
94
|
+
* The caller raises `actualLlm`, because the call happened and the report owes
|
|
95
|
+
* the reader that count.
|
|
96
|
+
*/
|
|
97
|
+
cascadeAttempt(usage: {
|
|
98
|
+
inputTokens: number;
|
|
99
|
+
outputTokens: number;
|
|
100
|
+
}, cheapPrice: CostModel): void;
|
|
81
101
|
/**
|
|
82
102
|
* Lo que de verdad hizo la compresión, para publicarlo en
|
|
83
103
|
* `SavingsReport.compression`. El campo estaba declarado en el contrato y no lo
|
|
@@ -252,21 +272,55 @@ interface SavingsToggles {
|
|
|
252
272
|
deterministicResolvers?: boolean;
|
|
253
273
|
router?: boolean;
|
|
254
274
|
/**
|
|
255
|
-
* OPT-IN
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
275
|
+
* OPT-IN, AND WHETHER IT SAVES OR COSTS DEPENDS ON THE MODEL. Read this whole
|
|
276
|
+
* entry before switching it on.
|
|
277
|
+
*
|
|
278
|
+
* It sends the provider a compacted form of your output contract — short
|
|
279
|
+
* property keys, short enum codes — and expands the reply back to YOUR shape
|
|
280
|
+
* before it is validated, cached or returned. What you receive in `data`,
|
|
281
|
+
* `text` and `rendered` is identical either way, and the layer proves that
|
|
282
|
+
* round trip is exact before it applies anything.
|
|
283
|
+
*
|
|
284
|
+
* WHAT LIVE A/Bs MEASURED, same triage contract, same prompts, 8 paired
|
|
285
|
+
* repetitions each. Input fell identically on both models, from 184 to 158
|
|
286
|
+
* tokens — that part is deterministic, it is the smaller contract. Output did
|
|
287
|
+
* not: `gpt-4o` wrote 3 tokens FEWER and the request came out 8.0% cheaper,
|
|
288
|
+
* while `gpt-4o-mini` wrote 16 tokens MORE and the request came out 8.2% more
|
|
289
|
+
* expensive. Short field names appear to give a smaller model less to go on,
|
|
290
|
+
* so it fills in more, and output is billed around 4x input on that family.
|
|
260
291
|
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
292
|
+
* SO THE LEVER APPLIES ONLY WHERE THAT DELTA HAS BEEN MEASURED. It cannot be
|
|
293
|
+
* read off a schema — the schema was identical in both runs — so the layer
|
|
294
|
+
* does not guess. It uses, in order: the delta you measured and passed in
|
|
295
|
+
* {@link SavingsToggles.outputCodebookMeasuredOutputDeltaTokens}; the same
|
|
296
|
+
* delta remembered from an earlier request for that contract and model; the
|
|
297
|
+
* delta BiVelio has published for that model. With none of those it skips and
|
|
298
|
+
* says so in `report.traces`, including the exact break-even for your contract
|
|
299
|
+
* so you know what a measurement would have to beat.
|
|
268
300
|
*/
|
|
269
301
|
outputCodebook?: boolean;
|
|
302
|
+
/**
|
|
303
|
+
* The output-token delta you MEASURED for the contract on this request, with
|
|
304
|
+
* {@link SavingsToggles.outputCodebook} on versus off, against the model you
|
|
305
|
+
* are sending it to. POSITIVE means the compact contract made the model write
|
|
306
|
+
* FEWER output tokens; negative means it wrote more.
|
|
307
|
+
*
|
|
308
|
+
* This is what lets the layer apply the codebook on a model it has not
|
|
309
|
+
* published a figure for, and it overrides the published one when it has —
|
|
310
|
+
* your traffic beats our benchmark. A negative delta switches the lever off
|
|
311
|
+
* for that model: the input win is capped by the size of your schema while the
|
|
312
|
+
* output loss grows with the answer, so no schema is large enough to buy it
|
|
313
|
+
* back.
|
|
314
|
+
*
|
|
315
|
+
* It belongs to ONE contract against ONE model, which is why it travels on the
|
|
316
|
+
* request rather than the layer config: a delta measured on your triage
|
|
317
|
+
* contract says nothing about your extraction contract, and one measured on
|
|
318
|
+
* `gpt-4o` says nothing about `gpt-4o-mini` — those two came out with opposite
|
|
319
|
+
* signs. Measure it with a paired A/B over the same prompts, which is what
|
|
320
|
+
* `benchmarks/ab-live.ts` in this package does, and measure it again when you
|
|
321
|
+
* change model, contract or prompt.
|
|
322
|
+
*/
|
|
323
|
+
outputCodebookMeasuredOutputDeltaTokens?: number;
|
|
270
324
|
/**
|
|
271
325
|
* OPT-IN, and it changes the latency contract: where it applies, one request
|
|
272
326
|
* becomes TWO provider calls, one after the other.
|
|
@@ -306,6 +360,249 @@ interface SavingsToggles {
|
|
|
306
360
|
* action can be lost to a discovery step.
|
|
307
361
|
*/
|
|
308
362
|
toolDiscovery?: boolean;
|
|
363
|
+
/**
|
|
364
|
+
* Send the request to a CHEAPER model of the same family, check the answer
|
|
365
|
+
* with a deterministic gate, and fall back to the model you asked for only
|
|
366
|
+
* when that gate rejects it. Defaults to `"off"`.
|
|
367
|
+
*
|
|
368
|
+
* It is the only lever here that changes the price of the WHOLE bill — input
|
|
369
|
+
* and output — instead of one axis of it. Read {@link ModelCascadeMode} for
|
|
370
|
+
* what each mode does, and {@link ModelCascadeReport} for the failure this
|
|
371
|
+
* cannot protect you from. Start at `"shadow"`.
|
|
372
|
+
*/
|
|
373
|
+
modelCascade?: ModelCascadeMode;
|
|
374
|
+
/**
|
|
375
|
+
* Declare that this answer is NOT needed immediately, so the layer may ask the
|
|
376
|
+
* provider for a cheaper, slower processing tier. Defaults to `false`.
|
|
377
|
+
*
|
|
378
|
+
* YOU DECLARE IT; THE LAYER NEVER GUESSES. Whether a request can wait is a
|
|
379
|
+
* property of your business, not of the text: the same prompt is deferrable in
|
|
380
|
+
* a nightly enrichment job and not deferrable behind a user's cursor. There is
|
|
381
|
+
* no heuristic that can tell those apart, so there is no default that could be
|
|
382
|
+
* right.
|
|
383
|
+
*
|
|
384
|
+
* IT CHANGES YOUR LATENCY, AND THAT IS THE WHOLE POINT. Where a cheaper tier
|
|
385
|
+
* exists it is slower and its latency is variable, so a request on a
|
|
386
|
+
* user-facing path must not carry this. `report.deferred.latency` states what
|
|
387
|
+
* the provider documents. Nothing else about the request changes: same model,
|
|
388
|
+
* same prompt, same sampling controls, so the answer is the answer you would
|
|
389
|
+
* have got.
|
|
390
|
+
*
|
|
391
|
+
* WHAT IT IS WORTH IS READ BACK, NEVER ASSUMED. A provider short on capacity
|
|
392
|
+
* may serve the standard tier and bill the standard rate without saying so in
|
|
393
|
+
* the response body's shape. The layer therefore reads the tier the provider
|
|
394
|
+
* reports having SERVED and credits only that — see
|
|
395
|
+
* {@link DeferredExecutionReport}. On a provider with no cheaper synchronous
|
|
396
|
+
* tier the request is sent unchanged and the report says so.
|
|
397
|
+
*/
|
|
398
|
+
deferrable?: boolean;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* What asking for a cheaper processing tier actually got you on this request.
|
|
402
|
+
*
|
|
403
|
+
* Present whenever `savings.deferrable` is `true`, INCLUDING when it earned
|
|
404
|
+
* nothing — "we asked and did not get it" is the answer you need most often, and
|
|
405
|
+
* it is the one a report that only spoke on success would hide.
|
|
406
|
+
*
|
|
407
|
+
* ⚠️ THE FAILURE THIS EXISTS TO PREVENT. Asking for a discounted tier is not
|
|
408
|
+
* getting one. Providers document that a request may be served at a different
|
|
409
|
+
* tier from the one it asked for and billed at that tier's rate, and the
|
|
410
|
+
* downgrade is silent: the answer comes back looking exactly the same. A layer
|
|
411
|
+
* that credited the tier it REQUESTED would publish a discount your invoice does
|
|
412
|
+
* not carry, on every request the provider quietly downgraded.
|
|
413
|
+
*
|
|
414
|
+
* So {@link servedTier} is read from the provider's response and it is the only
|
|
415
|
+
* thing {@link credited} is allowed to depend on. When the provider reports no
|
|
416
|
+
* tier at all, nothing is credited: an absent value means "cannot be known", not
|
|
417
|
+
* "standard".
|
|
418
|
+
*/
|
|
419
|
+
interface DeferredExecutionReport {
|
|
420
|
+
/** The tier the layer asked the provider for, absent if it asked for none. */
|
|
421
|
+
requestedTier?: string;
|
|
422
|
+
/**
|
|
423
|
+
* The tier the provider reports having SERVED, exactly as it named it. Absent
|
|
424
|
+
* when the provider reported none.
|
|
425
|
+
*/
|
|
426
|
+
servedTier?: string;
|
|
427
|
+
/**
|
|
428
|
+
* Whether the served tier bills BELOW the standard rate card, which is the
|
|
429
|
+
* only condition under which a discount is claimed here.
|
|
430
|
+
*/
|
|
431
|
+
credited: boolean;
|
|
432
|
+
/**
|
|
433
|
+
* Fraction of the standard list price the served tier bills — `0.5` for a tier
|
|
434
|
+
* documented at half price. Present only when {@link credited}.
|
|
435
|
+
*/
|
|
436
|
+
discountRate?: number;
|
|
437
|
+
/**
|
|
438
|
+
* What the tier was worth on this request, in your currency unit.
|
|
439
|
+
*
|
|
440
|
+
* A COUNTERFACTUAL priced from the standard rate card: this request was not
|
|
441
|
+
* also run at standard price, so it is `(1 - discountRate)` applied to the
|
|
442
|
+
* standard-rate cost of THE ONE CALL whose {@link servedTier} was read.
|
|
443
|
+
*
|
|
444
|
+
* ⚠️ IT IS NOT `cost.actual * (1 - discountRate)`, and the difference is not
|
|
445
|
+
* rounding. `cost.actual` is the whole request: it can also carry a repair
|
|
446
|
+
* retry, a tool-discovery probe, or a model-cascade attempt that was tried and
|
|
447
|
+
* thrown away. No tier was read back for any of those, so none of them is
|
|
448
|
+
* credited here even though they very likely got the discount too. Compute the
|
|
449
|
+
* product yourself and you will get a LARGER number than this field — this
|
|
450
|
+
* field is the part that was actually observed.
|
|
451
|
+
*
|
|
452
|
+
* ⚠️ `cost.actual` prices this request at the STANDARD rate card, so when this
|
|
453
|
+
* field is present your invoice line will be LOWER than `cost.actual` by at
|
|
454
|
+
* least this amount. The bias is deliberate and it is the safe one: the layer
|
|
455
|
+
* under-reports the saving rather than promising one it cannot prove. The
|
|
456
|
+
* reason it is not folded in is {@link creditedLedger}.
|
|
457
|
+
*/
|
|
458
|
+
estimatedTierSaving?: number;
|
|
459
|
+
/**
|
|
460
|
+
* Which of the four ledgers this credits: none, and that is the honest answer.
|
|
461
|
+
* Deferring avoids no call (ledger 1), removes no tokens (2), re-encodes
|
|
462
|
+
* nothing (3) and is not provider caching (4). It changes the PRICE of the
|
|
463
|
+
* tokens, exactly as the model cascade does, and there is no ledger for that.
|
|
464
|
+
*
|
|
465
|
+
* `cost.netSavings` therefore does not move: it is a ratio of baseline to
|
|
466
|
+
* actual priced from a SINGLE rate card, and a discount that scales both sides
|
|
467
|
+
* cannot change it. Folding this in would require a baseline priced from the
|
|
468
|
+
* other card — a request nobody ran.
|
|
469
|
+
*/
|
|
470
|
+
creditedLedger: "none";
|
|
471
|
+
/**
|
|
472
|
+
* What the provider documents about this tier's latency, in one sentence.
|
|
473
|
+
*
|
|
474
|
+
* It is a quotation of what is published, not an estimate. Where a provider
|
|
475
|
+
* commits to no latency figure, this says so rather than inventing one.
|
|
476
|
+
*/
|
|
477
|
+
latency: string;
|
|
478
|
+
/** Why it did what it did, in one sentence. Never empty. */
|
|
479
|
+
reason: string;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* How much authority the model cascade has over your requests.
|
|
483
|
+
*
|
|
484
|
+
* - `"off"` (default) it neither measures nor decides. Nothing changes.
|
|
485
|
+
* - `"shadow"` it MEASURES and reports, and never changes your model. Every
|
|
486
|
+
* request still goes to the model you asked for. The report gains
|
|
487
|
+
* a {@link ModelCascadeReport} saying which cheaper model was
|
|
488
|
+
* eligible, what the arithmetic says about it, and what the swap
|
|
489
|
+
* would have been worth on THIS request. Costs nothing extra
|
|
490
|
+
* unless you also set `modelCascade.shadowSampleRate` on the
|
|
491
|
+
* layer, which is a separate, priced opt-in.
|
|
492
|
+
* - `"on"` it routes for real. Opt-in, never silent: the report always
|
|
493
|
+
* declares the model that served the answer, and a request served
|
|
494
|
+
* by a cheaper model is labelled `bounded_degradation`.
|
|
495
|
+
*
|
|
496
|
+
* `"on"` carries a gate: when a workload's measured escalation rate reaches the
|
|
497
|
+
* break-even, the cascade turns ITSELF off for that workload and says so. That
|
|
498
|
+
* gate protects your BILL. It cannot protect quality — see
|
|
499
|
+
* {@link ModelCascadeReport}.
|
|
500
|
+
*/
|
|
501
|
+
type ModelCascadeMode = "off" | "shadow" | "on";
|
|
502
|
+
/**
|
|
503
|
+
* What the model cascade did, or would have done, on this request.
|
|
504
|
+
*
|
|
505
|
+
* Present whenever `savings.modelCascade` is not `"off"` — including when the
|
|
506
|
+
* request was not eligible, because "we did not route this and here is why" is
|
|
507
|
+
* the answer you need most often.
|
|
508
|
+
*
|
|
509
|
+
* ⚠️ READ THIS BEFORE YOU TURN THE CASCADE ON.
|
|
510
|
+
*
|
|
511
|
+
* The gate that decides whether a cheap answer is good enough is DETERMINISTIC,
|
|
512
|
+
* which is what makes the saving real: an LLM judge would cost the very money
|
|
513
|
+
* this lever exists to save. But a deterministic gate measures FORM, not
|
|
514
|
+
* MEANING. An answer with impeccable JSON and the wrong content passes it.
|
|
515
|
+
*
|
|
516
|
+
* That failure is invisible by construction. It lowers the escalation rate, it
|
|
517
|
+
* raises the reported saving, and the automatic shut-off never fires — because
|
|
518
|
+
* the shut-off watches the escalation rate, and the escalation rate looks
|
|
519
|
+
* excellent. It has the same signature as success, and it surfaces weeks later
|
|
520
|
+
* as customer complaints.
|
|
521
|
+
*
|
|
522
|
+
* So: `escalationRate` is a MONEY figure. Its complement is not a quality score,
|
|
523
|
+
* and this report deliberately does not publish one. If you need evidence about
|
|
524
|
+
* quality, run an A/B on your own traffic. `divergedOnSample` (from shadow
|
|
525
|
+
* sampling) is a hint that something is wrong, never proof that nothing is.
|
|
526
|
+
*/
|
|
527
|
+
interface ModelCascadeReport {
|
|
528
|
+
mode: ModelCascadeMode;
|
|
529
|
+
/** The model the caller asked for. */
|
|
530
|
+
requestedModel: string;
|
|
531
|
+
/**
|
|
532
|
+
* The model that actually produced the answer. In `"shadow"` this always
|
|
533
|
+
* equals {@link requestedModel}; in `"on"` it is the cheap model when its
|
|
534
|
+
* answer was accepted, and the requested one when it was escalated.
|
|
535
|
+
*/
|
|
536
|
+
servedModel: string;
|
|
537
|
+
/** The cheaper model this request was (or would have been) routed to. */
|
|
538
|
+
candidateModel?: string;
|
|
539
|
+
/** Whether the cascade was allowed to consider this request at all. */
|
|
540
|
+
eligible: boolean;
|
|
541
|
+
/** Why it did what it did, in one sentence. Never empty. */
|
|
542
|
+
reason: string;
|
|
543
|
+
/** What the deterministic gate is able to check here. */
|
|
544
|
+
verifier: "none" | "structural" | "value-constrained";
|
|
545
|
+
/**
|
|
546
|
+
* cost(cheap) / cost(strong), worst case over any token mix. The saving on
|
|
547
|
+
* routed traffic is `1 - r - escalationRate`.
|
|
548
|
+
*/
|
|
549
|
+
costRatio?: number;
|
|
550
|
+
/** Escalation rate above which routing costs MORE than not routing (`1 - r`). */
|
|
551
|
+
breakEvenEscalationRate?: number;
|
|
552
|
+
/** Escalation rate above which routing stops hitting the target capture. */
|
|
553
|
+
targetEscalationRate?: number;
|
|
554
|
+
/** Opaque, stable id of the workload these rates are measured over. */
|
|
555
|
+
workload?: string;
|
|
556
|
+
/** Measured escalation rate for this workload, or absent if nothing measured yet. */
|
|
557
|
+
escalationRate?: number;
|
|
558
|
+
/** How many requests that rate is measured over. */
|
|
559
|
+
escalationSamples?: number;
|
|
560
|
+
/** Whether THIS request was escalated to the requested model after the gate rejected it. */
|
|
561
|
+
escalated?: boolean;
|
|
562
|
+
/**
|
|
563
|
+
* What swapping the model was worth on this request, in your currency unit.
|
|
564
|
+
*
|
|
565
|
+
* A COUNTERFACTUAL: the strong model was not run, so this is priced from the
|
|
566
|
+
* measured token counts at both list prices. It is deliberately NOT part of
|
|
567
|
+
* `cost.netSavings` — that number stays a comparison at a single price, and
|
|
568
|
+
* this one would inflate it with a call nobody made. Negative on an escalated
|
|
569
|
+
* request, which is exactly what an escalation costs you.
|
|
570
|
+
*/
|
|
571
|
+
estimatedSwapSaving?: number;
|
|
572
|
+
/**
|
|
573
|
+
* Which of the four ledgers this credits: none, and that is the honest answer.
|
|
574
|
+
* Routing avoids no call (ledger 1), removes no tokens (2), re-encodes nothing
|
|
575
|
+
* (3) and is not provider caching (4). It changes the PRICE of the tokens, and
|
|
576
|
+
* there is no ledger for that.
|
|
577
|
+
*/
|
|
578
|
+
creditedLedger: "none";
|
|
579
|
+
/**
|
|
580
|
+
* Input tokens of the cheap call whose answer was NOT served — the attempt
|
|
581
|
+
* discarded on an escalation, or a shadow-mode sample.
|
|
582
|
+
*
|
|
583
|
+
* They are deliberately absent from `tokens.actualInput`: another model billed
|
|
584
|
+
* them at another price, and that block is priced with a single cost model, so
|
|
585
|
+
* folding them in would price them wrong. Their MONEY is in `cost.actual`.
|
|
586
|
+
* These two fields are what closes the gap, so
|
|
587
|
+
* `tokens.actualInput * inputPer1k + tokens.actualOutput * outputPer1k` plus
|
|
588
|
+
* the cheap model's price applied here accounts for `cost.actual` in full.
|
|
589
|
+
*/
|
|
590
|
+
cascadeInputTokens?: number;
|
|
591
|
+
/** Output tokens of that same unserved call. See {@link cascadeInputTokens}. */
|
|
592
|
+
cascadeOutputTokens?: number;
|
|
593
|
+
/** Whether this shadow request paid for an extra cheap call to measure the rate. */
|
|
594
|
+
sampled?: boolean;
|
|
595
|
+
/** What that extra call cost, in your currency unit. */
|
|
596
|
+
sampleCost?: number;
|
|
597
|
+
/**
|
|
598
|
+
* On a sampled request where BOTH answers satisfied the contract: whether they
|
|
599
|
+
* disagree on a hard value (a number, a boolean, a short code).
|
|
600
|
+
*
|
|
601
|
+
* A hint about false valids, and nothing more. It only covers sampled traffic,
|
|
602
|
+
* disagreement is not proof the cheap answer is the wrong one, and agreement
|
|
603
|
+
* is not proof either answer is right.
|
|
604
|
+
*/
|
|
605
|
+
divergedOnSample?: boolean;
|
|
309
606
|
}
|
|
310
607
|
interface RequestContext {
|
|
311
608
|
tenantId?: string;
|
|
@@ -395,6 +692,14 @@ type CacheOutcome = "miss" | "exact" | "semantic" | "singleflight" | "determinis
|
|
|
395
692
|
* on top of any similarity score.
|
|
396
693
|
* - `not_verified` the model was called and nothing beyond the shape of the
|
|
397
694
|
* answer was checked. The honest default, and the common case.
|
|
695
|
+
* - `bounded_degradation`
|
|
696
|
+
* the answer was produced by a model CHEAPER than the one
|
|
697
|
+
* you asked for, and it cleared the deterministic gate for
|
|
698
|
+
* its output contract before being served. The bound is
|
|
699
|
+
* exactly what that gate checks — shape, and whatever value
|
|
700
|
+
* constraints your contract declares. NOT meaning: a
|
|
701
|
+
* well-formed answer with wrong content earns this label
|
|
702
|
+
* too. See {@link ModelCascadeReport}.
|
|
398
703
|
* - `rejected` what was served does not satisfy its output contract, and
|
|
399
704
|
* a repair either failed or would have been a wasted call.
|
|
400
705
|
* The answer is still returned: this is the layer's verdict
|
|
@@ -405,10 +710,19 @@ type CacheOutcome = "miss" | "exact" | "semantic" | "singleflight" | "determinis
|
|
|
405
710
|
* the day they can demonstrate it. Read this as an OPEN set — keep a default
|
|
406
711
|
* branch, exactly as with a licence status.
|
|
407
712
|
*/
|
|
408
|
-
declare const QUALITY_STATUSES: readonly ["exact", "task_equivalent", "not_verified", "rejected"];
|
|
713
|
+
declare const QUALITY_STATUSES: readonly ["exact", "task_equivalent", "not_verified", "bounded_degradation", "rejected"];
|
|
409
714
|
type QualityStatus = (typeof QUALITY_STATUSES)[number];
|
|
410
715
|
interface SavingsReport {
|
|
411
716
|
requestId: string;
|
|
717
|
+
/**
|
|
718
|
+
* The model that produced this answer.
|
|
719
|
+
*
|
|
720
|
+
* Equal to the model you asked for, EXCEPT when `savings.modelCascade` is
|
|
721
|
+
* `"on"` and a cheaper model's answer cleared the deterministic gate — then
|
|
722
|
+
* this names the cheaper model, because that is what ran and what your bill
|
|
723
|
+
* will show. `report.modelCascade.requestedModel` always holds what you asked
|
|
724
|
+
* for. Changing your model is never silent.
|
|
725
|
+
*/
|
|
412
726
|
model: string;
|
|
413
727
|
calls: {
|
|
414
728
|
baselineLlm: number;
|
|
@@ -480,6 +794,17 @@ interface SavingsReport {
|
|
|
480
794
|
* the `exact` label.
|
|
481
795
|
*/
|
|
482
796
|
qualityStatus?: QualityStatus;
|
|
797
|
+
/**
|
|
798
|
+
* What the model cascade did, or would have done. Present whenever
|
|
799
|
+
* `savings.modelCascade` is not `"off"`. Read its docstring before turning the
|
|
800
|
+
* cascade on: it documents a failure mode no gate in this layer can catch.
|
|
801
|
+
*/
|
|
802
|
+
modelCascade?: ModelCascadeReport;
|
|
803
|
+
/**
|
|
804
|
+
* What asking for a cheaper processing tier got you. Present whenever
|
|
805
|
+
* `savings.deferrable` is `true`, including when it got you nothing.
|
|
806
|
+
*/
|
|
807
|
+
deferred?: DeferredExecutionReport;
|
|
483
808
|
quality: {
|
|
484
809
|
taskPassed?: boolean;
|
|
485
810
|
/**
|
|
@@ -524,10 +849,14 @@ interface SavingsReport {
|
|
|
524
849
|
* Structural license gate the pipeline consults before enabling a managed
|
|
525
850
|
* feature (semantic cache, learned thresholds, long-context compression, …).
|
|
526
851
|
*
|
|
527
|
-
* It is intentionally a bare shape
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
852
|
+
* It is intentionally a bare shape, so any object with these methods works and
|
|
853
|
+
* the SDK never has to import a licensing package.
|
|
854
|
+
*
|
|
855
|
+
* There is no ungated mode: with no gate and no `licenseKey`, `generate()`
|
|
856
|
+
* throws {@link LicenseError} on entry. In the published npm package an injected
|
|
857
|
+
* gate is ignored entirely — a `licenseKey` verified against BiVelio's embedded
|
|
858
|
+
* public key is the only accepted license there, and this interface is what that
|
|
859
|
+
* key is turned into internally.
|
|
531
860
|
*/
|
|
532
861
|
interface LicenseGate {
|
|
533
862
|
isEntitled(feature: string): boolean;
|
|
@@ -783,6 +1112,14 @@ declare function normalizeText(text: string): string;
|
|
|
783
1112
|
declare function sha256(input: string): string;
|
|
784
1113
|
/** Stable JSON stringify with sorted keys so hashes are order-independent. */
|
|
785
1114
|
declare function stableStringify(value: unknown): string;
|
|
1115
|
+
/**
|
|
1116
|
+
* The version-and-size-independent family of a model id.
|
|
1117
|
+
*
|
|
1118
|
+
* Exported because the cache key is now built for the model that will actually
|
|
1119
|
+
* ANSWER, which is not always the one the caller named. Deriving the family a
|
|
1120
|
+
* second time somewhere else is how two rulers start to disagree.
|
|
1121
|
+
*/
|
|
1122
|
+
declare function modelFamilyOf(model: string): string;
|
|
786
1123
|
declare function canonicalize(request: SavingsRequest): CanonicalRequest;
|
|
787
1124
|
|
|
788
1125
|
/**
|
|
@@ -792,8 +1129,21 @@ declare function canonicalize(request: SavingsRequest): CanonicalRequest;
|
|
|
792
1129
|
* text but differ in tenant, permission scope, model version, system prompt,
|
|
793
1130
|
* schema, toolset, locale, sampling, knowledge epoch or safety policy — any of
|
|
794
1131
|
* which can change the correct answer. The exact key includes all of them.
|
|
1132
|
+
*
|
|
1133
|
+
* `servedModel` CARRIES THE MODEL THAT WILL ACTUALLY ANSWER, not the one the
|
|
1134
|
+
* caller named, and that distinction is what stops the model cascade from
|
|
1135
|
+
* poisoning the cache. Routing to a cheap model and storing its answer under the
|
|
1136
|
+
* STRONG model's key would hand that answer to the next request — one with the
|
|
1137
|
+
* cascade off, or from another process entirely — while the report claims the
|
|
1138
|
+
* requested model served it. That is a silent model swap, deferred, which is the
|
|
1139
|
+
* worst kind of silent model swap.
|
|
1140
|
+
*
|
|
1141
|
+
* `modelFamily` is derived from whichever id is used, for the same reason: it is
|
|
1142
|
+
* part of the identity of whoever answers.
|
|
795
1143
|
*/
|
|
796
|
-
declare function buildExactKey(c: CanonicalRequest
|
|
1144
|
+
declare function buildExactKey(c: CanonicalRequest, opciones?: {
|
|
1145
|
+
servedModel?: string;
|
|
1146
|
+
}): string;
|
|
797
1147
|
/**
|
|
798
1148
|
* In-flight (singleflight) key. Coalesces concurrent, equivalent requests onto
|
|
799
1149
|
* a single execution. It can be slightly looser than the exact key (it does not
|
|
@@ -804,8 +1154,37 @@ declare function buildExactKey(c: CanonicalRequest): string;
|
|
|
804
1154
|
* two concurrent calls that differ only in `schemaVersion` are different
|
|
805
1155
|
* requests and must never coalesce. All three doors — exact key, in-flight key
|
|
806
1156
|
* and semantic filter — key on the same identity, by design.
|
|
807
|
-
|
|
808
|
-
|
|
1157
|
+
*
|
|
1158
|
+
* `servedModel` CARRIES THE MODEL THAT WILL ACTUALLY ANSWER, for the same reason
|
|
1159
|
+
* {@link buildExactKey} does, and this door is the one that leaks FIRST. The
|
|
1160
|
+
* exact key protects the answer AFTER it is stored; this one protects it while
|
|
1161
|
+
* it is still being written, and a follower does not re-run anything — it is
|
|
1162
|
+
* handed the leader's text verbatim.
|
|
1163
|
+
*
|
|
1164
|
+
* The leak it closes, measured: two concurrent requests for the same text, one
|
|
1165
|
+
* with `savings.modelCascade: "on"` and one with the cascade OFF, coalesced onto
|
|
1166
|
+
* one execution. The routed leader called the cheap model, and the caller who
|
|
1167
|
+
* never opted in — whose own decision was "do not route" — was served the cheap
|
|
1168
|
+
* model's answer. Same shape inside a single uniformly-configured deployment:
|
|
1169
|
+
* the automatic shut-off can latch between two concurrent requests, so one is
|
|
1170
|
+
* routed and the other is not, and coalescing hands one of them the other's
|
|
1171
|
+
* model. Whoever the layer decided must go to the strong model has to actually
|
|
1172
|
+
* go there.
|
|
1173
|
+
*
|
|
1174
|
+
* `deferrable` CLOSES THE SAME HOLE ON THE LATENCY AXIS, which is why it belongs
|
|
1175
|
+
* here and NOT in {@link buildExactKey}. The two doors do not risk the same
|
|
1176
|
+
* thing: the exact key hands out an answer that is ALREADY WRITTEN, where the
|
|
1177
|
+
* processing tier only picked a queue and changes neither the text nor the wait
|
|
1178
|
+
* of whoever receives it. This one binds a follower to a call that HAS NOT COME
|
|
1179
|
+
* BACK YET, so it imposes the leader's wait on them.
|
|
1180
|
+
*
|
|
1181
|
+
* A caller who never set `savings.deferrable` must not be made to wait for one
|
|
1182
|
+
* who did.
|
|
1183
|
+
*/
|
|
1184
|
+
declare function buildInflightKey(c: CanonicalRequest, opciones?: {
|
|
1185
|
+
servedModel?: string;
|
|
1186
|
+
deferrable?: boolean;
|
|
1187
|
+
}): string;
|
|
809
1188
|
|
|
810
1189
|
/**
|
|
811
1190
|
* Policy engine: risk and freshness.
|
|
@@ -1604,6 +1983,19 @@ interface ProviderRequest {
|
|
|
1604
1983
|
* carry tenant or user data, because it does not isolate anything.
|
|
1605
1984
|
*/
|
|
1606
1985
|
promptCacheKey?: string;
|
|
1986
|
+
/**
|
|
1987
|
+
* The caller declares this answer is not needed immediately, so the adapter
|
|
1988
|
+
* may ask for a cheaper, slower processing tier.
|
|
1989
|
+
*
|
|
1990
|
+
* It is DECLARED, never inferred: whether a request can wait is a property of
|
|
1991
|
+
* the business, not of the text. An adapter whose provider has no cheaper
|
|
1992
|
+
* synchronous tier leaves the request unchanged.
|
|
1993
|
+
*
|
|
1994
|
+
* Asking is not getting. A provider may serve a downgraded tier and bill it at
|
|
1995
|
+
* the standard rate, so the discount is only ever read back from
|
|
1996
|
+
* {@link ProviderResponse.servedServiceTier}.
|
|
1997
|
+
*/
|
|
1998
|
+
deferrable?: boolean;
|
|
1607
1999
|
}
|
|
1608
2000
|
interface ProviderUsage {
|
|
1609
2001
|
inputTokens: number;
|
|
@@ -1655,6 +2047,30 @@ interface ProviderResponse {
|
|
|
1655
2047
|
* all the way to the caller.
|
|
1656
2048
|
*/
|
|
1657
2049
|
toolCalls?: ToolCallRequest[];
|
|
2050
|
+
/**
|
|
2051
|
+
* The processing tier the provider reports having SERVED this request, exactly
|
|
2052
|
+
* as it named it (OpenAI `service_tier`, Anthropic `usage.service_tier`).
|
|
2053
|
+
*
|
|
2054
|
+
* This is the only field a discount may be credited from, and the reason is
|
|
2055
|
+
* that it is not always what was asked for: a provider short on capacity may
|
|
2056
|
+
* serve the standard tier and bill the standard rate while the request said
|
|
2057
|
+
* otherwise. Crediting the REQUESTED tier would publish a saving the invoice
|
|
2058
|
+
* does not carry.
|
|
2059
|
+
*
|
|
2060
|
+
* Absent means the provider said nothing, which is NOT the same as "standard":
|
|
2061
|
+
* it means the tier cannot be known, so nothing is credited.
|
|
2062
|
+
*/
|
|
2063
|
+
servedServiceTier?: string;
|
|
2064
|
+
/**
|
|
2065
|
+
* The processing tier this adapter ASKED the provider for, when it asked for
|
|
2066
|
+
* one. Absent means it asked for nothing — which is the honest answer for a
|
|
2067
|
+
* provider that has no cheaper synchronous tier to ask for.
|
|
2068
|
+
*
|
|
2069
|
+
* Reported by the adapter rather than assumed by the caller: only the adapter
|
|
2070
|
+
* knows its provider's vocabulary, and a caller that hardcoded a tier name
|
|
2071
|
+
* would be describing a request some other adapter never made.
|
|
2072
|
+
*/
|
|
2073
|
+
requestedServiceTier?: string;
|
|
1658
2074
|
raw?: unknown;
|
|
1659
2075
|
}
|
|
1660
2076
|
interface Provider {
|
|
@@ -1670,6 +2086,22 @@ interface Provider {
|
|
|
1670
2086
|
* demonstrating the constrained-decoding contract end to end. Token usage is
|
|
1671
2087
|
* derived from the heuristic estimator so SavingsReport numbers are meaningful
|
|
1672
2088
|
* in examples and tests.
|
|
2089
|
+
*
|
|
2090
|
+
* ⚠️ WHAT THIS PROVIDER CANNOT MEASURE, and it has already cost money once.
|
|
2091
|
+
* It fabricates the answer FROM THE SCHEMA it receives, so a smaller schema
|
|
2092
|
+
* always produces a smaller answer. Any lever that shrinks the contract sent to
|
|
2093
|
+
* the provider therefore appears to shrink the OUTPUT too — automatically, on
|
|
2094
|
+
* every run, whatever model id is being simulated. That is a property of this
|
|
2095
|
+
* file, not of any model.
|
|
2096
|
+
*
|
|
2097
|
+
* The output codebook is exactly that shape of lever, and against this provider
|
|
2098
|
+
* the benchmark reported it saving 24.8%. Measured live it saves 8.0% on
|
|
2099
|
+
* `gpt-4o` and COSTS 8.2% on `gpt-4o-mini`, because a real model decides how
|
|
2100
|
+
* much to WRITE and a smaller model writes more when the field names carry less
|
|
2101
|
+
* meaning. So: never take an output-token saving measured here as evidence of
|
|
2102
|
+
* anything. Prove those with the paired A/B in `benchmarks/ab-live.ts`, and
|
|
2103
|
+
* write tests for output-side effects against a provider that models the
|
|
2104
|
+
* behaviour you are claiming — see `test/codebook-de-salida.test.ts`.
|
|
1673
2105
|
*/
|
|
1674
2106
|
interface MockProviderOptions {
|
|
1675
2107
|
/** Fixed text to return when no schema is present. */
|
|
@@ -1833,7 +2265,19 @@ declare class TraceCollector {
|
|
|
1833
2265
|
* unlicensed, rather than silently serving requests for free.
|
|
1834
2266
|
*/
|
|
1835
2267
|
declare class LicenseError extends Error {
|
|
1836
|
-
/**
|
|
2268
|
+
/**
|
|
2269
|
+
* Resolved license status — the stable handle for branching on the cause,
|
|
2270
|
+
* since the message text is rewritten whenever it can be made clearer:
|
|
2271
|
+
*
|
|
2272
|
+
* - `none` — nothing was configured (no `licenseKey`, no gate).
|
|
2273
|
+
* - `invalid` — a key was configured but does not verify.
|
|
2274
|
+
* - `expired` / `grace` — it verifies, but the term is over.
|
|
2275
|
+
* - `revoked` — cancelled by the control plane.
|
|
2276
|
+
* - `stale` — paid and current, but unconfirmed: a connectivity problem.
|
|
2277
|
+
*
|
|
2278
|
+
* The same value is repeated at the end of the message (`license status: X`)
|
|
2279
|
+
* because an uncaught error prints nothing else.
|
|
2280
|
+
*/
|
|
1837
2281
|
readonly status?: string;
|
|
1838
2282
|
constructor(message: string, status?: string);
|
|
1839
2283
|
}
|
|
@@ -1842,10 +2286,10 @@ declare class LicenseError extends Error {
|
|
|
1842
2286
|
* Offline license verification for the paid SDK.
|
|
1843
2287
|
*
|
|
1844
2288
|
* A license is a compact signed token `base64url(header).base64url(payload).
|
|
1845
|
-
* base64url(sig)
|
|
1846
|
-
*
|
|
1847
|
-
*
|
|
1848
|
-
*
|
|
2289
|
+
* base64url(sig)`, the exact format BiVelio's licensing service mints. We verify
|
|
2290
|
+
* the Ed25519 signature against BiVelio's public key, decode the payload, and
|
|
2291
|
+
* apply the same grace policy the issuer applies. Verification is
|
|
2292
|
+
* **browser-safe**: it uses
|
|
1849
2293
|
* `@noble/curves` (pure JS) + Web primitives (`atob`, `TextEncoder`) rather than
|
|
1850
2294
|
* `node:crypto`, so the shared entry point still compiles into the browser
|
|
1851
2295
|
* demo bundle. The private signing key never leaves the control plane; only the
|
|
@@ -1943,8 +2387,8 @@ declare function deriveStatus(payload: {
|
|
|
1943
2387
|
grace_days: number;
|
|
1944
2388
|
}, nowSeconds: number, revoked?: ReadonlySet<string>): LicenseStatus;
|
|
1945
2389
|
/**
|
|
1946
|
-
* Verify + apply the grace policy → a resolved status. Mirrors
|
|
1947
|
-
*
|
|
2390
|
+
* Verify + apply the grace policy → a resolved status. Mirrors what the issuing
|
|
2391
|
+
* control plane resolves for the same token. Bad signature / malformed
|
|
1948
2392
|
* → invalid; otherwise the status comes from {@link deriveStatus}.
|
|
1949
2393
|
*/
|
|
1950
2394
|
declare function resolveLicense(token: string, publicKey: string | LicenseKeyset, opts?: {
|
|
@@ -2326,6 +2770,11 @@ interface SavingsLayerConfig {
|
|
|
2326
2770
|
compressionEconomics?: CompressionEconomics;
|
|
2327
2771
|
retriever?: Retriever;
|
|
2328
2772
|
reranker?: Reranker;
|
|
2773
|
+
/**
|
|
2774
|
+
* Tuning for the model cascade (`savings.modelCascade`). All optional; the
|
|
2775
|
+
* defaults measure and never spend.
|
|
2776
|
+
*/
|
|
2777
|
+
modelCascade?: ModelCascadeSettings;
|
|
2329
2778
|
/**
|
|
2330
2779
|
* Signed BiVelio license token (from your paid subscription). This is the
|
|
2331
2780
|
* primary way to license the SDK: `createSavingsLayer` verifies it offline
|
|
@@ -2343,10 +2792,11 @@ interface SavingsLayerConfig {
|
|
|
2343
2792
|
*/
|
|
2344
2793
|
licensePublicKey?: string | LicenseKeyset;
|
|
2345
2794
|
/**
|
|
2346
|
-
* Pre-built license gate.
|
|
2347
|
-
*
|
|
2348
|
-
*
|
|
2349
|
-
*
|
|
2795
|
+
* Pre-built license gate. **Ignored in the published npm package**, where a
|
|
2796
|
+
* {@link licenseKey} verified against the embedded BiVelio public key is the
|
|
2797
|
+
* only accepted license — passing a gate there logs a warning and changes
|
|
2798
|
+
* nothing. It exists for builds from source (this repo's own tests and
|
|
2799
|
+
* benchmarks), where it takes precedence over {@link licenseKey}.
|
|
2350
2800
|
*/
|
|
2351
2801
|
licenseGate?: LicenseGate;
|
|
2352
2802
|
/**
|
|
@@ -2492,6 +2942,58 @@ interface SavingsLayerConfig {
|
|
|
2492
2942
|
/** Injectable id generator for deterministic tests. */
|
|
2493
2943
|
generateId?: () => string;
|
|
2494
2944
|
}
|
|
2945
|
+
/**
|
|
2946
|
+
* Tuning for the model cascade. Everything here is optional, and the defaults
|
|
2947
|
+
* cost nothing: with no settings at all, `modelCascade: "shadow"` measures what
|
|
2948
|
+
* it can measure for free and makes no extra provider call.
|
|
2949
|
+
*/
|
|
2950
|
+
interface ModelCascadeSettings {
|
|
2951
|
+
/**
|
|
2952
|
+
* Your own strong → cheap pairs, replacing the built-in table.
|
|
2953
|
+
*
|
|
2954
|
+
* Keys and values are model ids WITHOUT a vendor prefix (`"gpt-4o"`, not
|
|
2955
|
+
* `"openai/gpt-4o"`); the caller's prefix is carried over automatically, and a
|
|
2956
|
+
* dated snapshot inherits from its base id. A pair whose economics do not work
|
|
2957
|
+
* out at your prices is refused with a reason in the report — declaring it here
|
|
2958
|
+
* does not override the arithmetic.
|
|
2959
|
+
*/
|
|
2960
|
+
pairs?: Record<string, string>;
|
|
2961
|
+
/**
|
|
2962
|
+
* How many requests of a workload are routed before the automatic shut-off
|
|
2963
|
+
* judges the measured escalation rate (default 20).
|
|
2964
|
+
*
|
|
2965
|
+
* The rate is only observable on requests that were actually routed, so there
|
|
2966
|
+
* is no way to know without spending a bounded amount to find out. Worst case
|
|
2967
|
+
* (every one of them escalates) that exploration costs `n x r` requests'
|
|
2968
|
+
* worth of extra spend, once per workload per process — with a ratio of 0.06
|
|
2969
|
+
* and the default, about 1.2 requests.
|
|
2970
|
+
*/
|
|
2971
|
+
exploration?: number;
|
|
2972
|
+
/**
|
|
2973
|
+
* PRICED OPT-IN, default 0 (off). Fraction of `"shadow"` requests on which the
|
|
2974
|
+
* layer also calls the cheap model, purely to measure.
|
|
2975
|
+
*
|
|
2976
|
+
* Shadow mode is free precisely because it does not run the cheap model: it
|
|
2977
|
+
* reports eligibility, the arithmetic, and what the swap would have been worth.
|
|
2978
|
+
* What it cannot know for free is the one number that decides everything — how
|
|
2979
|
+
* often the deterministic gate would have REJECTED the cheap answer. That
|
|
2980
|
+
* answer does not exist until the cheap model writes one.
|
|
2981
|
+
*
|
|
2982
|
+
* So this buys it, and the price is exact: each sampled request costs one extra
|
|
2983
|
+
* cheap call, i.e. `r` of what the request already cost — about 6% for
|
|
2984
|
+
* gpt-4o → gpt-4o-mini. At `0.05` that is roughly 0.3% on top of your bill, and
|
|
2985
|
+
* every sampled request reports its own `modelCascade.sampleCost`. It also
|
|
2986
|
+
* DOUBLES that request's provider latency, because the extra call is sequential.
|
|
2987
|
+
*
|
|
2988
|
+
* The sampled request's tokens count as spend and are held out of the baseline,
|
|
2989
|
+
* exactly like the repair retry: measurement must never pay for itself.
|
|
2990
|
+
*
|
|
2991
|
+
* Which requests get sampled is derived from the request's own cache key, so it
|
|
2992
|
+
* is deterministic and stable — the same request is always sampled or always
|
|
2993
|
+
* not, and no `Math.random` decides how your money is spent.
|
|
2994
|
+
*/
|
|
2995
|
+
shadowSampleRate?: number;
|
|
2996
|
+
}
|
|
2495
2997
|
declare const DEFAULT_COST_MODEL: CostModel;
|
|
2496
2998
|
|
|
2497
2999
|
/** Fully-resolved, non-optional dependency set the pipeline runs against. */
|
|
@@ -2531,9 +3033,15 @@ interface SavingsLayer {
|
|
|
2531
3033
|
* cache, a vector-backed semantic cache, a real tokenizer, a compressor sidecar,
|
|
2532
3034
|
* XGrammar/llguidance backends, etc.).
|
|
2533
3035
|
*
|
|
3036
|
+
* A `licenseKey` is not optional in practice: `generate()` is fail-closed and
|
|
3037
|
+
* throws {@link LicenseError} without one, so it belongs in the smallest example
|
|
3038
|
+
* there is.
|
|
3039
|
+
*
|
|
2534
3040
|
* @example
|
|
2535
|
-
*
|
|
2536
|
-
*
|
|
3041
|
+
* // `licenseKey` is the signed token from savings.bivelio.com/dashboard/install,
|
|
3042
|
+
* // read from wherever you keep secrets (BIVELIO_LICENSE_KEY in the README).
|
|
3043
|
+
* const layer = createSavingsLayer({ provider, licenseKey });
|
|
3044
|
+
* const { text, report } = await layer.generate({
|
|
2537
3045
|
* model: "openai/gpt-4o-mini",
|
|
2538
3046
|
* messages: [{ role: "user", content: "What is 2 + 2 * 3?" }],
|
|
2539
3047
|
* });
|
|
@@ -2567,6 +3075,6 @@ declare function createSavingsLayer(config: Omit<SavingsLayerConfig, "tokenizer"
|
|
|
2567
3075
|
* constant to package.json so the two can never drift.
|
|
2568
3076
|
*/
|
|
2569
3077
|
|
|
2570
|
-
declare const BV_SALA_VERSION = "0.3.
|
|
3078
|
+
declare const BV_SALA_VERSION = "0.3.1";
|
|
2571
3079
|
|
|
2572
|
-
export { type AnthropicOptions, AnthropicProvider, BV_SALA_VERSION, type BivelioHandoff, CATALOGO, COMPACT_ROWS_INSTRUCTION, type CacheOutcome, type CacheTier, type CachedAnswer, type CanonicalRequest, type ChatMessage, type CompactRowsDecodeOptions, type CompactRowsOptions, type CompactVerification, type CompressionEconomics, type CompressionPolicyInput, type CompressionRequest, type CompressionResult, type Compressor, type ConstraintBackend, type ConstraintBackendId, type ConstraintPlan, type ConversationState, type CostBasis, type CostModel, DEFAULT_COST_MODEL, type DeterministicResolver, EMBEDDED_PUBLIC_KEY, type EmbeddingFn, type EvidenceDoc, type ExactCache, ExactTokenizer, type ExecutionClass, ExecutionRouter, type FormatChoice, FormatSelector, type FormatSelectorOptions, type HandoffFact, HeuristicEstimator, InMemoryExactCache, InMemorySemanticCache, type JsonSchema, LicenseError, type LicenseGate, type LicenseKeyset, type LicenseStatus, type LicenseTokenPayload, type LocalClassifier, MODELOS_POR_CODIFICACION, MODELS_BY_ENCODING, type MemoryDelta, type MessageRole, MockProvider, type MockProviderOptions, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OutputContract, PRECIOS_AL_DIA, type Policy, type ProtectedSpan, type Provider, type ProviderRequest, type ProviderResponse, type ProviderUsage, QUALITY_STATUSES, type QualityStatus, type RequestContext, type Reranker, type ResolvedDeps, type ResolvedGate, type ResolvedLicense, ResolverRegistry, type ResolverResult, type RetrievalOptions, type RetrievalOutcome, type RetrievalPlan, type Retriever, type RevocationListBody, type RevocationListVerification, type RevocationPollEvent, RevocationPoller, type RevocationPollerOptions, RevocationSnapshot, type RouteDecision, type SavingsLayer, type SavingsLayerConfig, SavingsLedger, type SavingsReport, type SavingsRequest, type SavingsResult, type SavingsToggles, SchemaRegistry, type SemanticCacheOptions, type SemanticHit, type SemanticRecord, type SemanticVerifier, type SerializationFormat, type Serializer, Singleflight, type TokenEstimator, TokenizerRegistry, type ToolCallRequest, type ToolDescriptor, type ToolRisk, type ToolSelection, ToolSelector, type ToolSelectorOptions, TraceCollector, type TraceEvent, UsageEmitter, type UsageEmitterOptions, type ValidationError, type ValidationResult, adaptiveK, arithmeticResolver, buildExactKey, buildInflightKey, canonicalize, compactRowsSerializer, computeNextDelay, cosine, createCompactRowsSerializer, createDefaultResolvers, createHandoff, createMockProvider, createSavingsLayer, csvSerializer, decodeCompactRows, dedupe, defaultTokenizerRegistry, deriveSeatId, deriveStatus, detectCi, emptyState, encodeCompactRows, evalArithmetic, evaluatePolicy, executeRetrievalPlan, gateFromKey, heuristicEstimator, isKeyset, isStrictCompatible, jsonCompactSerializer, keyTokensMatch, liveGateFromKey, mergeDelta, noopCompressor, normalizeText, precioDeLista, projectContext, providerNativeBackend, randomId, registerExactTokenizer, registrarTokenizadorExacto, renderState, resolveConstraintBackend, resolveDependencies, resolveLicense, sha256, shouldCompress, stableStringify, uniformColumns, validateAgainstSchema, verifyCompactSignature, verifyLicenseToken, verifyRevocationList, withProtectedSpans };
|
|
3080
|
+
export { type AnthropicOptions, AnthropicProvider, BV_SALA_VERSION, type BivelioHandoff, CATALOGO, COMPACT_ROWS_INSTRUCTION, type CacheOutcome, type CacheTier, type CachedAnswer, type CanonicalRequest, type ChatMessage, type CompactRowsDecodeOptions, type CompactRowsOptions, type CompactVerification, type CompressionEconomics, type CompressionPolicyInput, type CompressionRequest, type CompressionResult, type Compressor, type ConstraintBackend, type ConstraintBackendId, type ConstraintPlan, type ConversationState, type CostBasis, type CostModel, DEFAULT_COST_MODEL, type DeferredExecutionReport, type DeterministicResolver, EMBEDDED_PUBLIC_KEY, type EmbeddingFn, type EvidenceDoc, type ExactCache, ExactTokenizer, type ExecutionClass, ExecutionRouter, type FormatChoice, FormatSelector, type FormatSelectorOptions, type HandoffFact, HeuristicEstimator, InMemoryExactCache, InMemorySemanticCache, type JsonSchema, LicenseError, type LicenseGate, type LicenseKeyset, type LicenseStatus, type LicenseTokenPayload, type LocalClassifier, MODELOS_POR_CODIFICACION, MODELS_BY_ENCODING, type MemoryDelta, type MessageRole, MockProvider, type MockProviderOptions, type ModelCascadeMode, type ModelCascadeReport, type ModelCascadeSettings, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OutputContract, PRECIOS_AL_DIA, type Policy, type ProtectedSpan, type Provider, type ProviderRequest, type ProviderResponse, type ProviderUsage, QUALITY_STATUSES, type QualityStatus, type RequestContext, type Reranker, type ResolvedDeps, type ResolvedGate, type ResolvedLicense, ResolverRegistry, type ResolverResult, type RetrievalOptions, type RetrievalOutcome, type RetrievalPlan, type Retriever, type RevocationListBody, type RevocationListVerification, type RevocationPollEvent, RevocationPoller, type RevocationPollerOptions, RevocationSnapshot, type RouteDecision, type SavingsLayer, type SavingsLayerConfig, SavingsLedger, type SavingsReport, type SavingsRequest, type SavingsResult, type SavingsToggles, SchemaRegistry, type SemanticCacheOptions, type SemanticHit, type SemanticRecord, type SemanticVerifier, type SerializationFormat, type Serializer, Singleflight, type TokenEstimator, TokenizerRegistry, type ToolCallRequest, type ToolDescriptor, type ToolRisk, type ToolSelection, ToolSelector, type ToolSelectorOptions, TraceCollector, type TraceEvent, UsageEmitter, type UsageEmitterOptions, type ValidationError, type ValidationResult, adaptiveK, arithmeticResolver, buildExactKey, buildInflightKey, canonicalize, compactRowsSerializer, computeNextDelay, cosine, createCompactRowsSerializer, createDefaultResolvers, createHandoff, createMockProvider, createSavingsLayer, csvSerializer, decodeCompactRows, dedupe, defaultTokenizerRegistry, deriveSeatId, deriveStatus, detectCi, emptyState, encodeCompactRows, evalArithmetic, evaluatePolicy, executeRetrievalPlan, gateFromKey, heuristicEstimator, isKeyset, isStrictCompatible, jsonCompactSerializer, keyTokensMatch, liveGateFromKey, mergeDelta, modelFamilyOf, noopCompressor, normalizeText, precioDeLista, projectContext, providerNativeBackend, randomId, registerExactTokenizer, registrarTokenizadorExacto, renderState, resolveConstraintBackend, resolveDependencies, resolveLicense, sha256, shouldCompress, stableStringify, uniformColumns, validateAgainstSchema, verifyCompactSignature, verifyLicenseToken, verifyRevocationList, withProtectedSpans };
|