@bivelio/savings-layer 0.4.0 → 0.4.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 +99 -126
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,31 +1,61 @@
|
|
|
1
|
-
#
|
|
1
|
+
# BV‑SALA — the savings layer for your LLM bill
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
provider
|
|
5
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://savings.bivelio.com/en/how-it-works/opengraph-image" alt="Your application → BV-SALA → provider API. The bill drops from $330 to $160 a month, measured." width="720">
|
|
5
|
+
</p>
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@bivelio/savings-layer"><img src="https://img.shields.io/npm/v/%40bivelio%2Fsavings-layer?color=2F63D8&label=npm" alt="npm version"></a>
|
|
9
|
+
<img src="https://img.shields.io/badge/node-%E2%89%A520-14A06F" alt="Node ≥ 20">
|
|
10
|
+
<img src="https://img.shields.io/badge/license-commercial-0F1218" alt="Commercial license">
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
**One layer inside your code, right where your app calls the OpenAI or Anthropic API.**
|
|
14
|
+
For every request it picks the cheapest execution that still meets your quality bar —
|
|
15
|
+
avoiding calls that don't need to happen and trimming what must be sent — and hands
|
|
16
|
+
you an auditable `SavingsReport`. Your bill drops, and you can verify why.
|
|
9
17
|
|
|
10
18
|
> **Commercial software — © 2026 BiVelio Inc.** Free to install, **paid to run**:
|
|
11
|
-
> BV‑SALA is
|
|
12
|
-
>
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
|
|
19
|
+
> BV‑SALA is fail‑closed and executes only with an active BiVelio license key.
|
|
20
|
+
> License checks are **offline** and **your prompts never leave your infrastructure** —
|
|
21
|
+
> only counts and cost are ever reported. Use is governed by the [LICENSE](./LICENSE)
|
|
22
|
+
> and the BiVelio Terms. Not a wrapper around any third‑party library.
|
|
23
|
+
|
|
24
|
+
## Where it installs
|
|
25
|
+
|
|
26
|
+
Your application → **BV‑SALA** → provider API. Traffic always goes straight from
|
|
27
|
+
your app to your provider — BV‑SALA is a library inside your code, never a
|
|
28
|
+
middleman server, and it works with any OpenAI‑compatible endpoint (OpenAI, Azure,
|
|
29
|
+
vLLM, SGLang, a gateway) as well as Anthropic.
|
|
30
|
+
|
|
31
|
+
**Only use ChatGPT or Claude?** Then there is nothing to install: those products
|
|
32
|
+
charge a flat subscription, so there is no per‑token bill to cut. BV‑SALA is for
|
|
33
|
+
applications that call the API with their own key. The whole story, in plain words:
|
|
34
|
+
**[Where does the saving install?](https://savings.bivelio.com/en/how-it-works)**
|
|
35
|
+
|
|
36
|
+
## Try it before you install
|
|
37
|
+
|
|
38
|
+
Run the real optimizer **free in your browser** — pick an example or paste your own
|
|
39
|
+
data and watch the meter — at **[savings.bivelio.com](https://savings.bivelio.com)**.
|
|
16
40
|
|
|
17
|
-
## Install
|
|
41
|
+
## Install in three steps
|
|
42
|
+
|
|
43
|
+
**1 · The package**
|
|
18
44
|
|
|
19
45
|
```bash
|
|
20
46
|
pnpm add @bivelio/savings-layer
|
|
21
47
|
# or: npm i @bivelio/savings-layer · yarn add @bivelio/savings-layer
|
|
22
48
|
```
|
|
23
49
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
50
|
+
**2 · The license** — from your [dashboard](https://savings.bivelio.com/dashboard/install)
|
|
51
|
+
(**€4 / seat / month** or **€39 / seat / year**, EUR)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export BIVELIO_LICENSE_KEY=… # your license key
|
|
55
|
+
export BIVELIO_SERVICE_KEY=… # service-account key: auto-renewal + seat metering
|
|
56
|
+
```
|
|
27
57
|
|
|
28
|
-
|
|
58
|
+
**3 · Wrap the call** — this is the entire code change:
|
|
29
59
|
|
|
30
60
|
```ts
|
|
31
61
|
import { createSavingsLayer, OpenAICompatibleProvider } from "@bivelio/savings-layer";
|
|
@@ -54,8 +84,30 @@ console.log(report.calls.avoidedLlm); // → whole calls you never paid for
|
|
|
54
84
|
console.log(report.cost.netSavings); // → verified savings, per request
|
|
55
85
|
```
|
|
56
86
|
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
That's it. From the first request, `report` carries the saving — measured, not
|
|
88
|
+
estimated.
|
|
89
|
+
|
|
90
|
+
## What you get on every request
|
|
91
|
+
|
|
92
|
+
A `SavingsReport` with the numbers behind every claim, kept in **four separate
|
|
93
|
+
ledgers** that are never summed into one flattering figure:
|
|
94
|
+
|
|
95
|
+
| Ledger | Meaning |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `avoided_calls` | LLM / retrieval / tool calls that never executed |
|
|
98
|
+
| `eliminated_tokens` | information dropped because it was not needed |
|
|
99
|
+
| `compressed_tokens` | information kept, but encoded with fewer tokens |
|
|
100
|
+
| `provider_cached_tokens` | tokens still in the prompt, billed/processed more cheaply |
|
|
101
|
+
|
|
102
|
+
And a promise you can hold it to: **never worse than your JSON.** Payload encodings
|
|
103
|
+
are chosen by counting real tokens with the destination model's own tokenizer, and
|
|
104
|
+
BV‑SALA only moves away from plain JSON when the saving clearly clears the bar —
|
|
105
|
+
`report.serialization` shows what was chosen and what each candidate would have cost.
|
|
106
|
+
|
|
107
|
+
<details>
|
|
108
|
+
<summary><b>Structured output — validated <code>data</code>, not just text</b></summary>
|
|
109
|
+
|
|
110
|
+
Ask for a response contract and you also get `data`, validated against your schema:
|
|
59
111
|
|
|
60
112
|
```ts
|
|
61
113
|
const { data, text } = await layer.generate<{ answer: number }>({
|
|
@@ -76,42 +128,10 @@ const { data, text } = await layer.generate<{ answer: number }>({
|
|
|
76
128
|
console.log(data.answer); // 8
|
|
77
129
|
```
|
|
78
130
|
|
|
79
|
-
|
|
80
|
-
product and **refuses to run unlicensed, expired, or tampered** (it throws
|
|
81
|
-
`LicenseError` at the `generate()` entry, carrying a `status` of `none`,
|
|
82
|
-
`invalid`, `expired`, `grace`, `revoked` or `stale`). Your key — and this snippet
|
|
83
|
-
with the key already filled in — is at
|
|
84
|
-
[savings.bivelio.com/dashboard/install](https://savings.bivelio.com/dashboard/install).
|
|
85
|
-
|
|
86
|
-
> **Set `serviceAccountKey` on every long‑running deployment.** Your licence token
|
|
87
|
-
> expires at the end of the billing period; each renewal mints a **new** token. With
|
|
88
|
-
> a service‑account key (`bvk_…`, same dashboard) the SDK picks the renewed token up
|
|
89
|
-
> by itself and swaps it in without a restart. **Without it there is no machine
|
|
90
|
-
> pickup**, so somebody has to paste the new token by hand every cycle — and if
|
|
91
|
-
> nobody does, the deployment stops with `LicenseError` once the grace period ends,
|
|
92
|
-
> while the subscription is paid and current. The key also enables seat metering
|
|
93
|
-
> (counts only — never prompts or completions).
|
|
94
|
-
|
|
95
|
-
### Seats (how you are billed)
|
|
96
|
-
|
|
97
|
-
A **seat is a machine**, never a person. The SDK derives a stable, opaque id per
|
|
98
|
-
machine + service-account key and reports it with the counts; the control plane
|
|
99
|
-
bills a seat only once it has been seen on **3 separate days**.
|
|
100
|
-
|
|
101
|
-
**Set `BVSALA_SEAT_ID` (one value per replica or service) whenever the machine
|
|
102
|
-
identity can't be deduced** — Kubernetes, or any fleet where the hostname is
|
|
103
|
-
assigned dynamically. Without it, every pod of a deployment shares one fingerprint
|
|
104
|
-
and the whole deployment counts as a **single** seat. It is also the way to keep
|
|
105
|
-
seat ids stable across an SDK upgrade: the fingerprint changed in v0.1.x, so a
|
|
106
|
-
fleet that never set it may be counted twice in the month it upgrades.
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
BVSALA_SEAT_ID=worker-03 # stable per replica; [A-Za-z0-9._:/-], max 128 chars
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
CI runners are auto-detected and excluded from billable seats.
|
|
131
|
+
</details>
|
|
113
132
|
|
|
114
|
-
|
|
133
|
+
<details>
|
|
134
|
+
<summary><b>Tool calls</b></summary>
|
|
115
135
|
|
|
116
136
|
When you pass `tools` and the model asks to invoke one, the reply is not the final
|
|
117
137
|
answer: `text` is empty by design and the request is in `toolCalls`. Execute it,
|
|
@@ -155,92 +175,45 @@ if (res.toolCalls?.length) {
|
|
|
155
175
|
A tool‑call turn is never served from cache and never counted as an avoided call:
|
|
156
176
|
an action that has not run yet cannot be a saving.
|
|
157
177
|
|
|
158
|
-
>
|
|
159
|
-
> **only when building from source** (this repo's tests and benchmarks). They are
|
|
160
|
-
> **disabled in this published package** — a valid `licenseKey` is the only way to
|
|
161
|
-
> run it. They are not a way to use the product for free.
|
|
162
|
-
|
|
163
|
-
Every component ships with an in‑memory default and is independently swappable:
|
|
164
|
-
plug in your own cache, vector store, tokenizer, compressor or constraint backend
|
|
165
|
-
behind the same interfaces.
|
|
166
|
-
|
|
167
|
-
## The optimization order (cheapest first)
|
|
178
|
+
</details>
|
|
168
179
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
3. **Eliminate unnecessary context** before trying to shrink what remains.
|
|
172
|
-
4. **Shrink** the tokens that genuinely must be sent.
|
|
173
|
-
5. **Constrain generation** to emit only the structure and length required.
|
|
180
|
+
<details>
|
|
181
|
+
<summary><b>Running a fleet? Seats and renewals</b></summary>
|
|
174
182
|
|
|
175
|
-
|
|
183
|
+
- **A seat is a machine, never a person.** A seat is billed only once it has been
|
|
184
|
+
seen on 3 separate days, and CI runners are auto‑detected and excluded.
|
|
185
|
+
- **Set `serviceAccountKey` on every long‑running deployment.** Renewals mint a new
|
|
186
|
+
license token each billing period; with the service‑account key (`bvk_…`, same
|
|
187
|
+
dashboard) the SDK picks the renewed token up by itself, without a restart.
|
|
188
|
+
- **Set `BVSALA_SEAT_ID` (one stable value per replica) on Kubernetes or any fleet
|
|
189
|
+
with dynamic hostnames**, so each replica counts as what it is:
|
|
176
190
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
## Four separate ledgers (never summed)
|
|
181
|
-
|
|
182
|
-
Mixing these produces misleading metrics, so BV‑SALA keeps them apart:
|
|
183
|
-
|
|
184
|
-
| Ledger | Meaning |
|
|
185
|
-
| --- | --- |
|
|
186
|
-
| `avoided_calls` | LLM / retrieval / tool calls that never executed |
|
|
187
|
-
| `eliminated_tokens` | information dropped because it was not needed |
|
|
188
|
-
| `compressed_tokens` | information kept, but encoded with fewer tokens |
|
|
189
|
-
| `provider_cached_tokens` | tokens still in the prompt, billed/processed more cheaply |
|
|
190
|
-
|
|
191
|
-
A cache hit removes a whole call. A re‑encode makes a payload smaller. Compression
|
|
192
|
-
drops redundant words. A prefix cache makes tokens cheaper without removing them.
|
|
193
|
-
Four different things — summing them would lie to you, so the report never does.
|
|
194
|
-
|
|
195
|
-
## The decision cascade
|
|
196
|
-
|
|
197
|
-
```
|
|
198
|
-
Request
|
|
199
|
-
→ Canonicalize + Policy (risk & freshness)
|
|
200
|
-
→ Deterministic resolvers ─────────────► answer (0 calls)
|
|
201
|
-
→ Exact cache ─────────────────────────► answer (0 calls)
|
|
202
|
-
→ Concurrent duplicates coalesced ─────► answer (0 calls)
|
|
203
|
-
→ Near-duplicate reuse ────────────► answer (0 calls)
|
|
204
|
-
→ Execution planning (how much work this really needs)
|
|
205
|
-
→ Context reduction (only when it pays for itself)
|
|
206
|
-
→ Payload encoding chosen by measurement, not by default
|
|
207
|
-
→ Output contract enforced
|
|
208
|
-
→ ONE primary LLM call
|
|
209
|
-
→ Structural + semantic validation (+ ≤1 repair)
|
|
210
|
-
→ Local render / transcode / cache write
|
|
211
|
-
→ SavingsReport + traces
|
|
191
|
+
```bash
|
|
192
|
+
BVSALA_SEAT_ID=worker-03 # stable per replica; [A-Za-z0-9._:/-], max 128 chars
|
|
212
193
|
```
|
|
213
194
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
A compact encoding can be *larger* than plain JSON on nested or non‑uniform data,
|
|
217
|
-
so BV‑SALA never assumes one. It counts the candidates with the destination
|
|
218
|
-
model's own tokenizer — including the cost of explaining the encoding to the
|
|
219
|
-
model — and only moves away from JSON when the saving clears a margin worth the
|
|
220
|
-
change.
|
|
221
|
-
|
|
222
|
-
On a wide, uniform table that is a large reduction. On a small nested object it
|
|
223
|
-
leaves JSON alone. Whichever it picks, `report.serialization` tells you what was
|
|
224
|
-
chosen and what each candidate would have cost, so the decision is auditable
|
|
225
|
-
rather than promised.
|
|
195
|
+
</details>
|
|
226
196
|
|
|
227
|
-
|
|
197
|
+
<details>
|
|
198
|
+
<summary><b>Requirements</b></summary>
|
|
228
199
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
200
|
+
- **Node ≥ 20.** The package is **ESM‑only** (`"type": "module"`); from CommonJS,
|
|
201
|
+
`require()` works on Node ≥ 22.
|
|
202
|
+
- Optional peer `gpt-tokenizer` for exact OpenAI token counts — without it a
|
|
203
|
+
built‑in estimator is used, so it is not required to get started.
|
|
204
|
+
- Every component (cache, vector store, tokenizer, compressor, constraint backend)
|
|
205
|
+
ships with an in‑memory default and is independently swappable behind the same
|
|
206
|
+
interfaces.
|
|
233
207
|
|
|
234
|
-
|
|
235
|
-
the token counts behind it.
|
|
208
|
+
</details>
|
|
236
209
|
|
|
237
210
|
## Licensing & privacy
|
|
238
211
|
|
|
239
212
|
BV‑SALA is commercial, per‑seat software (**€4 / seat / month** or **€39 / seat /
|
|
240
213
|
year**, EUR). The license is a signed token your SDK verifies **offline**; the
|
|
241
|
-
managed control plane
|
|
242
|
-
|
|
243
|
-
|
|
214
|
+
managed control plane and the revocation kill‑switch are served from BiVelio. Your
|
|
215
|
+
LLM traffic goes **straight to your provider** — BiVelio sees counts and cost,
|
|
216
|
+
never prompts or completions.
|
|
244
217
|
|
|
245
218
|
Get a key and read the terms at **[savings.bivelio.com](https://savings.bivelio.com)**.
|
|
246
219
|
Onboarding & general questions: **support@bivelio.com** · licensing & compliance:
|
package/dist/index.d.ts
CHANGED
|
@@ -3193,6 +3193,6 @@ declare function createSavingsLayer(config: Omit<SavingsLayerConfig, "tokenizer"
|
|
|
3193
3193
|
* constant to package.json so the two can never drift.
|
|
3194
3194
|
*/
|
|
3195
3195
|
|
|
3196
|
-
declare const BV_SALA_VERSION = "0.4.
|
|
3196
|
+
declare const BV_SALA_VERSION = "0.4.1";
|
|
3197
3197
|
|
|
3198
3198
|
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, UMBRAL_LOCAL, 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, embebedorLocal, 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, vectorLocal, verifyCompactSignature, verifyLicenseToken, verifyRevocationList, withProtectedSpans };
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ Problems found:
|
|
|
27
27
|
${P}
|
|
28
28
|
|
|
29
29
|
Return ONLY the corrected JSON object. Keep the same content; fix only what is listed.`}],ee=this.tokensFor(this.assemblePromptText(Q),n),te=i.sentInputLocal>0?i.actualInput/i.sentInputLocal:1,de=Math.round(te*ee),Ze=Math.min(O.usage.outputTokens,n.response?.maxOutputTokens??Number.POSITIVE_INFINITY),pe=de/1e3*xe.inputPer1k+Ze/1e3*xe.outputPer1k,z=this.config.skipRepairAboveBaseline?i.estimateCost(xe):void 0;if(z!=null&&z.baselineEstimate>0&&z.actual+pe>z.baselineEstimate&&z!=null)c.record("validation","repair-skipped",{reason:"repairing would cost more than not using the layer at all; the invalid answer is served as-is and reported as invalid",errors:A.errors,baselineUsd:z.baselineEstimate,actualUsd:z.actual,repairEstimateUsd:pe}),this.avisar("reparacion-mas-cara-que-el-baseline",`[bvsala] The answer did not satisfy the output contract, and repairing it would have cost MORE than sending this request without the layer at all (baseline ~$${z.baselineEstimate}, already spent ~$${z.actual}, repair ~$${pe.toFixed(6)}). The repair was skipped and the invalid answer is returned with \`constraints.structurallyValid: false\` \u2014 check it before using it. This combination is usually a request carrying both tools and an output contract; see the adapter warning for the cheaper shapes.`);else {i.retries=1,c.record("validation","repair-attempt",{errors:A.errors}),O=await this.llamarProveedor({model:ue,messages:Q,schema:R,...n.response?.maxOutputTokens!=null?{maxOutputTokens:n.response.maxOutputTokens}:{}},e),i.actualLlm+=1,i.actualInput+=O.usage.inputTokens,i.actualOutput+=O.usage.outputTokens,i.repairOutput+=O.usage.outputTokens,i.repairInput+=O.usage.inputTokens,i.sentInputLocal+=ee,$=O.text;let Z=Ge($);A=Z.ok?ae(Z.value,R):{valid:false,errors:[{path:"$",message:"not valid JSON"}]},Z.ok&&(We=Z.value,Z.rescatado!=null&&A.valid&&($=Z.rescatado));}}else k.ok&&(We=k.value);_e=A.valid,c.record("validation",_e?"valid":"invalid");}let Ns=this.now()-_,$s=xc(We),nn={text:$,data:We,rendered:$s,storedAtMs:this.now()},ke=this.informeDeDiferido(s,O,xe);ke&&c.record("deferred-tier",ke.credited?"credited":"not-credited",{...ke.requestedTier?{requestedTier:ke.requestedTier}:{},...ke.servedTier?{servedTier:ke.servedTier}:{},creditedLedger:"none",reason:ke.reason});try{let k=L.aplicado,A=O.finishReason==="length",j=_e!==!1&&!Ye&&!k&&!A;j||c.record("cache-write",Ye?"skipped: tool-call turn (an action request must not be replayed from cache)":_e===!1?"skipped: response fails its output contract":A?'skipped: answer cut off by the output cap (finish_reason "length"); replaying half an answer would bill it as a 100% avoided call':"skipped: answered with a reduced tool view (tool discovery), so it must not be replayed");let G=J?bn(o,{servedModel:ue}):l;if(j&&r.allowExactCache&&s.exactCache!==!1){let Q=this.config.exactCacheTtlMs??864e5,ee=r.maxCacheAgeMs==null?Q:Math.min(Q,r.maxCacheAgeMs);await this.deps.exactCache.set(G,nn,ee);}let P=ue!==n.model;j&&!P&&r.allowSemanticCache&&s.semanticCache&&this.deps.semanticCache?await this.deps.semanticCache.store(o,nn):j&&P&&s.semanticCache&&c.record("cache-write","semantic write skipped: a cheaper model answered, and this cache keys on the model the caller asked for");}catch(k){c.record("cache-write","failed (non-fatal; answer already served)",{error:k instanceof Error?k.message:String(k)});}let on=this.finish(n,o,nn,"miss",i,xe,c,m,y,void 0,void 0,_e,v.backend,Ns,this.informeDeCascada(d,{servedModel:ue,...d.enruta?{escalated:J}:{},...d.elegible&&d.precioBarato?{estimatedSwapSaving:kc(i,J,d.precioBarato,this.costModelFor(n.model))}:{},...ve?{sampled:true,sampleCost:tn(ve.coste),...ve.divergio!==null?{divergedOnSample:ve.divergio}:{}}:{},...i.cascadeInput>0||i.cascadeOutput>0?{cascadeInputTokens:i.cascadeInput,cascadeOutputTokens:i.cascadeOutput}:{}}),ke);return Ye&&(on.toolCalls=O.toolCalls),O.finishReason!==void 0&&(on.finishReason=O.finishReason),on}async descubrirHerramientas(e,n,o,r,s,i,a,c){let l={tools:r,tokensLocalesDelSondeo:0,aplicado:false};if(o.toolDiscovery!==true)return l;if(r.length<2)return c.record("tool-discovery","skipped (nothing to discover)",{candidates:r.length}),l;let u=g=>this.tokensFor(vo(g),n),d=r.map(Ds),p=_s({promptTokens:this.tokensFor(this.assemblePromptText(s),n),esquemasCompletos:r.reduce((g,y)=>g+u(y),0),descriptoresLigeros:d.reduce((g,y)=>g+u(y),0),esquemasDeLaSegunda:Ls(r.map(g=>({risk:g.risk,tokens:u(g)})),3),salidaFinal:n.response?.maxOutputTokens??256,salidaDelSondeo:96,precio:a});if(!p.aplicar)return c.record("tool-discovery","skipped (not worth a second call)",{reason:p.razon,oneCall:p.costeDeUnaLlamada,twoCalls:p.costeDeDosLlamadas}),l;let f,m=this.tokensFor(this.assemblePromptText(s,d),n);try{f=await this.llamarProveedor({model:n.model,messages:s,tools:d,maxOutputTokens:96,...n.temperature!=null?{temperature:n.temperature}:{},...n.seed!=null?{seed:n.seed}:{}},e);}catch(g){return c.record("tool-discovery","failed (falling back to a single call with every schema)",{error:g instanceof Error?g.message:String(g)}),l}i.actualLlm+=1,i.actualInput+=f.usage.inputTokens,i.actualOutput+=f.usage.outputTokens,i.discoveryInput+=f.usage.inputTokens,i.discoveryOutput+=f.usage.outputTokens;let h=As((f.toolCalls??[]).map(g=>g.name),r,3);return h.reconocidos.length===0?(c.record("tool-discovery","degraded: probe named no known tool",{finishReason:f.finishReason??null,...h.ignorados.length?{unknownNames:h.ignorados}:{}}),{tools:r,tokensLocalesDelSondeo:m,aplicado:false}):(c.record("tool-discovery","applied (two provider calls)",{chosen:h.reconocidos,sent:h.tools.map(g=>g.id),candidates:r.length,...h.ignorados.length?{unknownNames:h.ignorados}:{}}),{tools:h.tools,tokensLocalesDelSondeo:m,aplicado:true})}informeDeCascada(e,n={}){if(e.modo!=="off")return {mode:e.modo,servedModel:n.servedModel??e.modeloServido,eligible:e.elegible,reason:e.razon,verifier:e.fuerza,creditedLedger:"none",...e.candidato?{candidateModel:e.candidato}:{},...e.economia?{costRatio:ct(e.economia.r),breakEvenEscalationRate:ct(e.economia.equilibrio),targetEscalationRate:ct(e.economia.escaladoMaximo)}:{},...e.bucket?{workload:e.bucket}:{},...e.observada!=null?{escalationRate:ct(e.observada),escalationSamples:e.muestras}:{},...n,requestedModel:e.modeloPedido}}informeDeDiferido(e,n,o){if(e.deferrable!==true)return;let r=n.requestedServiceTier,s=er(n.servedServiceTier),i={...r?{requestedTier:r}:{},...s?{servedTier:s.servido}:{},credited:false,creditedLedger:"none",latency:or(r),reason:""};if(!r)return {...i,reason:nr};if(!s)return {...i,reason:`asked the provider for the "${r}" tier, and it reported none back: the rate this request was billed at cannot be known, so nothing is credited`};if(s.factor==null)return {...i,reason:`asked for "${r}" and the provider reports serving "${s.servido}", a tier this layer has no published rate for: nothing is credited`};if(!s.conDescuento)return {...i,reason:`asked for "${r}" and the provider reports serving "${s.servido}", which bills at the standard rate: this request was billed as if it had never been deferred`};let a=n.usage,c=Math.min(Math.max(0,a.cachedInputTokens??0),Math.max(0,a.inputTokens)),l=o.cachedInputPer1k??o.inputPer1k,u=(Math.max(0,a.inputTokens)-c)/1e3*o.inputPer1k+c/1e3*l+Math.max(0,a.outputTokens)/1e3*o.outputPer1k,d=tr(s,u);return {...i,credited:true,discountRate:ct(s.factor),...d!=null?{estimatedTierSaving:tn(d)}:{},reason:`the provider reports serving the "${s.servido}" tier, which bills at ${(s.factor*100).toFixed(0)}% of the standard rate; the discount stacks with provider prefix caching rather than replacing it`}}diferidoSinLlamada(e){if(e.savings?.deferrable===true)return {credited:false,creditedLedger:"none",latency:"not applicable: no provider call was made for this request.",reason:"no provider call was made, so no processing tier was served and none is credited; the call was avoided outright, which is worth more than any tier discount on it"}}finish(e,n,o,r,s,i,a,c,l,u,d,p,f="none",m=0,h,g){let y=e.response?.schema,b=p===null?null:p??(y?ae(o.data,y).valid:true),x=this.buildReport(e,n,r,s,i,a,c,l,u,d,b,f,m,h,g??this.diferidoSinLlamada(e));return {requestId:x.requestId,data:o.data,text:o.text,...o.rendered!==void 0?{rendered:o.rendered}:{},report:x}}buildReport(e,n,o,r,s,i,a,c,l,u,d,p,f,m,h){let g=r.estimateCost(s),y=i.elapsed(),b=m!=null&&m.servedModel!==m.requestedModel;return {requestId:this.generateId(),model:m?.servedModel??e.model,calls:{baselineLlm:r.baselineLlm,actualLlm:r.actualLlm,avoidedLlm:r.avoidedLlm,baselineRetrieval:r.baselineRetrieval,actualRetrieval:r.actualRetrieval,baselineTools:r.baselineTools,actualTools:r.actualTools,retries:r.retries},tokens:{baselineInput:r.baselineInput,actualInput:r.actualInput,eliminatedInput:r.eliminatedInput,compressedInput:r.compressedInput,baselineOutput:r.publishedBaselineOutput,actualOutput:r.actualOutput,eliminatedOutput:r.eliminatedOutput,...r.providerCachedInput?{providerCachedInput:r.providerCachedInput}:{}},cache:{result:o,...u!==void 0?{confidence:u}:{},...l!==void 0?{ageMs:l}:{}},routing:{executionClass:a.executionClass,confidence:a.confidence,rounds:r.actualRetrieval,reason:a.reason},serialization:{chosen:c.chosen,candidateTokens:c.candidateTokens,instructionOverheadTokens:c.instructionOverheadTokens},...r.compressionReport?{compression:r.compressionReport}:{},constraints:{backend:p,schemaVersion:n.schemaVersion,...d===null?{}:{structurallyValid:d}},qualityStatus:vc(o,d,b),...m?{modelCascade:m}:{},...h?{deferred:h}:{},quality:{...o!=="miss"?{freshnessPassed:!yn(n).requiresFreshData}:{}},cost:g,latencyMs:{total:y,preprocessing:Math.max(0,y-f),provider:f},traces:i.all()}}async failOpenDirect(e,n){let o=new et(this.now);o.record("fail-open","internal optimizer error \u2014 bypassed to a direct provider call",{error:n instanceof Error?n.message:String(n)});let r=new Ne,s=this.costModelFor(e.model),i;try{i=gn(e);}catch{i={schemaVersion:e.response?.version??e.response?.contractId??"none"};}let a=e.response?.schema,c=this.now(),l=await this.config.provider.generate({model:e.model,messages:e.messages,...e.tools?.length?{tools:e.tools}:{},...a?{schema:a}:{},...e.response?.maxOutputTokens!=null?{maxOutputTokens:e.response.maxOutputTokens}:{},...e.temperature!=null?{temperature:e.temperature}:{},...e.seed!=null?{seed:e.seed}:{}}),u=this.now()-c;r.baselineLlm=1,r.actualLlm=1,r.actualInput=l.usage.inputTokens,r.actualOutput=l.usage.outputTokens,r.baselineInput=l.usage.inputTokens,r.baselineOutput=l.usage.outputTokens,l.usage.cachedInputTokens&&r.providerCached(l.usage.cachedInputTokens);let d=l.text,p=true,f=(l.toolCalls?.length??0)>0;if(f&&(p=null),a&&!f){let h=Ge(l.text);p=h.ok?ae(h.value,a).valid:false,h.ok&&(d=h.value);}let m=this.buildReport(e,i,"miss",r,s,o,lt(),ut(),void 0,void 0,p,"none",u,void 0,e.savings?.deferrable===true?{credited:false,creditedLedger:"none",latency:"unchanged: the fail-open path asks for no processing tier, so this request was scheduled exactly as an ordinary one.",reason:"the optimizer failed and this request went out on the direct fail-open path, which asks for no cheaper tier: that tier can be refused for lack of capacity, and trading availability for a discount on a last-resort call is the wrong trade"}:void 0);return {requestId:m.requestId,data:d,text:l.text,...f?{toolCalls:l.toolCalls}:{},...l.finishReason!==void 0?{finishReason:l.finishReason}:{},report:m}}asCoalescedFollower(e,n,o,r,s){let i=new Ne;i.avoidCall(n,o);let a=i.estimateCost(r),c=this.generateId(),l=this.diferidoSinLlamada(s),u=l?{deferred:l}:{},{deferred:d,...p}=e.report;return {...e,requestId:c,report:{...p,requestId:c,calls:{...e.report.calls,actualLlm:0,avoidedLlm:1},tokens:{baselineInput:i.baselineInput,actualInput:i.actualInput,eliminatedInput:i.eliminatedInput,compressedInput:i.compressedInput,baselineOutput:i.publishedBaselineOutput,actualOutput:i.actualOutput,eliminatedOutput:i.eliminatedOutput,...i.providerCachedInput?{providerCachedInput:i.providerCachedInput}:{}},cache:{result:"singleflight"},...u,cost:a}}}assembleBaselinePrompt(e){return this.assemblePromptText(e.messages,e.tools,e.structuredData)}assemblePromptText(e,n,o){let r=e.map(s=>s.content);o!==void 0&&r.push(JSON.stringify(o));for(let s of n??[])r.push(vo(s));return r.join(`
|
|
30
|
-
`)}tokensFor(e,n){return this.config.tokenizer.count(e,{...n.tokenizer?{tokenizer:n.tokenizer}:{},model:n.model})}estimatorEsExacto(e){let n=this.config.tokenizer;if(typeof n.resolve!="function")return false;try{return n.resolve({...e.tokenizer?{tokenizer:e.tokenizer}:{},model:e.model}).exact===!0}catch{return false}}entitled(e){return this.devOpen()?true:!!this.config.licenseGate&&this.config.licenseGate.isEntitled(e)}precioConocido(e){let n=this.config.costModels;if(n){let o=n[e];if(o)return o;let r=e.indexOf("/");if(r>=0){let s=n[e.slice(r+1)];if(s)return s}}return ft(e)}costModelFor(e){let n=this.precioConocido(e);return n||(this.config.defaultCostModel?this.config.defaultCostModel:(this.avisar(`precio-ilustrativo:${e}`,`[bv-sala] no cost model configured for "${e}"; falling back to the ILLUSTRATIVE default price. Dollar figures will not match your bill. Pass { costModels: { "${e}": { inputPer1k, outputPer1k } } }.`),ds))}};function Ge(t){try{return {ok:!0,value:JSON.parse(t)}}catch{}for(let e of bc(t))try{return {ok:!0,value:JSON.parse(e),rescatado:e}}catch{continue}return {ok:false}}function bc(t){let e=[],n=/```[ \t]*[a-zA-Z0-9_-]*[ \t]*\r?\n([\s\S]*?)```/g;for(let o of t.matchAll(n)){let r=o[1]?.trim();r&&e.push(r);}for(let o of ["{","["]){let r=t.indexOf(o);if(r===-1)continue;let s=yc(t,r);s&&e.push(s);}return e}function yc(t,e){let n=t[e],o=n==="{"?"}":"]",r=0,s=false,i=false;for(let a=e;a<t.length;a+=1){let c=t[a];if(s){i?i=false:c==="\\"?i=true:c==='"'&&(s=false);continue}if(c==='"'){s=true;continue}if(c===n)r+=1;else if(c===o&&(r-=1,r===0))return t.slice(e,a+1)}}function xc(t){return typeof t=="string"?t:JSON.stringify(t,null,2)}function vc(t,e,n=false){if(e===false)return "rejected";if(n)return "bounded_degradation";switch(t){case "deterministic":case "exact":return "exact";case "semantic":return "task_equivalent";default:return "not_verified"}}function ct(t){return Math.round(t*1e6)/1e6}function tn(t){let e=Math.round(t*1e10)/1e10;return e===0?0:e}function kc(t,e,n,o){if(e)return tn(-t.extraCostUsd);let r=s=>t.actualInput/1e3*s.inputPer1k+t.actualOutput/1e3*s.outputPer1k;return tn(r(o)-r(n))}function wc(t,e){if(!(e>0))return false;if(e>=1)return true;let n=ie(`${t}:cascade-sample`);return Number.parseInt(n.slice(0,13),16)/2**52<e}function lt(){return {executionClass:"NO_RETRIEVAL",confidence:1,reason:"n/a (short-circuited)",rounds:0}}function ut(){return {chosen:"json-compact",encoded:"",instruction:"",candidateTokens:{},instructionOverheadTokens:0,reason:"no structured payload"}}function ko(t,e="",n=null){if(t==null||typeof t!="object")return "";let o=t,r=[],s=e||"the value",i=m=>typeof o[m]=="number"?o[m]:null,a=i("maxLength"),c=i("minLength"),l=i("maxItems"),u=i("minItems"),d=i("maximum"),p=i("minimum");if(a!=null){let m=n!=null?Math.min(a,n):a;r.push(`${s}<=${m}ch`);}c!=null&&r.push(`${s}>=${c}ch`),l!=null&&r.push(`${s}<=${l} items`),u!=null&&r.push(`${s}>=${u} items`),d!=null&&r.push(`${s}<=${d}`),p!=null&&r.push(`${s}>=${p}`),typeof o.pattern=="string"&&r.push(`${s} matches /${o.pattern}/`);let f=o.properties;if(f&&typeof f=="object")for(let[m,h]of Object.entries(f)){let g=ko(h,e?`${e}.${m}`:m,n);g&&r.push(g);}if(o.items!==void 0){let m=ko(o.items,`${s} entries`,n);m&&r.push(m);}return r.join("; ")}function dt(t){let e=t.response;return e?e.contractId??e.version??JSON.stringify(e.schema??{}).slice(0,200):""}function Sc(t){return t.some(e=>/exceeds maxItems|exceeds maxLength|match pattern|exceeds maximum|below minimum|below minLength|below minItems/.test(e.message))}function vo(t){return JSON.stringify({type:"function",function:{name:t.id,...t.description?{description:t.description}:{},parameters:t.parameters??{type:"object",properties:{}}}})}function Qt(t,e){for(let n=t.length-1;n>=0;n--)if(t[n].role==="user"){t.splice(n,0,e);return}t.push(e);}function wo(t,e=false){if(e){let n=0;for(;n<t.length&&t[n].role==="system";)n+=1;return n}for(let n=t.length-1;n>=0;n--)if(t[n].role==="user")return n;return wo(t,true)}function Tc(t,e){let n=xo(t,e);return n.cacheReadMultiplier<1?n:null}var Ec=6*3600;function Gp(t){t.licenseGate&&(console.warn("[bvsala] Ignoring the injected `licenseGate`: in the published package a license is only accepted as a `licenseKey` verified against BiVelio's embedded public key. Get yours at https://savings.bivelio.com/dashboard/install"),t={...t,licenseGate:void 0});let n={...t,tokenizer:t.tokenizer??Ro},o,r;if(t.licenseKey&&!t.licenseGate){let a=rs;if(t.licenseServerUrl){let c=new qe,l=p=>Ut(p,a,{revocation:c,...t.now?{now:t.now}:{},maxStalenessSeconds:t.licenseRevocation?.maxStalenessSeconds??Ec}),u=l(t.licenseKey);n.licenseGate={isEntitled:p=>u.isEntitled(p),isActive:()=>u.isActive(),status:()=>u.status()};let d=`${t.licenseServerUrl.replace(/\/+$/,"")}/licenses/revocations`;o=new qt({url:d,publicKeyPem:a,snapshot:c,getRefreshAfter:()=>u.refreshAfter?.(),...t.now?{nowSeconds:()=>Math.floor(t.now()/1e3)}:{},...t.licenseFetch?{fetchImpl:t.licenseFetch}:{},...t.licensePollIntervalSeconds!=null?{pollIntervalSeconds:t.licensePollIntervalSeconds}:{},...t.silenceWarnings!=null?{silenceWarnings:t.silenceWarnings}:{},...t.licenseRevocation??{}}),o.start(),t.serviceAccountKey&&t.licenseRefresh?.enabled!==false&&(r=new Kt({url:`${t.licenseServerUrl.replace(/\/+$/,"")}/api/license/current`,serviceAccountKey:t.serviceAccountKey,publicKey:a,initialToken:t.licenseKey,revocados:c,onNewToken:p=>{u=l(p);},...t.licenseFetch?{fetchImpl:t.licenseFetch}:{},...t.now?{now:t.now}:{},...t.licenseRefresh?.intervalMs!=null?{pollIntervalMs:t.licenseRefresh.intervalMs}:{},...t.licenseRefresh?.leadSeconds!=null?{refreshLeadSeconds:t.licenseRefresh.leadSeconds}:{}}),r.start());}else n.licenseGate=ls(t.licenseKey,a,t.now);}let s=new en(n),i;if(t.serviceAccountKey&&t.metering?.enabled!==false){let a=t.meteringUrl??(t.licenseServerUrl?`${t.licenseServerUrl.replace(/\/+$/,"")}/api/metering/usage`:void 0);if(a){i=new at({url:a,serviceAccountKey:t.serviceAccountKey,...t.metering?.orgId?{orgId:t.metering.orgId}:{},...t.metering?.flushIntervalMs!=null?{flushIntervalMs:t.metering.flushIntervalMs}:{},...t.metering?.maxBatch!=null?{maxBatch:t.metering.maxBatch}:{},...t.metering?.maxBuffer!=null?{maxBuffer:t.metering.maxBuffer}:{},...t.meteringFetch?{fetchImpl:t.meteringFetch}:t.licenseFetch?{fetchImpl:t.licenseFetch}:{},...t.now?{now:t.now}:{},...t.metering?.ci!=null?{ci:t.metering.ci}:{},...t.silenceWarnings!=null?{silenceWarnings:t.silenceWarnings}:{}});let c=t.metering?.ci??ro();if(t.metering?.seatId)i.setSeat(t.metering.seatId,c);else {let l=i;so(t.serviceAccountKey).then(u=>l.setSeat(u,c)).catch(()=>{});}i.start();}}return {generate:async a=>{let c=await s.generate(a);if(i)try{i.record(c.report);}catch{}return c},close:()=>{o?.stop(),r?.stop(),i?.stop();}}}var ef="0.4.
|
|
30
|
+
`)}tokensFor(e,n){return this.config.tokenizer.count(e,{...n.tokenizer?{tokenizer:n.tokenizer}:{},model:n.model})}estimatorEsExacto(e){let n=this.config.tokenizer;if(typeof n.resolve!="function")return false;try{return n.resolve({...e.tokenizer?{tokenizer:e.tokenizer}:{},model:e.model}).exact===!0}catch{return false}}entitled(e){return this.devOpen()?true:!!this.config.licenseGate&&this.config.licenseGate.isEntitled(e)}precioConocido(e){let n=this.config.costModels;if(n){let o=n[e];if(o)return o;let r=e.indexOf("/");if(r>=0){let s=n[e.slice(r+1)];if(s)return s}}return ft(e)}costModelFor(e){let n=this.precioConocido(e);return n||(this.config.defaultCostModel?this.config.defaultCostModel:(this.avisar(`precio-ilustrativo:${e}`,`[bv-sala] no cost model configured for "${e}"; falling back to the ILLUSTRATIVE default price. Dollar figures will not match your bill. Pass { costModels: { "${e}": { inputPer1k, outputPer1k } } }.`),ds))}};function Ge(t){try{return {ok:!0,value:JSON.parse(t)}}catch{}for(let e of bc(t))try{return {ok:!0,value:JSON.parse(e),rescatado:e}}catch{continue}return {ok:false}}function bc(t){let e=[],n=/```[ \t]*[a-zA-Z0-9_-]*[ \t]*\r?\n([\s\S]*?)```/g;for(let o of t.matchAll(n)){let r=o[1]?.trim();r&&e.push(r);}for(let o of ["{","["]){let r=t.indexOf(o);if(r===-1)continue;let s=yc(t,r);s&&e.push(s);}return e}function yc(t,e){let n=t[e],o=n==="{"?"}":"]",r=0,s=false,i=false;for(let a=e;a<t.length;a+=1){let c=t[a];if(s){i?i=false:c==="\\"?i=true:c==='"'&&(s=false);continue}if(c==='"'){s=true;continue}if(c===n)r+=1;else if(c===o&&(r-=1,r===0))return t.slice(e,a+1)}}function xc(t){return typeof t=="string"?t:JSON.stringify(t,null,2)}function vc(t,e,n=false){if(e===false)return "rejected";if(n)return "bounded_degradation";switch(t){case "deterministic":case "exact":return "exact";case "semantic":return "task_equivalent";default:return "not_verified"}}function ct(t){return Math.round(t*1e6)/1e6}function tn(t){let e=Math.round(t*1e10)/1e10;return e===0?0:e}function kc(t,e,n,o){if(e)return tn(-t.extraCostUsd);let r=s=>t.actualInput/1e3*s.inputPer1k+t.actualOutput/1e3*s.outputPer1k;return tn(r(o)-r(n))}function wc(t,e){if(!(e>0))return false;if(e>=1)return true;let n=ie(`${t}:cascade-sample`);return Number.parseInt(n.slice(0,13),16)/2**52<e}function lt(){return {executionClass:"NO_RETRIEVAL",confidence:1,reason:"n/a (short-circuited)",rounds:0}}function ut(){return {chosen:"json-compact",encoded:"",instruction:"",candidateTokens:{},instructionOverheadTokens:0,reason:"no structured payload"}}function ko(t,e="",n=null){if(t==null||typeof t!="object")return "";let o=t,r=[],s=e||"the value",i=m=>typeof o[m]=="number"?o[m]:null,a=i("maxLength"),c=i("minLength"),l=i("maxItems"),u=i("minItems"),d=i("maximum"),p=i("minimum");if(a!=null){let m=n!=null?Math.min(a,n):a;r.push(`${s}<=${m}ch`);}c!=null&&r.push(`${s}>=${c}ch`),l!=null&&r.push(`${s}<=${l} items`),u!=null&&r.push(`${s}>=${u} items`),d!=null&&r.push(`${s}<=${d}`),p!=null&&r.push(`${s}>=${p}`),typeof o.pattern=="string"&&r.push(`${s} matches /${o.pattern}/`);let f=o.properties;if(f&&typeof f=="object")for(let[m,h]of Object.entries(f)){let g=ko(h,e?`${e}.${m}`:m,n);g&&r.push(g);}if(o.items!==void 0){let m=ko(o.items,`${s} entries`,n);m&&r.push(m);}return r.join("; ")}function dt(t){let e=t.response;return e?e.contractId??e.version??JSON.stringify(e.schema??{}).slice(0,200):""}function Sc(t){return t.some(e=>/exceeds maxItems|exceeds maxLength|match pattern|exceeds maximum|below minimum|below minLength|below minItems/.test(e.message))}function vo(t){return JSON.stringify({type:"function",function:{name:t.id,...t.description?{description:t.description}:{},parameters:t.parameters??{type:"object",properties:{}}}})}function Qt(t,e){for(let n=t.length-1;n>=0;n--)if(t[n].role==="user"){t.splice(n,0,e);return}t.push(e);}function wo(t,e=false){if(e){let n=0;for(;n<t.length&&t[n].role==="system";)n+=1;return n}for(let n=t.length-1;n>=0;n--)if(t[n].role==="user")return n;return wo(t,true)}function Tc(t,e){let n=xo(t,e);return n.cacheReadMultiplier<1?n:null}var Ec=6*3600;function Gp(t){t.licenseGate&&(console.warn("[bvsala] Ignoring the injected `licenseGate`: in the published package a license is only accepted as a `licenseKey` verified against BiVelio's embedded public key. Get yours at https://savings.bivelio.com/dashboard/install"),t={...t,licenseGate:void 0});let n={...t,tokenizer:t.tokenizer??Ro},o,r;if(t.licenseKey&&!t.licenseGate){let a=rs;if(t.licenseServerUrl){let c=new qe,l=p=>Ut(p,a,{revocation:c,...t.now?{now:t.now}:{},maxStalenessSeconds:t.licenseRevocation?.maxStalenessSeconds??Ec}),u=l(t.licenseKey);n.licenseGate={isEntitled:p=>u.isEntitled(p),isActive:()=>u.isActive(),status:()=>u.status()};let d=`${t.licenseServerUrl.replace(/\/+$/,"")}/licenses/revocations`;o=new qt({url:d,publicKeyPem:a,snapshot:c,getRefreshAfter:()=>u.refreshAfter?.(),...t.now?{nowSeconds:()=>Math.floor(t.now()/1e3)}:{},...t.licenseFetch?{fetchImpl:t.licenseFetch}:{},...t.licensePollIntervalSeconds!=null?{pollIntervalSeconds:t.licensePollIntervalSeconds}:{},...t.silenceWarnings!=null?{silenceWarnings:t.silenceWarnings}:{},...t.licenseRevocation??{}}),o.start(),t.serviceAccountKey&&t.licenseRefresh?.enabled!==false&&(r=new Kt({url:`${t.licenseServerUrl.replace(/\/+$/,"")}/api/license/current`,serviceAccountKey:t.serviceAccountKey,publicKey:a,initialToken:t.licenseKey,revocados:c,onNewToken:p=>{u=l(p);},...t.licenseFetch?{fetchImpl:t.licenseFetch}:{},...t.now?{now:t.now}:{},...t.licenseRefresh?.intervalMs!=null?{pollIntervalMs:t.licenseRefresh.intervalMs}:{},...t.licenseRefresh?.leadSeconds!=null?{refreshLeadSeconds:t.licenseRefresh.leadSeconds}:{}}),r.start());}else n.licenseGate=ls(t.licenseKey,a,t.now);}let s=new en(n),i;if(t.serviceAccountKey&&t.metering?.enabled!==false){let a=t.meteringUrl??(t.licenseServerUrl?`${t.licenseServerUrl.replace(/\/+$/,"")}/api/metering/usage`:void 0);if(a){i=new at({url:a,serviceAccountKey:t.serviceAccountKey,...t.metering?.orgId?{orgId:t.metering.orgId}:{},...t.metering?.flushIntervalMs!=null?{flushIntervalMs:t.metering.flushIntervalMs}:{},...t.metering?.maxBatch!=null?{maxBatch:t.metering.maxBatch}:{},...t.metering?.maxBuffer!=null?{maxBuffer:t.metering.maxBuffer}:{},...t.meteringFetch?{fetchImpl:t.meteringFetch}:t.licenseFetch?{fetchImpl:t.licenseFetch}:{},...t.now?{now:t.now}:{},...t.metering?.ci!=null?{ci:t.metering.ci}:{},...t.silenceWarnings!=null?{silenceWarnings:t.silenceWarnings}:{}});let c=t.metering?.ci??ro();if(t.metering?.seatId)i.setSeat(t.metering.seatId,c);else {let l=i;so(t.serviceAccountKey).then(u=>l.setSeat(u,c)).catch(()=>{});}i.start();}}return {generate:async a=>{let c=await s.generate(a);if(i)try{i.record(c.report);}catch{}return c},close:()=>{o?.stop(),r?.stop(),i?.stop();}}}var ef="0.4.1";/*! Bundled license information:
|
|
31
31
|
|
|
32
32
|
@noble/curves/utils.js:
|
|
33
33
|
@noble/curves/abstract/modular.js:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bivelio/savings-layer",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "BV-SALA — provider-neutral LLM execution optimizer. A decision layer in front of any LLM provider that cuts the cost of every request while preserving required quality, and reports the saving per call with token-level accounting you can check against your bill. Proprietary and confidential — property of BiVelio Inc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"llm",
|