@bivelio/savings-layer 0.4.30 → 0.4.31
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 +64 -6
- package/dist/gateway/bin.js +740 -687
- package/dist/index.d.ts +93 -17
- package/dist/index.js +1277 -1208
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -325,7 +325,7 @@ declare function precioDeLista(model: string, at?: Date | number): CostModel | u
|
|
|
325
325
|
* on the customer's machine. `test/version-declarada.test.ts` ties this
|
|
326
326
|
* constant to package.json so the two can never drift.
|
|
327
327
|
*/
|
|
328
|
-
declare const BV_SALA_VERSION = "0.4.
|
|
328
|
+
declare const BV_SALA_VERSION = "0.4.31";
|
|
329
329
|
|
|
330
330
|
/**
|
|
331
331
|
* Environment-agnostic UUID generation.
|
|
@@ -546,7 +546,11 @@ interface OutputContract {
|
|
|
546
546
|
/** Stable identifier, e.g. "research-answer:v3". */
|
|
547
547
|
contractId: string;
|
|
548
548
|
schema: JsonSchema;
|
|
549
|
-
/**
|
|
549
|
+
/**
|
|
550
|
+
* Hard ceiling on generated tokens for this contract. A free-text request (no
|
|
551
|
+
* schema) sets its ceiling with {@link SavingsRequest.maxOutputTokens}; when
|
|
552
|
+
* both are set, the smaller one is sent.
|
|
553
|
+
*/
|
|
550
554
|
maxOutputTokens?: number;
|
|
551
555
|
/** Version marker included in the exact-cache key. */
|
|
552
556
|
version?: string;
|
|
@@ -1103,6 +1107,19 @@ interface SavingsRequest {
|
|
|
1103
1107
|
/** Sampling controls that participate in the exact-cache key. */
|
|
1104
1108
|
temperature?: number;
|
|
1105
1109
|
seed?: number;
|
|
1110
|
+
/**
|
|
1111
|
+
* Hard ceiling on generated tokens for this request, with or without an
|
|
1112
|
+
* output contract. It travels to every adapter: Anthropic `max_tokens`,
|
|
1113
|
+
* Chat Completions `max_completion_tokens` on OpenAI's own API and
|
|
1114
|
+
* `max_tokens` on any other OpenAI-compatible endpoint (see
|
|
1115
|
+
* `OpenAICompatibleOptions.maxTokensParam`). When `response.maxOutputTokens`
|
|
1116
|
+
* is also set, the smaller of the two is sent. Unset, nothing changes.
|
|
1117
|
+
*
|
|
1118
|
+
* It is a limit you set, not a saving: it never raises the estimated output
|
|
1119
|
+
* of an avoided call and is never credited as output avoided. An answer cut
|
|
1120
|
+
* by it (`finishReason: "length"`) is not cached. Must be a positive integer.
|
|
1121
|
+
*/
|
|
1122
|
+
maxOutputTokens?: number;
|
|
1106
1123
|
/** Tokenizer id to cost against; defaults to a model-derived estimate. */
|
|
1107
1124
|
tokenizer?: string;
|
|
1108
1125
|
/** Arbitrary structured payload to be serialized into the prompt. */
|
|
@@ -1336,11 +1353,12 @@ interface QualityTruncationCheck {
|
|
|
1336
1353
|
/** The stop reason exactly as the provider named it; absent when it reported none. */
|
|
1337
1354
|
finishReason?: string;
|
|
1338
1355
|
/**
|
|
1339
|
-
* Whether you set the limit (`
|
|
1356
|
+
* Whether you set the limit (`maxOutputTokens` on the request or on
|
|
1357
|
+
* `response`). When false, any
|
|
1340
1358
|
* limit that applied was a provider or adapter default.
|
|
1341
1359
|
*/
|
|
1342
1360
|
capSetByCaller: boolean;
|
|
1343
|
-
/** The limit
|
|
1361
|
+
/** The limit that was sent (the smaller of the two when both were set). Present only when `capSetByCaller`. */
|
|
1344
1362
|
outputLimit?: number;
|
|
1345
1363
|
}
|
|
1346
1364
|
/** How a cache hit matched this request. */
|
|
@@ -2240,8 +2258,13 @@ interface SemanticCacheOptions {
|
|
|
2240
2258
|
*
|
|
2241
2259
|
* Pass your own for true semantics; the local one only sees LEXICAL closeness.
|
|
2242
2260
|
* Either way the deterministic guard below still rejects a candidate whose
|
|
2243
|
-
* numbers
|
|
2244
|
-
*
|
|
2261
|
+
* numbers (in digits or spelled out in en/es/ca: "three", "twice", "half"),
|
|
2262
|
+
* negation parity or content words differ beyond its overlap floor. It is a
|
|
2263
|
+
* lexical guard, not a proof: a one-word entity swap in a long query can
|
|
2264
|
+
* still clear the overlap floor, and through 0.4.30 a number written in words
|
|
2265
|
+
* cleared it too (GSM8K: 477 of 564 such variants got their original's
|
|
2266
|
+
* answer). Calibrate on your own traffic before trusting it with answers
|
|
2267
|
+
* that differ by one word.
|
|
2245
2268
|
*/
|
|
2246
2269
|
embed?: EmbeddingFn;
|
|
2247
2270
|
/**
|
|
@@ -2558,7 +2581,20 @@ interface ToolSelection {
|
|
|
2558
2581
|
setIsStable: boolean;
|
|
2559
2582
|
}
|
|
2560
2583
|
interface ToolSelectorOptions {
|
|
2561
|
-
/**
|
|
2584
|
+
/**
|
|
2585
|
+
* Max tools the selector keeps when it has a SIGNAL to select on: a catalogue
|
|
2586
|
+
* whose tools declare `intents` and/or `risk`, with the router on. Default 8.
|
|
2587
|
+
*
|
|
2588
|
+
* It never truncates a catalogue it cannot rank. A catalogue that declares no
|
|
2589
|
+
* `intents` and no `risk` (the usual case: MCP and OpenAI tool lists) and every
|
|
2590
|
+
* request with `savings: { router: false }` go to the provider WHOLE, exactly as
|
|
2591
|
+
* the caller sent them, and the layer credits nothing for the tool block:
|
|
2592
|
+
* cutting by position left the model unable to call the rest (on BFCL
|
|
2593
|
+
* multi-turn, gpt-4o-mini hit the reference call 8/10 times directly and 1/10
|
|
2594
|
+
* through the layer). When the selector does prune a typed catalogue, the
|
|
2595
|
+
* report's `tool-selector` trace lists what was left out and the SDK warns
|
|
2596
|
+
* (once per process, silenced by `silenceWarnings`).
|
|
2597
|
+
*/
|
|
2562
2598
|
maxTools?: number;
|
|
2563
2599
|
/** Tokenizer-aware scorer for tie-breaking (optional). */
|
|
2564
2600
|
scoreIntentMatch?: (text: string, tool: ToolDescriptor) => number;
|
|
@@ -2604,16 +2640,9 @@ declare class ToolSelector {
|
|
|
2604
2640
|
private readonly freezer;
|
|
2605
2641
|
constructor(opts?: ToolSelectorOptions);
|
|
2606
2642
|
/**
|
|
2607
|
-
*
|
|
2608
|
-
*
|
|
2609
|
-
*
|
|
2610
|
-
* Se usa cuando el llamante apaga el router (`savings:{router:false}`): sin
|
|
2611
|
-
* clasificación no hay de dónde derivar el riesgo, y filtrar sobre el
|
|
2612
|
-
* `defaultRoute()` tiraba en silencio las herramientas de escritura. Apagar el
|
|
2613
|
-
* router significa "yo elijo las herramientas", así que la relevancia pasa a
|
|
2614
|
-
* ser del llamante — pero el tope de presupuesto NO se levanta: mandar 200
|
|
2615
|
-
* esquemas al proveedor es un 400 seguro y una petición que antes funcionaba
|
|
2616
|
-
* pasaría a fallar en duro.
|
|
2643
|
+
* Every tool the caller passed, as passed: none left out, none credited.
|
|
2644
|
+
* Used when there is no signal to select on (`savings: { router: false }`,
|
|
2645
|
+
* or a catalogue with no `intents` and no `risk`).
|
|
2617
2646
|
*/
|
|
2618
2647
|
passthrough(tools: ToolDescriptor[] | undefined): ToolSelection;
|
|
2619
2648
|
select(text: string, tools: ToolDescriptor[] | undefined, execution: ExecutionClass,
|
|
@@ -3014,6 +3043,10 @@ interface ProviderRequest {
|
|
|
3014
3043
|
tools?: ToolDescriptor[];
|
|
3015
3044
|
/** Output contract to enforce via constrained decoding, when available. */
|
|
3016
3045
|
schema?: JsonSchema;
|
|
3046
|
+
/**
|
|
3047
|
+
* Output cap chosen by the caller: the smaller of `SavingsRequest.maxOutputTokens`
|
|
3048
|
+
* and `response.maxOutputTokens`. Each adapter maps it to its own field.
|
|
3049
|
+
*/
|
|
3017
3050
|
maxOutputTokens?: number;
|
|
3018
3051
|
temperature?: number;
|
|
3019
3052
|
seed?: number;
|
|
@@ -3504,7 +3537,28 @@ interface SavingsLayerConfig {
|
|
|
3504
3537
|
provider: Provider;
|
|
3505
3538
|
tokenizer: TokenizerRegistry;
|
|
3506
3539
|
exactCache?: ExactCache;
|
|
3540
|
+
/**
|
|
3541
|
+
* WHERE reworded questions are looked up and stored. Giving the layer a cache
|
|
3542
|
+
* does NOT switch it on: a request still has to ask for it with
|
|
3543
|
+
* `savings.semanticCache`, or you set {@link semanticCacheDefault} to ask for
|
|
3544
|
+
* it on every request. A layer that has a cache and a request that neither
|
|
3545
|
+
* asks for it nor turns it off gets a one-time console warning (silenced by
|
|
3546
|
+
* `silenceWarnings`, or by setting `semanticCacheDefault`, `false` included).
|
|
3547
|
+
*/
|
|
3507
3548
|
semanticCache?: InMemorySemanticCache;
|
|
3549
|
+
/**
|
|
3550
|
+
* Default for `savings.semanticCache` on every request of this layer. A
|
|
3551
|
+
* request's own value always wins, `false` included. Unset, the semantic cache
|
|
3552
|
+
* is used only by requests that ask for it.
|
|
3553
|
+
*
|
|
3554
|
+
* OPT-IN, and deliberately a separate field from {@link semanticCache}: the
|
|
3555
|
+
* cache is the backend, this is the decision to serve answers to reworded
|
|
3556
|
+
* questions, which can serve a wrong answer. Prefer it with a cache built with
|
|
3557
|
+
* `calibration`, which serves nothing until your own traffic certifies a
|
|
3558
|
+
* floor. `false` states that you switch it on per request, and silences the
|
|
3559
|
+
* warning about a cache that no request uses.
|
|
3560
|
+
*/
|
|
3561
|
+
semanticCacheDefault?: boolean | "safe-only" | "include-agentic";
|
|
3508
3562
|
singleflight?: Singleflight;
|
|
3509
3563
|
resolvers?: ResolverRegistry;
|
|
3510
3564
|
router?: ExecutionRouter;
|
|
@@ -4587,6 +4641,25 @@ interface OpenAICompatibleOptions {
|
|
|
4587
4641
|
* saving. Benchmarks that make real cost claims must set this.
|
|
4588
4642
|
*/
|
|
4589
4643
|
requireUsage?: boolean;
|
|
4644
|
+
/**
|
|
4645
|
+
* Which Chat Completions field carries the output cap (`maxOutputTokens`).
|
|
4646
|
+
*
|
|
4647
|
+
* Default (undefined): `max_completion_tokens` when `baseUrl` is OpenAI's own
|
|
4648
|
+
* API (https://api.openai.com), `max_tokens` everywhere else. OpenAI
|
|
4649
|
+
* deprecated `max_tokens` when it introduced `max_completion_tokens`
|
|
4650
|
+
* (2024-09-12) and its reasoning models (o-series, gpt-5.x) reject it with a
|
|
4651
|
+
* 400; `max_completion_tokens` is accepted by every current OpenAI chat
|
|
4652
|
+
* model. OpenAI-compatible servers (proxies, self-hosted inference servers,
|
|
4653
|
+
* routers, Azure with an older api-version, a local gateway) understand
|
|
4654
|
+
* `max_tokens`, and some silently IGNORE a field they do not know, which
|
|
4655
|
+
* would drop the cap without an error.
|
|
4656
|
+
*
|
|
4657
|
+
* With the default, a 400/422 that names the field sent as unsupported is
|
|
4658
|
+
* retried once with the other one (it is rejected before any token is
|
|
4659
|
+
* generated, so nothing is billed twice) and the model is remembered. An
|
|
4660
|
+
* explicit value always wins and is never switched.
|
|
4661
|
+
*/
|
|
4662
|
+
maxTokensParam?: "max_tokens" | "max_completion_tokens";
|
|
4590
4663
|
}
|
|
4591
4664
|
/**
|
|
4592
4665
|
* ¿Cumple este esquema las reglas del modo `strict` de OpenAI?
|
|
@@ -4616,6 +4689,7 @@ declare class OpenAICompatibleProvider implements Provider {
|
|
|
4616
4689
|
/** Models of this endpoint already known to reject `response_format`. */
|
|
4617
4690
|
private readonly sinResponseFormat;
|
|
4618
4691
|
private streamOptionsRejected;
|
|
4692
|
+
private readonly campoDeTopeAprendido;
|
|
4619
4693
|
private readonly origen;
|
|
4620
4694
|
constructor(opts: OpenAICompatibleOptions);
|
|
4621
4695
|
generate(req: ProviderRequest, options?: ProviderStreamOptions): Promise<ProviderResponse>;
|
|
@@ -4629,6 +4703,8 @@ declare class OpenAICompatibleProvider implements Provider {
|
|
|
4629
4703
|
* as one text event.
|
|
4630
4704
|
*/
|
|
4631
4705
|
generateStream(req: ProviderRequest, options?: ProviderStreamOptions): AsyncGenerator<ProviderStreamEvent, void, undefined>;
|
|
4706
|
+
private campoDeTope;
|
|
4707
|
+
private corregirCampoDeTope;
|
|
4632
4708
|
private enviar;
|
|
4633
4709
|
private construirCuerpo;
|
|
4634
4710
|
/** Translate a 2xx endpoint response into the provider-neutral shape. */
|