@bivelio/savings-layer 0.4.26 → 0.4.28
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 +113 -12
- package/dist/adapters/ai-sdk.js +73 -73
- package/dist/adapters/anthropic-sdk.js +67 -66
- package/dist/adapters/langchain.js +60 -58
- package/dist/adapters/mastra.js +65 -65
- package/dist/gateway/bin.js +537 -530
- package/dist/index.d.ts +256 -6
- package/dist/index.js +1293 -1192
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -256,6 +256,19 @@ exists, as for Anthropic models), and `"unmeasured"` when the provider returned
|
|
|
256
256
|
usage. Only `measured` and `reference` figures reach your invoice; estimated ones
|
|
257
257
|
never do.
|
|
258
258
|
|
|
259
|
+
A repeat is valued by reference only when the call that ran reached the provider's
|
|
260
|
+
own API (`https://api.openai.com`, `https://api.anthropic.com` or
|
|
261
|
+
`https://generativelanguage.googleapis.com`), because the list price it is valued at
|
|
262
|
+
is the invoice only there. When `OpenAICompatibleProvider` or `AnthropicProvider`
|
|
263
|
+
points anywhere else — a proxy such as LiteLLM, a gateway, Azure, Bedrock, Vertex —
|
|
264
|
+
or when the Anthropic SDK or LangChain adapter reads that its client does, that call
|
|
265
|
+
leaves no reference: its repeats stay `estimated`, and the `reference` trace of the
|
|
266
|
+
call that ran says `unofficial-origin`. When the layer cannot tell where the call
|
|
267
|
+
went (a provider of your own, the AI SDK and Mastra adapters, a LangChain model that
|
|
268
|
+
does not expose its base URL), the rule applies as it always has. The layer reads the
|
|
269
|
+
configured base URL, not the wire: a custom `fetch` that sends the request elsewhere
|
|
270
|
+
is not seen.
|
|
271
|
+
|
|
259
272
|
**Streaming.** `generateStream()` takes the same request and hands you the answer as
|
|
260
273
|
the provider writes it, then the same `SavingsReport`:
|
|
261
274
|
|
|
@@ -679,6 +692,77 @@ const placedLayer = createSavingsLayer({
|
|
|
679
692
|
|
|
680
693
|
</details>
|
|
681
694
|
|
|
695
|
+
<details>
|
|
696
|
+
<summary><b>Serverless: keep what the layer learns between instances</b></summary>
|
|
697
|
+
|
|
698
|
+
Calibrated reuse and `cacheBreakpoints: "auto"` learn from your traffic, and by default
|
|
699
|
+
what they learn lives in the process. On serverless platforms (Vercel Functions, AWS
|
|
700
|
+
Lambda) an instance may serve one request or live a few minutes, so neither would ever
|
|
701
|
+
get past its starting point. Give each one somewhere to keep it:
|
|
702
|
+
|
|
703
|
+
```ts
|
|
704
|
+
import { InMemorySemanticCache } from "@bivelio/savings-layer";
|
|
705
|
+
|
|
706
|
+
// Any key-value client your instances share, such as Redis.
|
|
707
|
+
type SharedKeyValue = {
|
|
708
|
+
get(key: string): Promise<unknown>;
|
|
709
|
+
set(key: string, value: string, options?: { px: number }): Promise<unknown>;
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
async function serverlessLayer(kv: SharedKeyValue) {
|
|
713
|
+
const semanticCache = new InMemorySemanticCache({ calibration: { maxErrorRate: 0.02 } });
|
|
714
|
+
const saved = await kv.get("bvsala:semantic-calibration");
|
|
715
|
+
if (saved) semanticCache.importCalibration(saved); // the object or its JSON text
|
|
716
|
+
|
|
717
|
+
const layer = createSavingsLayer({
|
|
718
|
+
provider,
|
|
719
|
+
licenseKey: process.env.BIVELIO_LICENSE_KEY,
|
|
720
|
+
semanticCache,
|
|
721
|
+
cacheBreakpoints: "auto",
|
|
722
|
+
cacheBreakpointStore: {
|
|
723
|
+
get: (key) => kv.get(key),
|
|
724
|
+
set: (key, value, ttlMs) => kv.set(key, value, { px: ttlMs }),
|
|
725
|
+
},
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
// After handling requests with `layer`, save the calibration:
|
|
729
|
+
const save = async () => {
|
|
730
|
+
await semanticCache.settled();
|
|
731
|
+
await kv.set("bvsala:semantic-calibration", JSON.stringify(semanticCache.exportCalibration()));
|
|
732
|
+
};
|
|
733
|
+
return { layer, save };
|
|
734
|
+
}
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
- **Breakpoint placement.** The store holds prompt-prefix fingerprints, timestamps and
|
|
738
|
+
counts, one key per traffic class, never prompt text. The layer reads it before
|
|
739
|
+
placing breakpoints and reads and rewrites it after the provider answers, so every
|
|
740
|
+
instance extends the same measurement. If the store fails, that request is placed as
|
|
741
|
+
a fresh instance would place it and nothing is written over what others learned.
|
|
742
|
+
Without a store nothing changes.
|
|
743
|
+
- **Calibration.** The saved state is the whole experiment: both halves of the labels,
|
|
744
|
+
how many tests have already drawn on the confidence budget, and the floor in force.
|
|
745
|
+
Restoring it continues the same calibration, so the bound keeps holding across
|
|
746
|
+
restarts; it never starts the budget over. A state recorded under another embedder,
|
|
747
|
+
verifier, judge or configuration is refused with `CalibrationStateError`. If you pass
|
|
748
|
+
your own `embed`, `verify` or `judge`, name them (`embedderId`, `verifierId`,
|
|
749
|
+
`calibration.judgeId`) so a state can say what it was recorded with.
|
|
750
|
+
- **One line of history.** The bound holds along one line: restore the latest state and
|
|
751
|
+
save from where it went. Instances that continue the same state at the same time
|
|
752
|
+
each spend its remaining confidence again, and the last one to save overwrites the
|
|
753
|
+
others' labels. For one bound across many concurrent instances, calibrate in a single
|
|
754
|
+
long-lived process, or offline with `calibrateSemanticFloor()`, and give every
|
|
755
|
+
instance the certified floor as `acceptThreshold`. The cached answers themselves
|
|
756
|
+
still live in each instance's memory.
|
|
757
|
+
- **Why a predicted cache read did not happen** (Anthropic's own API). With
|
|
758
|
+
`cacheMissDiagnostics: true`, the layer asks Anthropic to compare each marked request
|
|
759
|
+
with the one whose cache entry it expected to read, and puts the provider's
|
|
760
|
+
`cache_miss_reason` in `report.traces` when that read does not arrive. Anthropic
|
|
761
|
+
keeps a short-lived fingerprint (hashes and token-count estimates) of each request
|
|
762
|
+
that opts in; check that against your data-retention terms first.
|
|
763
|
+
|
|
764
|
+
</details>
|
|
765
|
+
|
|
682
766
|
<details>
|
|
683
767
|
<summary><b>Structured output — validated <code>data</code>, not just text</b></summary>
|
|
684
768
|
|
|
@@ -710,10 +794,11 @@ console.log(data.answer); // 8
|
|
|
710
794
|
|
|
711
795
|
When you pass `tools` and the model asks to invoke one, the reply is not the final
|
|
712
796
|
answer: `text` is empty by design and the request is in `toolCalls`. Execute it,
|
|
713
|
-
append the
|
|
797
|
+
append the assistant turn and one `role: "tool"` message per call to `messages`, and
|
|
798
|
+
call `generate()` again.
|
|
714
799
|
|
|
715
800
|
```ts
|
|
716
|
-
import type { ToolDescriptor } from "@bivelio/savings-layer";
|
|
801
|
+
import type { ChatMessage, ToolDescriptor } from "@bivelio/savings-layer";
|
|
717
802
|
|
|
718
803
|
const tools: ToolDescriptor[] = [
|
|
719
804
|
{
|
|
@@ -730,23 +815,33 @@ const tools: ToolDescriptor[] = [
|
|
|
730
815
|
},
|
|
731
816
|
];
|
|
732
817
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
messages: [{ role: "user", content: "What's the weather in Madrid?" }],
|
|
736
|
-
tools,
|
|
737
|
-
});
|
|
818
|
+
// ← your tool
|
|
819
|
+
const getWeather = async (city: string): Promise<string> => `${city}: 21 °C, clear`;
|
|
738
820
|
|
|
739
|
-
|
|
740
|
-
|
|
821
|
+
const messages: ChatMessage[] = [{ role: "user", content: "What's the weather in Madrid?" }];
|
|
822
|
+
let res = await layer.generate({ model: "openai/gpt-4o-mini", messages, tools });
|
|
823
|
+
|
|
824
|
+
while (res.toolCalls?.length) {
|
|
825
|
+
// res.finishReason === "tool_calls". Send the calls back as they came, ids included.
|
|
826
|
+
messages.push({ role: "assistant", content: res.text, toolCalls: res.toolCalls });
|
|
741
827
|
for (const call of res.toolCalls) {
|
|
742
828
|
const args = JSON.parse(call.arguments) as { city: string };
|
|
743
|
-
|
|
829
|
+
const output = await getWeather(args.city);
|
|
830
|
+
messages.push({ role: "tool", toolCallId: call.id, name: call.name, content: output });
|
|
744
831
|
}
|
|
745
|
-
|
|
746
|
-
console.log(res.text);
|
|
832
|
+
res = await layer.generate({ model: "openai/gpt-4o-mini", messages, tools });
|
|
747
833
|
}
|
|
834
|
+
console.log(res.text);
|
|
748
835
|
```
|
|
749
836
|
|
|
837
|
+
- **Ids.** Each result carries the `toolCallId` of the call it answers, and every call
|
|
838
|
+
of a turn gets its result before the next user or assistant message. On Anthropic
|
|
839
|
+
that is what lets the turn travel as `tool_use`/`tool_result` blocks (with the tool
|
|
840
|
+
still in that request's `tools`); otherwise it is sent as plain text, as before, and
|
|
841
|
+
the SDK warns once.
|
|
842
|
+
- **Errors.** When a tool fails, put the error in `content` and set `isError: true`.
|
|
843
|
+
Anthropic receives it as `is_error`; providers without such a flag get the text.
|
|
844
|
+
|
|
750
845
|
A tool‑call turn is never served from cache and never counted as an avoided call:
|
|
751
846
|
an action that has not run yet cannot be a saving.
|
|
752
847
|
|
|
@@ -767,6 +862,12 @@ cached prompt prefix stays the same from one question to the next.
|
|
|
767
862
|
search on every request even with a warm prompt cache. `"always"` skips those checks
|
|
768
863
|
(for example behind a proxy that forwards the search blocks). Requests with an output
|
|
769
864
|
contract, or with the model cascade on, keep the selector.
|
|
865
|
+
- **Across turns.** Append the assistant turn with its `toolCalls` (ids as returned)
|
|
866
|
+
before the tool results, as in any tool conversation. The Anthropic adapter then sends
|
|
867
|
+
the earlier search results back in that turn, so the model calls the tools it already
|
|
868
|
+
found without searching again. It keeps them in memory, per adapter instance and
|
|
869
|
+
bounded; a turn it no longer remembers (another process, say) goes out as before and
|
|
870
|
+
the model searches again.
|
|
770
871
|
- **Whose saving.** The provider's. Your usage counter shows it; the layer credits
|
|
771
872
|
nothing for it and charges no commission on it.
|
|
772
873
|
|
package/dist/adapters/ai-sdk.js
CHANGED
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
import {createSavingsLayer,LicenseError,sha256,stableStringify}from'@bivelio/savings-layer';import {AsyncLocalStorage}from'async_hooks';var j=new Set;function $(t,e,n){t===true||j.has(e)||(j.add(e),console.warn(n));}var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
ultCostModel","exactCache","exactCacheTtlMs","resolvers","exactTokenizer","silenceWarnings","failOpen"];function
|
|
9
|
-
t.completada}var
|
|
10
|
-
let n=U(),r={};for(let
|
|
11
|
-
try{let d=await n.run(s,()=>
|
|
12
|
-
let u=n.run(s,()=>
|
|
13
|
-
"sin-informe",
|
|
14
|
-
stringify(
|
|
1
|
+
import {createSavingsLayer,LicenseError,sha256,stableStringify}from'@bivelio/savings-layer';import {AsyncLocalStorage}from'async_hooks';var j=new Set;function $(t,e,n){t===true||j.has(e)||(j.add(e),console.warn(n));}var N=Symbol.for("@bivelio/savings-layer:provider-origin");var ie="[bvsala] internal: the layer changed a request this adapter must forward unchanged; nothing was sent.",se="[bvsala] internal: the layer asked for a second model call within one framework call;\
|
|
2
|
+
nothing more was sent.",de="[bvsala] internal: the layer called the model outside a framework call; nothing was sent.";function C(t,e,n,r){return {renderizado:t,generar:e,...n?{transmitir:n}:{},invocada:false,
|
|
3
|
+
completada:false,...{}}}async function x(t,e){try{let n=await e();return t.completada=!0,n}catch(n){throw t.errorDelMarco={error:n},n}}function ue(t,e){if(t===e)return true;try{return stableStringify(
|
|
4
|
+
t)===stableStringify(e)}catch{return false}}function G(t,e){let n=t??[],r=e??[];return n.length===r.length&&n.every((a,i)=>ue(a,r[i]))}function le(t,e){return t.model===e.model&&G(t.messages,e.messages)&&G(t.tools,e.tools)}
|
|
5
|
+
function _(t,e){let n=a=>{let i=e.getStore();if(!i)throw new Error(de);if(i.invocada)throw new Error(se);if(!le(a,i.renderizado))throw new Error(ie);return i.invocada=true,i},r={id:`bivelio-adapter:${t}`,
|
|
6
|
+
async generate(a,i){return n(a).generar(i?.signal)},async*generateStream(a,i){let o=n(a);if(o.transmitir){yield*o.transmitir(i?.signal);return}let s=await o.generar(i?.signal);s.text!==""&&(yield {type:"\
|
|
7
|
+
text",delta:s.text}),yield {type:"done",response:s};}};return Object.defineProperty(r,N,{value:()=>e.getStore()?.origen}),r}function U(){return new AsyncLocalStorage}var fe=["licenseKey","licenseServerUrl","serviceAccountKey","licenseRefresh","licenseRevocation","licensePollIntervalSeconds","licenseFetch","metering","meteringUrl","meteringFetch","costModels","defa\
|
|
8
|
+
ultCostModel","exactCache","exactCacheTtlMs","resolvers","exactTokenizer","silenceWarnings","failOpen"];function F(t,e){return e instanceof LicenseError||t.errorDelMarco&&t.errorDelMarco.error===e?false:t.invocada&&
|
|
9
|
+
t.completada}var V="[bvsala] the model answered, but the savings layer failed while accounting for it; the answer is returned unchanged, without a savings report and without a usage record.";function W(t,e){
|
|
10
|
+
let n=U(),r={};for(let o of fe)e[o]!==void 0&&(r[o]=e[o]);let a=createSavingsLayer({...r,provider:_(t,n)}),i=(o,s)=>$(e.silenceWarnings,`${t}:${o}`,s);return {ejecutar(o,s){return n.run(s,()=>a.generate(o))},async generar(o,s){
|
|
11
|
+
try{let d=await n.run(s,()=>a.generate(o));return s.invocada?{tipo:"vivo",result:d}:{tipo:"atajo",result:d}}catch(d){if(F(s,d))return i("sin-informe",V),{tipo:"sin-informe"};throw d}},async transmitir(o,s,d){
|
|
12
|
+
let u=n.run(s,()=>a.generateStream(o,d?{signal:d}:{})).result;s.resultado=u,u.catch(()=>{});let c;try{c=await Promise.race([s.abierta.then(()=>"abierta"),u.then(()=>"resuelta")]);}catch(l){if(F(s,l))return i(
|
|
13
|
+
"sin-informe",V),{tipo:"sin-informe"};throw l}if(c==="abierta")return {tipo:"abierto"};let g=await u;return s.invocada?{tipo:"entero",result:g}:{tipo:"atajo",result:g}},informe(o){let s=JSON.parse(JSON.
|
|
14
|
+
stringify(o));if(e.onReport)try{e.onReport(s);}catch{i("onreport","[bvsala] `onReport` threw; the error was caught and the model call was not affected.");}return s},avisar:i,close(){a.close();}}}function B(){
|
|
15
15
|
let t;return {abierta:new Promise(n=>{t=n;}),abrir:t}}var b=class{pendientes=[];esperando;terminada=false;fallo;push(e){if(this.terminada||this.fallo)return;let n=this.esperando;if(n){this.esperando=void 0,n.resolver({value:e,done:false});return}this.pendientes.
|
|
16
16
|
push(e);}end(){if(this.terminada||this.fallo)return;this.terminada=true;let e=this.esperando;e&&this.pendientes.length===0&&(this.esperando=void 0,e.resolver({value:void 0,done:true}));}fail(e){if(this.terminada||
|
|
17
17
|
this.fallo)return;this.fallo={error:e};let n=this.esperando;n&&this.pendientes.length===0&&(this.esperando=void 0,n.rechazar(e));}get cerrada(){return this.terminada||this.fallo!==void 0}[Symbol.asyncIterator](){
|
|
18
18
|
return {next:()=>this.pendientes.length>0?Promise.resolve({value:this.pendientes.shift(),done:false}):this.fallo?Promise.reject(this.fallo.error):this.terminada?Promise.resolve({value:void 0,done:true}):new Promise(
|
|
19
|
-
(e,n)=>{this.esperando={resolver:e,rechazar:n};}),return:()=>(this.terminada=true,this.pendientes.length=0,Promise.resolve({value:void 0,done:true}))}}};function
|
|
19
|
+
(e,n)=>{this.esperando={resolver:e,rechazar:n};}),return:()=>(this.terminada=true,this.pendientes.length=0,Promise.resolve({value:void 0,done:true}))}}};function f(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function J(t){return typeof t=="string"?[{type:"text",text:t}]:Array.isArray(t)?t.filter(f):[]}function A(t){return t.filter(e=>e.type===
|
|
20
20
|
"text"&&typeof e.text=="string").map(e=>e.text).join(`
|
|
21
|
-
`)}function v(t){if(typeof t=="string")return t;try{return JSON.stringify(t??{})}catch{return "{}"}}function
|
|
22
|
-
"string"?t.value:v(t.value);case "json":case "error-json":return v(t.value);case "execution-denied":return `execution denied${typeof t.reason=="string"?`: ${t.reason}`:""}`;case "content":return
|
|
23
|
-
return v(t)}function e(n){return Array.isArray(n)?n.filter(
|
|
24
|
-
system",content:typeof n.content=="string"?n.content:
|
|
25
|
-
map(i=>({...typeof i.toolCallId=="string"?{id:i.toolCallId}:{},name:String(i.toolName??""),arguments:v(i.input??i.args)}));e.push({role:"assistant",content:
|
|
26
|
-
tool":for(let
|
|
27
|
-
{}});break}}return e}var
|
|
28
|
-
entries(t))if(!(n==="toolCallId"||n==="id")&&!(n==="text"&&t.type==="text")){if(n==="providerOptions"||n==="providerMetadata"){e[n]=
|
|
29
|
-
t:[]).map(e=>
|
|
30
|
-
if(!
|
|
31
|
-
entries(t))n==="prompt"||n==="abortSignal"||n==="headers"||n==="providerOptions"||(e[n]=r);return e.prompt=
|
|
32
|
-
responseFormat;if(
|
|
33
|
-
void 0}function
|
|
34
|
-
outputTokens:g??0,complete:false}}let i=m(r.total),
|
|
35
|
-
void 0?{cacheWriteInputTokens:s}:{},...
|
|
36
|
-
g")return t.unified}function
|
|
37
|
-
|
|
21
|
+
`)}function v(t){if(typeof t=="string")return t;try{return JSON.stringify(t??{})}catch{return "{}"}}function ge(t){if(!f(t))return v(t);switch(t.type){case "text":case "error-text":return typeof t.value==
|
|
22
|
+
"string"?t.value:v(t.value);case "json":case "error-json":return v(t.value);case "execution-denied":return `execution denied${typeof t.reason=="string"?`: ${t.reason}`:""}`;case "content":return A(e(t.value));default:
|
|
23
|
+
return v(t)}function e(n){return Array.isArray(n)?n.filter(f):[]}}function H(t){let e=[];for(let n of Array.isArray(t)?t:[]){if(!f(n))continue;let r=J(n.content);switch(n.role){case "system":e.push({role:"\
|
|
24
|
+
system",content:typeof n.content=="string"?n.content:A(r)});break;case "user":e.push({role:"user",content:A(r)});break;case "assistant":{let a=r.filter(i=>i.type==="tool-call"&&i.providerExecuted!==true).
|
|
25
|
+
map(i=>({...typeof i.toolCallId=="string"?{id:i.toolCallId}:{},name:String(i.toolName??""),arguments:v(i.input??i.args)}));e.push({role:"assistant",content:A(r),...a.length>0?{toolCalls:a}:{}});break}case "\
|
|
26
|
+
tool":for(let a of r)a.type==="tool-result"&&e.push({role:"tool",content:ge(a.output??a.result),...typeof a.toolCallId=="string"?{toolCallId:a.toolCallId}:{},...typeof a.toolName=="string"?{name:a.toolName}:
|
|
27
|
+
{}});break}}return e}var me=new Set(["bivelio","mastra"]);function D(t){if(!f(t))return t;let e={};for(let[n,r]of Object.entries(t))me.has(n)||(e[n]=r);return e}function ve(t){let e={};for(let[n,r]of Object.
|
|
28
|
+
entries(t))if(!(n==="toolCallId"||n==="id")&&!(n==="text"&&t.type==="text")){if(n==="providerOptions"||n==="providerMetadata"){e[n]=D(r);continue}e[n]=r;}return e}function ye(t){return (Array.isArray(t)?
|
|
29
|
+
t:[]).map(e=>f(e)?{role:e.role,content:typeof e.content=="string"?"$text":J(e.content).map(ve),providerOptions:D(e.providerOptions)}:e)}var he=new Set(["anthropic-beta","openai-beta"]);function Re(t){
|
|
30
|
+
if(!f(t))return;let e={};for(let[n,r]of Object.entries(t))he.has(n.toLowerCase())&&r!==void 0&&(e[n.toLowerCase()]=r);return Object.keys(e).length>0?e:void 0}function K(t){let e={};for(let[n,r]of Object.
|
|
31
|
+
entries(t))n==="prompt"||n==="abortSignal"||n==="headers"||n==="providerOptions"||(e[n]=r);return e.prompt=ye(t.prompt),e.headers=Re(t.headers),e.providerOptions=D(t.providerOptions),e}function Z(t){let e=t.
|
|
32
|
+
responseFormat;if(f(e)&&e.type==="json")return true;let n=t.toolChoice;return f(n)&&(n.type==="required"||n.type==="tool")?true:n==="required"}function m(t){return typeof t=="number"&&Number.isFinite(t)?t:
|
|
33
|
+
void 0}function we(t,e){let n=f(t)?t:{},r=f(n.inputTokens)?n.inputTokens:void 0,a=f(n.outputTokens)?n.outputTokens:void 0;if(!r||!a){let c=m(n.inputTokens),g=m(n.outputTokens);return {inputTokens:c??0,
|
|
34
|
+
outputTokens:g??0,complete:false}}let i=m(r.total),o=m(r.cacheRead),s=m(r.cacheWrite),d=m(a.total),p=m(a.reasoning);return {inputTokens:i??0,outputTokens:d??0,...o!==void 0?{cachedInputTokens:o}:{},...s!==
|
|
35
|
+
void 0?{cacheWriteInputTokens:s}:{},...p!==void 0?{reasoningTokens:p}:{},...i!==void 0&&d!==void 0&&!e?{}:{complete:false}}}function Se(t){if(typeof t=="string")return t;if(f(t)&&typeof t.unified=="strin\
|
|
36
|
+
g")return t.unified}function xe(t){switch(t){case void 0:return;case "tool-calls":return "tool_calls";case "content-filter":return "content_filter";default:return t}}function be(t){return f(t)&&Object.keys(
|
|
37
|
+
D(t)).length>0}var R=class{texto="";toolCalls=[];reproducible=true;finish;error;anadir(e){switch(e.type){case "text-delta":{let n=typeof e.delta=="string"?e.delta:typeof e.textDelta=="string"?e.textDelta:
|
|
38
38
|
"";return this.texto+=n,n===""?void 0:n}case "text":{let n=typeof e.text=="string"?e.text:"";return this.texto+=n,n===""?void 0:n}case "tool-call":e.providerExecuted===true?this.reproducible=false:this.toolCalls.
|
|
39
39
|
push({...typeof e.toolCallId=="string"?{id:e.toolCallId}:{},name:String(e.toolName??""),arguments:v(e.input??e.args)});return;case "reasoning":case "reasoning-start":case "reasoning-delta":case "reasoning\
|
|
40
|
-
-end":
|
|
41
|
-
raw":return;case "finish":this.finish=e;return;case "error":this.error={error:e.error};return;default:this.reproducible=false;return}}respuesta(e,n,r){let
|
|
42
|
-
text:this.texto,...this.toolCalls.length>0?{toolCalls:this.toolCalls}:{},...i?{finishReason:i}:{},usage:
|
|
43
|
-
t.content:[])
|
|
44
|
-
return t.text!==""&&e.push({type:"text",text:t.text}),(t.toolCalls??[]).forEach((n,r)=>{e.push({type:"tool-call",toolCallId:n.id??`bvsala-${t.requestId}-${r}`,toolName:n.name,input:n.arguments});}),e}function
|
|
45
|
-
return {unified:(t.toolCalls?.length??0)>0?"tool-calls":"stop",raw:void 0}}function
|
|
46
|
-
response-metadata",...n.response}),t.forEach((
|
|
47
|
-
xt-start",id:
|
|
48
|
-
{providerMetadata:
|
|
49
|
-
id:
|
|
50
|
-
{pull(n){e<t.length?n.enqueue(t[e++]):n.close();}})}function
|
|
51
|
-
return typeof t.provider=="string"&&t.provider.toLowerCase().startsWith("mock")}function y(t,e){return {...
|
|
52
|
-
function ke(t,e,n={}){let r=
|
|
53
|
-
erministicResolvers")&&n.sinResolvers!==true}}function
|
|
54
|
-
let n=e.delProveedor!==true&&
|
|
40
|
+
-end":be(e.providerMetadata)&&(this.reproducible=false);return;case "text-start":case "text-end":case "tool-input-start":case "tool-input-delta":case "tool-input-end":case "stream-start":case "response-metadata":case "\
|
|
41
|
+
raw":return;case "finish":this.finish=e;return;case "error":this.error={error:e.error};return;default:this.reproducible=false;return}}respuesta(e,n,r){let a=Se(n),i=xe(a),o=this.reproducible&&a==="stop";return {
|
|
42
|
+
text:this.texto,...this.toolCalls.length>0?{toolCalls:this.toolCalls}:{},...i?{finishReason:i}:{},usage:we(e,r),...o?{}:{replayable:false}}}};function P(t,e){let n=new R;for(let r of Array.isArray(t.content)?
|
|
43
|
+
t.content:[])f(r)&&n.anadir(r);return n.respuesta(t.usage,t.finishReason,e)}var L={inputTokens:{total:0,noCache:0,cacheRead:0,cacheWrite:0},outputTokens:{total:0,text:0,reasoning:0}};function O(t){let e=[];
|
|
44
|
+
return t.text!==""&&e.push({type:"text",text:t.text}),(t.toolCalls??[]).forEach((n,r)=>{e.push({type:"tool-call",toolCallId:n.id??`bvsala-${t.requestId}-${r}`,toolName:n.name,input:n.arguments});}),e}function I(t){
|
|
45
|
+
return {unified:(t.toolCalls?.length??0)>0?"tool-calls":"stop",raw:void 0}}function T(t,e,n){let r=[{type:"stream-start",warnings:Array.isArray(n.warnings)?n.warnings:[]}];return n.response&&r.push({type:"\
|
|
46
|
+
response-metadata",...n.response}),t.forEach((a,i)=>{if(!f(a))return;let o=`bvsala-${i}`;if(a.type==="text"){let s=a.providerMetadata!==void 0?{providerMetadata:a.providerMetadata}:{};r.push({type:"te\
|
|
47
|
+
xt-start",id:o,...s}),typeof a.text=="string"&&a.text!==""&&r.push({type:"text-delta",id:o,delta:a.text}),r.push({type:"text-end",id:o,...s});}else if(a.type==="reasoning"){let s=a.providerMetadata!==void 0?
|
|
48
|
+
{providerMetadata:a.providerMetadata}:{};r.push({type:"reasoning-start",id:o,...s}),typeof a.text=="string"&&a.text!==""&&r.push({type:"reasoning-delta",id:o,delta:a.text}),r.push({type:"reasoning-end",
|
|
49
|
+
id:o,...s});}else r.push(a);}),r.push({type:"finish",usage:e.usage,finishReason:e.finishReason,...e.providerMetadata!==void 0?{providerMetadata:e.providerMetadata}:{}}),r}function E(t){let e=0;return new ReadableStream(
|
|
50
|
+
{pull(n){e<t.length?n.enqueue(t[e++]):n.close();}})}function Q(t){let e=String(t.modelId??"");if(e.includes("/"))return e;let n=String(t.provider??"").split(".")[0]??"";return n!==""?`${n}/${e}`:e}function X(t){
|
|
51
|
+
return typeof t.provider=="string"&&t.provider.toLowerCase().startsWith("mock")}function y(t,e){return {...f(t)?t:{},bivelio:{savingsReport:e}}}var De={router:false,compression:false,elision:false,serialization:false,toolDiscovery:false,modelCascade:"off",outputCodebook:false,deferrable:false,semanticCache:false,verification:false};
|
|
52
|
+
function ke(t,e,n={}){let r=a=>t?.[a]!==false&&e?.[a]!==false;return {...De,exactCache:r("exactCache")&&n.sinReutilizar!==true,singleflight:r("singleflight")&&n.sinReutilizar!==true,deterministicResolvers:r("det\
|
|
53
|
+
erministicResolvers")&&n.sinResolvers!==true}}function Me(t,e){let n=t.readOnlyTools;if(typeof n=="function")try{return n(e)===!0}catch{return false}return Array.isArray(n)?n.includes(e):false}function ee(t,e){
|
|
54
|
+
let n=e.delProveedor!==true&&Me(t,e.nombre);return {id:e.nombre,intents:[],risk:n?"read":"write",...e.parametros!==void 0&&e.parametros!==null&&typeof e.parametros=="object"?{parameters:e.parametros}:{},
|
|
55
55
|
...typeof e.descripcion=="string"?{description:e.descripcion}:{}}}function w(t,e,n){if(t===null)return null;switch(typeof t){case "string":case "boolean":return t;case "number":return Number.isFinite(t)?
|
|
56
56
|
t:String(t);case "bigint":return `${t.toString()}n`;case "undefined":case "function":case "symbol":return}let r=t;if(r instanceof Uint8Array)return e.push(r),{$bytes:e.length-1};if(r instanceof ArrayBuffer)
|
|
57
57
|
return e.push(new Uint8Array(r)),{$bytes:e.length-1};if(ArrayBuffer.isView(r))return e.push(new Uint8Array(r.buffer,r.byteOffset,r.byteLength)),{$bytes:e.length-1};if(r instanceof URL)return {$url:r.href};
|
|
58
|
-
if(r instanceof Date)return {$date:Number.isNaN(r.getTime())?"invalid":r.toISOString()};if(n.has(r))return "$cycle";n.add(r);try{if(Array.isArray(r))return r.map(i=>{let
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
2,"0")).join("")}let n="";for(let r=0;r<t.length;r+=32768)n+=String.fromCharCode(...t.subarray(r,r+32768));return sha256(n)}async function
|
|
62
|
-
all(e.map(
|
|
58
|
+
if(r instanceof Date)return {$date:Number.isNaN(r.getTime())?"invalid":r.toISOString()};if(n.has(r))return "$cycle";n.add(r);try{if(Array.isArray(r))return r.map(i=>{let o=w(i,e,n);return o===void 0?null:
|
|
59
|
+
o});if(r instanceof Map)return {$map:[...r.entries()].map(i=>w(i,e,n))};if(r instanceof Set)return {$set:[...r.values()].map(i=>w(i,e,n))};let a={};for(let i of Object.keys(r).sort()){let o=w(r[i],e,n);
|
|
60
|
+
o!==void 0&&(a[i]=o);}return a}finally{n.delete(r);}}async function Y(t){let e=globalThis.crypto?.subtle;if(e){let r=new Uint8Array(await e.digest("SHA-256",t));return Array.from(r,a=>a.toString(16).padStart(
|
|
61
|
+
2,"0")).join("")}let n="";for(let r=0;r<t.length;r+=32768)n+=String.fromCharCode(...t.subarray(r,r+32768));return sha256(n)}async function Ce(t){try{let e=[],n=JSON.stringify(w(t,e,new WeakSet))??"null",r=await Promise.
|
|
62
|
+
all(e.map(Y)),a=new TextEncoder().encode(`${n}|${r.join(",")}`);return await Y(a)}catch{return null}}async function te(t,e){let n=await Ce(e.proyeccion),r=`${e.context?.authorizationScope??"default"}|\
|
|
63
63
|
bvsala-adapter:${n??"none"}`;return {model:e.model,messages:e.messages,...e.tools.length>0?{tools:e.tools}:{},...typeof e.temperature=="number"?{temperature:e.temperature}:{},...typeof e.seed=="number"?
|
|
64
|
-
{seed:e.seed}:{},context:{...e.context??{},authorizationScope:r},savings:ke(t.savings,e.savings,{...e.restricciones,...n===null?{sinReutilizar:true}:{}})}}function
|
|
65
|
-
{}}}function
|
|
66
|
-
let d=
|
|
67
|
-
|
|
68
|
-
l.type==="provider-defined"}));return {req:await
|
|
69
|
-
|
|
70
|
-
{}}}return {specificationVersion:"v3",async wrapGenerate(
|
|
71
|
-
"sin-informe")return
|
|
72
|
-
let{req:s,simulado:d}=await r(
|
|
73
|
-
S=>{g={...S,stream:
|
|
74
|
-
o")return g;if(h.tipo==="sin-informe")return
|
|
75
|
-
let
|
|
76
|
-
t a finish part; nothing was measured.")),d.close();return}let u=
|
|
77
|
-
if(c!==void 0&&e.push({type:"text",delta:c}),u.type!=="finish"||e.cerrada){d.enqueue(u);return}e.push({type:"done",response:s.respuesta(u.usage,u.finishReason,
|
|
78
|
-
|
|
79
|
-
by its reader; nothing was measured.")),
|
|
80
|
-
modelId,timestamp:new Date},warnings:[]}}function Ie(t,e,n){let r=O(
|
|
81
|
-
modelId,timestamp:new Date}});return {stream:E(r)}}function
|
|
82
|
-
e)}:t.providerMetadata!==void 0?{providerMetadata:t.providerMetadata}:{}},{warnings:t.warnings,response:n?Object.fromEntries(Object.entries(n).filter(([
|
|
83
|
-
stream:E(r),...t.request!==void 0?{request:t.request}:{},...n?.headers!==void 0?{response:{headers:n.headers}}:{}}}function
|
|
84
|
-
object"||typeof n.requestId!="string"))return n}export{
|
|
64
|
+
{seed:e.seed}:{},context:{...e.context??{},authorizationScope:r},savings:ke(t.savings,e.savings,{...e.restricciones,...n===null?{sinReutilizar:true}:{}})}}function ne(t,e){if(!(!t&&!e))return {...t??{},...e??
|
|
65
|
+
{}}}function re(t){if(!t||typeof t!="object")return {};let e=t,n={};return e.context&&typeof e.context=="object"&&(n.context=e.context),e.savings&&typeof e.savings=="object"&&(n.savings=e.savings),n}var Pe="[bvsala] a streamed call finished but its savings report could not be produced; the model answer was delivered unchanged.";function Xe(t){let e=W("ai-sdk",t),n=t.reportInMetadata!==false;async function r(o,s){
|
|
66
|
+
let d=re(o.providerOptions?.bivelio),p;t.context&&(p=t.context({provider:s.provider,modelId:s.modelId,params:o}));let u=t.modelId?t.modelId({provider:s.provider,modelId:s.modelId}):Q(s),c=(Array.isArray(
|
|
67
|
+
o.tools)?o.tools:[]).map(l=>ee(t,{nombre:String(l.name??l.id??""),descripcion:typeof l.description=="string"?l.description:void 0,parametros:l.inputSchema??l.parameters,delProveedor:l.type==="provider"||
|
|
68
|
+
l.type==="provider-defined"}));return {req:await te(t,{model:u,messages:H(o.prompt),tools:c,temperature:typeof o.temperature=="number"?o.temperature:void 0,seed:typeof o.seed=="number"?o.seed:void 0,context:ne(
|
|
69
|
+
p,d.context),savings:d.savings,proyeccion:{modelo:u,parametros:K(o)},restricciones:{sinResolvers:Z(o)}}),simulado:X(s)}}function a(o){return {model:o.model,messages:o.messages,...o.tools?{tools:o.tools}:
|
|
70
|
+
{}}}return {specificationVersion:"v3",async wrapGenerate(o){let{req:s,simulado:d}=await r(o.params,o.model),p,u=C(a(s),async()=>(p=await x(u,()=>o.doGenerate()),P(p,d))),c=await e.generar(s,u);if(c.tipo===
|
|
71
|
+
"sin-informe")return p;let g=e.informe(c.result.report);if(c.tipo==="vivo"){let l=p;return n?{...l,providerMetadata:y(l.providerMetadata,g)}:l}return Oe(c.result,n?g:void 0,o.model)},async wrapStream(o){
|
|
72
|
+
let{req:s,simulado:d}=await r(o.params,o.model),{abierta:p,abrir:u}=B(),c,g,l=Object.assign(C(a(s),async()=>(c=await x(l,()=>o.doGenerate()),P(c,d)),()=>{let M=new b;return x(l,()=>o.doStream()).then(
|
|
73
|
+
S=>{g={...S,stream:Le(S.stream,M,e,l,d,n)},u();},S=>M.fail(S)),M}),{abierta:p}),k=o.params.abortSignal instanceof AbortSignal?o.params.abortSignal:void 0,h=await e.transmitir(s,l,k);if(h.tipo==="abiert\
|
|
74
|
+
o")return g;if(h.tipo==="sin-informe")return oe(c,void 0);let q=e.informe(h.result.report);return h.tipo==="entero"?oe(c,n?q:void 0):Ie(h.result,n?q:void 0,o.model)},close(){e.close();}}}function Le(t,e,n,r,a,i){
|
|
75
|
+
let o=t.getReader(),s=new R;return new ReadableStream({async pull(d){let p;try{p=await o.read();}catch(l){e.fail(l),d.error(l);return}if(p.done){e.fail(new Error("[bvsala] the model stream ended withou\
|
|
76
|
+
t a finish part; nothing was measured.")),d.close();return}let u=p.value,c=s.anadir(u);if(u.type==="error"){e.fail(u.error??new Error("[bvsala] the model stream reported an error")),d.enqueue(u);return}
|
|
77
|
+
if(c!==void 0&&e.push({type:"text",delta:c}),u.type!=="finish"||e.cerrada){d.enqueue(u);return}e.push({type:"done",response:s.respuesta(u.usage,u.finishReason,a)}),e.end();let g=u;try{let l=await r.resultado,
|
|
78
|
+
k=n.informe(l.report);i&&(g={...u,providerMetadata:y(u.providerMetadata,k)});}catch{n.avisar("informe-del-stream",Pe);}d.enqueue(g);},cancel(d){return e.fail(new Error("[bvsala] the stream was cancelled \
|
|
79
|
+
by its reader; nothing was measured.")),o.cancel(d)}})}function Oe(t,e,n){return {content:O(t),finishReason:I(t),usage:L,...e?{providerMetadata:y(void 0,e)}:{},response:{id:`bvsala-${t.requestId}`,modelId:n.
|
|
80
|
+
modelId,timestamp:new Date},warnings:[]}}function Ie(t,e,n){let r=T(O(t),{usage:L,finishReason:I(t),...e?{providerMetadata:y(void 0,e)}:{}},{warnings:[],response:{id:`bvsala-${t.requestId}`,modelId:n.
|
|
81
|
+
modelId,timestamp:new Date}});return {stream:E(r)}}function oe(t,e){let n=t.response,r=T(Array.isArray(t.content)?t.content:[],{usage:t.usage,finishReason:t.finishReason,...e?{providerMetadata:y(t.providerMetadata,
|
|
82
|
+
e)}:t.providerMetadata!==void 0?{providerMetadata:t.providerMetadata}:{}},{warnings:t.warnings,response:n?Object.fromEntries(Object.entries(n).filter(([a])=>a!=="headers"&&a!=="body")):void 0});return {
|
|
83
|
+
stream:E(r),...t.request!==void 0?{request:t.request}:{},...n?.headers!==void 0?{response:{headers:n.headers}}:{}}}function Ye(t){let n=t?.providerMetadata?.bivelio?.savingsReport;if(!(!n||typeof n!="\
|
|
84
|
+
object"||typeof n.requestId!="string"))return n}export{Ye as getSavingsReport,Xe as savingsMiddleware};
|