@bivelio/savings-layer 0.4.22 → 0.4.25
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/LICENSE +105 -21
- package/README.md +545 -39
- package/dist/adapters/ai-sdk.d.ts +46 -0
- package/dist/adapters/ai-sdk.js +84 -0
- package/dist/adapters/anthropic-sdk.d.ts +35 -0
- package/dist/adapters/anthropic-sdk.js +99 -0
- package/dist/adapters/langchain.d.ts +29 -0
- package/dist/adapters/langchain.js +57 -0
- package/dist/adapters/mastra.d.ts +41 -0
- package/dist/adapters/mastra.js +74 -0
- package/dist/gateway/bin.js +751 -308
- package/dist/index.d.ts +2609 -1461
- package/dist/index.js +1121 -718
- package/docs/terminales/README.md +193 -14
- package/docs/terminales/claude-code.md +11 -4
- package/docs/terminales/cline.md +1 -1
- package/docs/terminales/codex.md +12 -11
- package/docs/terminales/crush.md +1 -1
- package/docs/terminales/droid.md +1 -1
- package/docs/terminales/goose.md +1 -1
- package/docs/terminales/kilo.md +1 -1
- package/docs/terminales/opencode.md +1 -1
- package/docs/terminales/qwen-code.md +1 -1
- package/package.json +70 -4
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { LanguageModelMiddleware } from 'ai';
|
|
2
|
+
import { SavingsAdapterOptions, RequestContext, SavingsReport } from '@bivelio/savings-layer';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link savingsMiddleware}. */
|
|
5
|
+
interface SavingsMiddlewareOptions extends SavingsAdapterOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Cache identity for a call (tenant, session…). `providerOptions.bivelio.context`
|
|
8
|
+
* on the call wins over it, key by key.
|
|
9
|
+
*/
|
|
10
|
+
context?: (call: {
|
|
11
|
+
provider: string;
|
|
12
|
+
modelId: string;
|
|
13
|
+
params: unknown;
|
|
14
|
+
}) => RequestContext | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* The model id the report is priced with. Default: `<provider>/<modelId>`, with
|
|
17
|
+
* the provider's first segment (`openai.responses` gives `openai/...`); a model
|
|
18
|
+
* id that already contains "/" is kept as it is.
|
|
19
|
+
*/
|
|
20
|
+
modelId?: (model: {
|
|
21
|
+
provider: string;
|
|
22
|
+
modelId: string;
|
|
23
|
+
}) => string;
|
|
24
|
+
/** Put the report in `providerMetadata.bivelio.savingsReport` (default true). */
|
|
25
|
+
reportInMetadata?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** The middleware, plus `close()` to stop the layer's background work when shutting down. */
|
|
28
|
+
type SavingsMiddleware = LanguageModelMiddleware & {
|
|
29
|
+
close(): void;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Wrap a model with the savings layer:
|
|
33
|
+
* `wrapLanguageModel({ model, middleware: savingsMiddleware({ licenseKey }) })`.
|
|
34
|
+
* Put it last in the middleware list, so nothing sits between it and the model.
|
|
35
|
+
*/
|
|
36
|
+
declare function savingsMiddleware(options: SavingsMiddlewareOptions): SavingsMiddleware;
|
|
37
|
+
/**
|
|
38
|
+
* The savings report of a call, read from a `generateText` result or step, or
|
|
39
|
+
* from `{ providerMetadata: await result.providerMetadata }` for a stream.
|
|
40
|
+
* `undefined` when the call carried none (for instance `reportInMetadata: false`).
|
|
41
|
+
*/
|
|
42
|
+
declare function getSavingsReport(source: {
|
|
43
|
+
providerMetadata?: unknown;
|
|
44
|
+
} | null | undefined): SavingsReport | undefined;
|
|
45
|
+
|
|
46
|
+
export { type SavingsMiddleware, type SavingsMiddlewareOptions, getSavingsReport, savingsMiddleware };
|
|
@@ -0,0 +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 ae="[bvsala] internal: the layer changed a request this adapter must forward unchanged; no\
|
|
2
|
+
thing was sent.",se="[bvsala] internal: the layer asked for a second model call within one framework call; nothing more was sent.",ie="[bvsala] internal: the layer called the model outside a framework\
|
|
3
|
+
call; nothing was sent.";function C(t,e,n){return {renderizado:t,generar:e,...n?{transmitir:n}:{},invocada:false,completada:false}}async function x(t,e){try{let n=await e();return t.completada=!0,n}catch(n){
|
|
4
|
+
throw t.errorDelMarco={error:n},n}}function de(t,e){if(t===e)return true;try{return stableStringify(t)===stableStringify(e)}catch{return false}}function N(t,e){let n=t??[],r=e??[];return n.length===r.length&&n.every((o,i)=>de(o,r[i]))}
|
|
5
|
+
function ue(t,e){return t.model===e.model&&N(t.messages,e.messages)&&N(t.tools,e.tools)}function G(t,e){let n=r=>{let o=e.getStore();if(!o)throw new Error(ie);if(o.invocada)throw new Error(se);if(!ue(
|
|
6
|
+
r,o.renderizado))throw new Error(ae);return o.invocada=true,o};return {id:`bivelio-adapter:${t}`,async generate(r,o){return n(r).generar(o?.signal)},async*generateStream(r,o){let i=n(r);if(i.transmitir){
|
|
7
|
+
yield*i.transmitir(o?.signal);return}let a=await i.generar(o?.signal);a.text!==""&&(yield {type:"text",delta:a.text}),yield {type:"done",response:a};}}}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 _(t,e){return e instanceof LicenseError||t.errorDelMarco&&t.errorDelMarco.error===e?false:t.invocada&&
|
|
9
|
+
t.completada}var F="[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 a of fe)e[a]!==void 0&&(r[a]=e[a]);let o=createSavingsLayer({...r,provider:G(t,n)}),i=(a,s)=>$(e.silenceWarnings,`${t}:${a}`,s);return {ejecutar(a,s){return n.run(s,()=>o.generate(a))},async generar(a,s){
|
|
11
|
+
try{let d=await n.run(s,()=>o.generate(a));return s.invocada?{tipo:"vivo",result:d}:{tipo:"atajo",result:d}}catch(d){if(_(s,d))return i("sin-informe",F),{tipo:"sin-informe"};throw d}},async transmitir(a,s,d){
|
|
12
|
+
let u=n.run(s,()=>o.generateStream(a,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(_(s,l))return i(
|
|
13
|
+
"sin-informe",F),{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(a){let s=JSON.parse(JSON.
|
|
14
|
+
stringify(a));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(){o.close();}}}function B(){
|
|
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
|
+
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
|
+
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
|
+
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 p(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(p):[]}function D(t){return t.filter(e=>e.type===
|
|
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 pe(t){if(!p(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 D(e(t.value));default:
|
|
23
|
+
return v(t)}function e(n){return Array.isArray(n)?n.filter(p):[]}}function V(t){let e=[];for(let n of Array.isArray(t)?t:[]){if(!p(n))continue;let r=J(n.content);switch(n.role){case "system":e.push({role:"\
|
|
24
|
+
system",content:typeof n.content=="string"?n.content:D(r)});break;case "user":e.push({role:"user",content:D(r)});break;case "assistant":{let o=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:D(r),...o.length>0?{toolCalls:o}:{}});break}case "\
|
|
26
|
+
tool":for(let o of r)o.type==="tool-result"&&e.push({role:"tool",content:pe(o.output??o.result),...typeof o.toolCallId=="string"?{toolCallId:o.toolCallId}:{},...typeof o.toolName=="string"?{name:o.toolName}:
|
|
27
|
+
{}});break}}return e}var ge=new Set(["bivelio","mastra"]);function k(t){if(!p(t))return t;let e={};for(let[n,r]of Object.entries(t))ge.has(n)||(e[n]=r);return e}function me(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]=k(r);continue}e[n]=r;}return e}function ve(t){return (Array.isArray(t)?
|
|
29
|
+
t:[]).map(e=>p(e)?{role:e.role,content:typeof e.content=="string"?"$text":J(e.content).map(me),providerOptions:k(e.providerOptions)}:e)}var ye=new Set(["anthropic-beta","openai-beta"]);function he(t){
|
|
30
|
+
if(!p(t))return;let e={};for(let[n,r]of Object.entries(t))ye.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=ve(t.prompt),e.headers=he(t.headers),e.providerOptions=k(t.providerOptions),e}function H(t){let e=t.
|
|
32
|
+
responseFormat;if(p(e)&&e.type==="json")return true;let n=t.toolChoice;return p(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 Re(t,e){let n=p(t)?t:{},r=p(n.inputTokens)?n.inputTokens:void 0,o=p(n.outputTokens)?n.outputTokens:void 0;if(!r||!o){let c=m(n.inputTokens),g=m(n.outputTokens);return {inputTokens:c??0,
|
|
34
|
+
outputTokens:g??0,complete:false}}let i=m(r.total),a=m(r.cacheRead),s=m(r.cacheWrite),d=m(o.total),f=m(o.reasoning);return {inputTokens:i??0,outputTokens:d??0,...a!==void 0?{cachedInputTokens:a}:{},...s!==
|
|
35
|
+
void 0?{cacheWriteInputTokens:s}:{},...f!==void 0?{reasoningTokens:f}:{},...i!==void 0&&d!==void 0&&!e?{}:{complete:false}}}function we(t){if(typeof t=="string")return t;if(p(t)&&typeof t.unified=="strin\
|
|
36
|
+
g")return t.unified}function Se(t){switch(t){case void 0:return;case "tool-calls":return "tool_calls";case "content-filter":return "content_filter";default:return t}}function xe(t){return p(t)&&Object.keys(
|
|
37
|
+
k(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
|
+
"";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
|
+
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":xe(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 o=we(n),i=Se(o),a=this.reproducible&&o==="stop";return {
|
|
42
|
+
text:this.texto,...this.toolCalls.length>0?{toolCalls:this.toolCalls}:{},...i?{finishReason:i}:{},usage:Re(e,r),...a?{}:{replayable:false}}}};function P(t,e){let n=new R;for(let r of Array.isArray(t.content)?
|
|
43
|
+
t.content:[])p(r)&&n.anadir(r);return n.respuesta(t.usage,t.finishReason,e)}var T={inputTokens:{total:0,noCache:0,cacheRead:0,cacheWrite:0},outputTokens:{total:0,text:0,reasoning:0}};function I(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 L(t){
|
|
45
|
+
return {unified:(t.toolCalls?.length??0)>0?"tool-calls":"stop",raw:void 0}}function O(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((o,i)=>{if(!p(o))return;let a=`bvsala-${i}`;if(o.type==="text"){let s=o.providerMetadata!==void 0?{providerMetadata:o.providerMetadata}:{};r.push({type:"te\
|
|
47
|
+
xt-start",id:a,...s}),typeof o.text=="string"&&o.text!==""&&r.push({type:"text-delta",id:a,delta:o.text}),r.push({type:"text-end",id:a,...s});}else if(o.type==="reasoning"){let s=o.providerMetadata!==void 0?
|
|
48
|
+
{providerMetadata:o.providerMetadata}:{};r.push({type:"reasoning-start",id:a,...s}),typeof o.text=="string"&&o.text!==""&&r.push({type:"reasoning-delta",id:a,delta:o.text}),r.push({type:"reasoning-end",
|
|
49
|
+
id:a,...s});}else r.push(o);}),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 Z(t){let e=String(t.modelId??"");if(e.includes("/"))return e;let n=String(t.provider??"").split(".")[0]??"";return n!==""?`${n}/${e}`:e}function Q(t){
|
|
51
|
+
return typeof t.provider=="string"&&t.provider.toLowerCase().startsWith("mock")}function y(t,e){return {...p(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=o=>t?.[o]!==false&&e?.[o]!==false;return {...De,exactCache:r("exactCache")&&n.sinReutilizar!==true,singleflight:r("singleflight")&&n.sinReutilizar!==true,deterministicResolvers:r("det\
|
|
53
|
+
erministicResolvers")&&n.sinResolvers!==true}}function Ae(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 Y(t,e){
|
|
54
|
+
let n=e.delProveedor!==true&&Ae(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
|
+
...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
|
+
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
|
+
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 a=w(i,e,n);return a===void 0?null:
|
|
59
|
+
a});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 o={};for(let i of Object.keys(r).sort()){let a=w(r[i],e,n);
|
|
60
|
+
a!==void 0&&(o[i]=a);}return o}finally{n.delete(r);}}async function X(t){let e=globalThis.crypto?.subtle;if(e){let r=new Uint8Array(await e.digest("SHA-256",t));return Array.from(r,o=>o.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 Me(t){try{let e=[],n=JSON.stringify(w(t,e,new WeakSet))??"null",r=await Promise.
|
|
62
|
+
all(e.map(X)),o=new TextEncoder().encode(`${n}|${r.join(",")}`);return await X(o)}catch{return null}}async function ee(t,e){let n=await Me(e.proyeccion),r=`${e.context?.authorizationScope??"default"}|\
|
|
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 te(t,e){if(!(!t&&!e))return {...t??{},...e??
|
|
65
|
+
{}}}function ne(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 Ce="[bvsala] a streamed call finished but its savings report could not be produced; the model answer was delivered unchanged.";function He(t){let e=W("ai-sdk",t),n=t.reportInMetadata!==false;async function r(a,s){
|
|
66
|
+
let d=ne(a.providerOptions?.bivelio),f;t.context&&(f=t.context({provider:s.provider,modelId:s.modelId,params:a}));let u=t.modelId?t.modelId({provider:s.provider,modelId:s.modelId}):Z(s),c=(Array.isArray(
|
|
67
|
+
a.tools)?a.tools:[]).map(l=>Y(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 ee(t,{model:u,messages:V(a.prompt),tools:c,temperature:typeof a.temperature=="number"?a.temperature:void 0,seed:typeof a.seed=="number"?a.seed:void 0,context:te(
|
|
69
|
+
f,d.context),savings:d.savings,proyeccion:{modelo:u,parametros:K(a)},restricciones:{sinResolvers:H(a)}}),simulado:Q(s)}}function o(a){return {model:a.model,messages:a.messages,...a.tools?{tools:a.tools}:
|
|
70
|
+
{}}}return {specificationVersion:"v3",async wrapGenerate(a){let{req:s,simulado:d}=await r(a.params,a.model),f,u=C(o(s),async()=>(f=await x(u,()=>a.doGenerate()),P(f,d))),c=await e.generar(s,u);if(c.tipo===
|
|
71
|
+
"sin-informe")return f;let g=e.informe(c.result.report);if(c.tipo==="vivo"){let l=f;return n?{...l,providerMetadata:y(l.providerMetadata,g)}:l}return Te(c.result,n?g:void 0,a.model)},async wrapStream(a){
|
|
72
|
+
let{req:s,simulado:d}=await r(a.params,a.model),{abierta:f,abrir:u}=B(),c,g,l=Object.assign(C(o(s),async()=>(c=await x(l,()=>a.doGenerate()),P(c,d)),()=>{let M=new b;return x(l,()=>a.doStream()).then(
|
|
73
|
+
S=>{g={...S,stream:Pe(S.stream,M,e,l,d,n)},u();},S=>M.fail(S)),M}),{abierta:f}),A=a.params.abortSignal instanceof AbortSignal?a.params.abortSignal:void 0,h=await e.transmitir(s,l,A);if(h.tipo==="abiert\
|
|
74
|
+
o")return g;if(h.tipo==="sin-informe")return re(c,void 0);let q=e.informe(h.result.report);return h.tipo==="entero"?re(c,n?q:void 0):Ie(h.result,n?q:void 0,a.model)},close(){e.close();}}}function Pe(t,e,n,r,o,i){
|
|
75
|
+
let a=t.getReader(),s=new R;return new ReadableStream({async pull(d){let f;try{f=await a.read();}catch(l){e.fail(l),d.error(l);return}if(f.done){e.fail(new Error("[bvsala] the model stream ended withou\
|
|
76
|
+
t a finish part; nothing was measured.")),d.close();return}let u=f.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,o)}),e.end();let g=u;try{let l=await r.resultado,
|
|
78
|
+
A=n.informe(l.report);i&&(g={...u,providerMetadata:y(u.providerMetadata,A)});}catch{n.avisar("informe-del-stream",Ce);}d.enqueue(g);},cancel(d){return e.fail(new Error("[bvsala] the stream was cancelled \
|
|
79
|
+
by its reader; nothing was measured.")),a.cancel(d)}})}function Te(t,e,n){return {content:I(t),finishReason:L(t),usage:T,...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=O(I(t),{usage:T,finishReason:L(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 re(t,e){let n=t.response,r=O(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(([o])=>o!=="headers"&&o!=="body")):void 0});return {
|
|
83
|
+
stream:E(r),...t.request!==void 0?{request:t.request}:{},...n?.headers!==void 0?{response:{headers:n.headers}}:{}}}function Ze(t){let n=t?.providerMetadata?.bivelio?.savingsReport;if(!(!n||typeof n!="\
|
|
84
|
+
object"||typeof n.requestId!="string"))return n}export{Ze as getSavingsReport,He as savingsMiddleware};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Middleware } from '@anthropic-ai/sdk';
|
|
2
|
+
import { SavingsReport, SavingsAdapterOptions, RequestContext } from '@bivelio/savings-layer';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link anthropicSavings}. */
|
|
5
|
+
interface AnthropicSavingsOptions extends SavingsAdapterOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Cache identity for a call (tenant, session…). `requestOptions` is what the
|
|
8
|
+
* call passed as its second argument (`client.messages.create(body, options)`).
|
|
9
|
+
* A `bivelio: { context }` entry in those options wins over it, key by key.
|
|
10
|
+
*/
|
|
11
|
+
context?: (call: {
|
|
12
|
+
body: unknown;
|
|
13
|
+
requestOptions: unknown;
|
|
14
|
+
}) => RequestContext | undefined;
|
|
15
|
+
/** How many reports {@link AnthropicSavings.reportFor} keeps (default 1000, oldest out first). */
|
|
16
|
+
reportCacheSize?: number;
|
|
17
|
+
}
|
|
18
|
+
/** What {@link anthropicSavings} returns. */
|
|
19
|
+
interface AnthropicSavings {
|
|
20
|
+
/** Pass it last in `new Anthropic({ middleware: [..., savings.middleware] })`. */
|
|
21
|
+
readonly middleware: Middleware;
|
|
22
|
+
/** The savings report of a message this client received, by the message or its id. */
|
|
23
|
+
reportFor(message: {
|
|
24
|
+
id: string;
|
|
25
|
+
} | string): SavingsReport | undefined;
|
|
26
|
+
/** Stop the layer's background work when shutting down. */
|
|
27
|
+
close(): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The savings layer as an Anthropic SDK middleware:
|
|
31
|
+
* `new Anthropic({ middleware: [savings.middleware] })`, last in the list.
|
|
32
|
+
*/
|
|
33
|
+
declare function anthropicSavings(options: AnthropicSavingsOptions): AnthropicSavings;
|
|
34
|
+
|
|
35
|
+
export { type AnthropicSavings, type AnthropicSavingsOptions, anthropicSavings };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {createSavingsLayer,LicenseError,sha256,stableStringify}from'@bivelio/savings-layer';import {AsyncLocalStorage}from'async_hooks';var w=t=>typeof t=="number"&&Number.isFinite(t)&&t>0?t:0;function N(t){if(!Array.isArray(t))return null;let e={input:0,output:0,cacheRead:0,cacheWrite:0,cacheWrite1h:0,iteraciones:0};for(let n of t){if(n===
|
|
2
|
+
null||typeof n!="object")continue;let r=n;if(r.type!=="compaction")continue;e.iteraciones++,e.input+=w(r.input_tokens),e.output+=w(r.output_tokens),e.cacheRead+=w(r.cache_read_input_tokens);let o=r.cache_creation,
|
|
3
|
+
s=w(o?.ephemeral_5m_input_tokens),a=w(o?.ephemeral_1h_input_tokens),i=typeof r.cache_creation_input_tokens=="number"?w(r.cache_creation_input_tokens):s+a;e.cacheWrite+=i,e.cacheWrite1h+=Math.min(a,i);}
|
|
4
|
+
return e.iteraciones>0?e:null}function W(t,e,n){let r=t??{},o=N(r.iterations),s=J(r.cache_read_input_tokens,o?.cacheRead),a=J(r.cache_creation_input_tokens,o?.cacheWrite),i=(r.input_tokens??0)+(o?.input??0)+(a??0)+(s??0),u=(e??0)+
|
|
5
|
+
(o?.output??0),d=typeof r.input_tokens!="number",f=typeof e!="number";return {usage:{inputTokens:i,outputTokens:u,...s!=null?{cachedInputTokens:s}:{},...a!=null?{cacheWriteInputTokens:a}:{},...n||f||o?
|
|
6
|
+
{}:{reasoningTokens:0},...d||f?{complete:false}:{}},entradaAusente:d,salidaAusente:f}}function J(t,e){return e?(t??0)+e:t}function B(t){let e=t?.service_tier;return typeof e=="string"&&e!==""?e:void 0}function q(t,e){
|
|
7
|
+
let n=Object.fromEntries(Object.entries(e??{}).filter(([,o])=>o!=null)),r=t?.cache_creation||e?.cache_creation?{...t?.cache_creation??{},...e?.cache_creation??{}}:void 0;return {...t??{},...n,...r?{cache_creation:r}:
|
|
8
|
+
{}}}function F(t){return t==="thinking"||t==="redacted_thinking"}function V(t){switch(t){case "end_turn":return "stop";case "max_tokens":return "length";case "tool_use":return "tool_calls";case "refusal":return "\
|
|
9
|
+
content_filter";default:return t}}var M=class{decoder;resto="";crPendiente=false;alPrincipio=true;datos="";evento="";ultimoId;push(e){let n=typeof e=="string"?e:(this.decoder??=new TextDecoder("utf-8")).decode(e,{stream:true});return this.procesar(
|
|
10
|
+
n)}end(){let e=[];if(this.decoder){let n=this.decoder.decode();n!==""&&e.push(...this.procesar(n));}return this.resto!==""&&(this.linea(this.resto,e),this.resto=""),this.despachar(e),this.crPendiente=false,
|
|
11
|
+
e}procesar(e){let n=[];if(e==="")return n;let r=e;if(this.alPrincipio&&(this.alPrincipio=false,r.charCodeAt(0)===65279&&(r=r.slice(1)),r===""))return n;let o=0;this.crPendiente&&(this.crPendiente=false,r.charCodeAt(
|
|
12
|
+
0)===10&&(o=1));let s=o;for(;o<r.length;){let a=r.charCodeAt(o);if(a!==10&&a!==13){o++;continue}this.linea(this.resto+r.slice(s,o),n),this.resto="",a===13&&(o+1<r.length?r.charCodeAt(o+1)===10&&o++:this.
|
|
13
|
+
crPendiente=true),o++,s=o;}return this.resto+=r.slice(s),n}linea(e,n){if(e===""){this.despachar(n);return}if(e.charCodeAt(0)===58)return;let r=e.indexOf(":"),o,s;switch(r===-1?(o=e,s=""):(o=e.slice(0,r),
|
|
14
|
+
s=e.slice(r+1),s.charCodeAt(0)===32&&(s=s.slice(1))),o){case "data":this.datos+=s+`
|
|
15
|
+
`;break;case "event":this.evento=s;break;case "id":s.includes("\0")||(this.ultimoId=s);break;}}despachar(e){if(this.datos===""){this.evento="";return}e.push({event:this.evento===""?"message":
|
|
16
|
+
this.evento,data:this.datos.slice(0,-1),...this.ultimoId!==void 0?{id:this.ultimoId}:{}}),this.datos="",this.evento="";}};var G=new Set;function H(t,e,n){t===true||G.has(e)||(G.add(e),console.warn(n));}var ge="[bvsala] internal: the layer changed a request this adapter must forward unchanged; no\
|
|
17
|
+
thing was sent.",me="[bvsala] internal: the layer asked for a second model call within one framework call; nothing more was sent.",he="[bvsala] internal: the layer called the model outside a framework\
|
|
18
|
+
call; nothing was sent.";function U(t,e,n){return {renderizado:t,generar:e,...n?{transmitir:n}:{},invocada:false,completada:false}}function ye(t,e){if(t===e)return true;try{return stableStringify(t)===stableStringify(e)}catch{return false}}function Z(t,e){let n=t??[],r=e??[];return n.length===r.length&&n.every((o,s)=>ye(o,r[s]))}function ve(t,e){return t.model===e.
|
|
19
|
+
model&&Z(t.messages,e.messages)&&Z(t.tools,e.tools)}function Q(t,e){let n=r=>{let o=e.getStore();if(!o)throw new Error(he);if(o.invocada)throw new Error(me);if(!ve(r,o.renderizado))throw new Error(ge);
|
|
20
|
+
return o.invocada=true,o};return {id:`bivelio-adapter:${t}`,async generate(r,o){return n(r).generar(o?.signal)},async*generateStream(r,o){let s=n(r);if(s.transmitir){yield*s.transmitir(o?.signal);return}
|
|
21
|
+
let a=await s.generar(o?.signal);a.text!==""&&(yield {type:"text",delta:a.text}),yield {type:"done",response:a};}}}function X(){return new AsyncLocalStorage}var Se=["licenseKey","licenseServerUrl","serviceAccountKey","licenseRefresh","licenseRevocation","licensePollIntervalSeconds","licenseFetch","metering","meteringUrl","meteringFetch","costModels","defa\
|
|
22
|
+
ultCostModel","exactCache","exactCacheTtlMs","resolvers","exactTokenizer","silenceWarnings","failOpen"];function Y(t,e){return e instanceof LicenseError||t.errorDelMarco&&t.errorDelMarco.error===e?false:t.invocada&&
|
|
23
|
+
t.completada}var ee="[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 te(t,e){
|
|
24
|
+
let n=X(),r={};for(let a of Se)e[a]!==void 0&&(r[a]=e[a]);let o=createSavingsLayer({...r,provider:Q(t,n)}),s=(a,i)=>H(e.silenceWarnings,`${t}:${a}`,i);return {ejecutar(a,i){return n.run(i,()=>o.generate(a))},async generar(a,i){
|
|
25
|
+
try{let u=await n.run(i,()=>o.generate(a));return i.invocada?{tipo:"vivo",result:u}:{tipo:"atajo",result:u}}catch(u){if(Y(i,u))return s("sin-informe",ee),{tipo:"sin-informe"};throw u}},async transmitir(a,i,u){
|
|
26
|
+
let f=n.run(i,()=>o.generateStream(a,u?{signal:u}:{})).result;i.resultado=f,f.catch(()=>{});let y;try{y=await Promise.race([i.abierta.then(()=>"abierta"),f.then(()=>"resuelta")]);}catch(_){if(Y(i,_))return s(
|
|
27
|
+
"sin-informe",ee),{tipo:"sin-informe"};throw _}if(y==="abierta")return {tipo:"abierto"};let b=await f;return i.invocada?{tipo:"entero",result:b}:{tipo:"atajo",result:b}},informe(a){let i=JSON.parse(JSON.
|
|
28
|
+
stringify(a));if(e.onReport)try{e.onReport(i);}catch{s("onreport","[bvsala] `onReport` threw; the error was caught and the model call was not affected.");}return i},avisar:s,close(){o.close();}}}function ne(){
|
|
29
|
+
let t;return {abierta:new Promise(n=>{t=n;}),abrir:t}}var C=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.
|
|
30
|
+
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||
|
|
31
|
+
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](){
|
|
32
|
+
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(
|
|
33
|
+
(e,n)=>{this.esperando={resolver:e,rechazar:n};}),return:()=>(this.terminada=true,this.pendientes.length=0,Promise.resolve({value:void 0,done:true}))}}};var we={router:false,compression:false,elision:false,serialization:false,toolDiscovery:false,modelCascade:"off",outputCodebook:false,deferrable:false,semanticCache:false,verification:false};
|
|
34
|
+
function xe(t,e,n={}){let r=o=>t?.[o]!==false&&e?.[o]!==false;return {...we,exactCache:r("exactCache")&&n.sinReutilizar!==true,singleflight:r("singleflight")&&n.sinReutilizar!==true,deterministicResolvers:r("det\
|
|
35
|
+
erministicResolvers")&&n.sinResolvers!==true}}function Ae(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 oe(t,e){
|
|
36
|
+
let n=e.delProveedor!==true&&Ae(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}:{},
|
|
37
|
+
...typeof e.descripcion=="string"?{description:e.descripcion}:{}}}function P(t,e,n){if(t===null)return null;switch(typeof t){case "string":case "boolean":return t;case "number":return Number.isFinite(t)?
|
|
38
|
+
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)
|
|
39
|
+
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};
|
|
40
|
+
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(s=>{let a=P(s,e,n);return a===void 0?null:
|
|
41
|
+
a});if(r instanceof Map)return {$map:[...r.entries()].map(s=>P(s,e,n))};if(r instanceof Set)return {$set:[...r.values()].map(s=>P(s,e,n))};let o={};for(let s of Object.keys(r).sort()){let a=P(r[s],e,n);
|
|
42
|
+
a!==void 0&&(o[s]=a);}return o}finally{n.delete(r);}}async function re(t){let e=globalThis.crypto?.subtle;if(e){let r=new Uint8Array(await e.digest("SHA-256",t));return Array.from(r,o=>o.toString(16).padStart(
|
|
43
|
+
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 ke(t){try{let e=[],n=JSON.stringify(P(t,e,new WeakSet))??"null",r=await Promise.
|
|
44
|
+
all(e.map(re)),o=new TextEncoder().encode(`${n}|${r.join(",")}`);return await re(o)}catch{return null}}async function se(t,e){let n=await ke(e.proyeccion),r=`${e.context?.authorizationScope??"default"}\
|
|
45
|
+
|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"?
|
|
46
|
+
{seed:e.seed}:{},context:{...e.context??{},authorizationScope:r},savings:xe(t.savings,e.savings,{...e.restricciones,...n===null?{sinReutilizar:true}:{}})}}function ae(t,e){if(!(!t&&!e))return {...t??{},...e??
|
|
47
|
+
{}}}function ie(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 I="[bvsala] could not read the request body; nothing was sent.";function p(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function De(t){if((t.method??"GET").toUpperCase()!=="POST")return false;
|
|
48
|
+
try{return new URL(t.url).pathname.replace(/\/+$/,"").endsWith("/v1/messages")}catch{return false}}function x(t){return typeof t=="string"?[{type:"text",text:t}]:Array.isArray(t)?t.filter(p):[]}function L(t){
|
|
49
|
+
return t.filter(e=>e.type==="text"&&typeof e.text=="string").map(e=>e.text).join(`
|
|
50
|
+
`)}function de(t){if(typeof t=="string")return t;try{return JSON.stringify(t??{})}catch{return "{}"}}function Ce(t){let e=[],n=t.system;(typeof n=="string"?n!=="":Array.isArray(n))&&e.push({role:"syste\
|
|
51
|
+
m",content:typeof n=="string"?n:L(x(n))});for(let r of Array.isArray(t.messages)?t.messages:[]){if(!p(r))continue;let o=x(r.content);if(r.role==="assistant"){let a=o.filter(i=>i.type==="tool_use").map(
|
|
52
|
+
i=>({...typeof i.id=="string"?{id:i.id}:{},name:String(i.name??""),arguments:de(i.input)}));e.push({role:"assistant",content:L(o),...a.length>0?{toolCalls:a}:{}});continue}for(let a of o)a.type==="too\
|
|
53
|
+
l_result"&&e.push({role:"tool",content:typeof a.content=="string"?a.content:L(x(a.content)),...typeof a.tool_use_id=="string"?{toolCallId:a.tool_use_id}:{}});let s=L(o);(s!==""||!o.some(a=>a.type==="t\
|
|
54
|
+
ool_result"))&&e.push({role:"user",content:s});}return e}function ce(t){let e={};for(let[n,r]of Object.entries(t))n==="id"||n==="tool_use_id"||n==="text"&&t.type==="text"||(e[n]=r);return e}function Pe(t,e){
|
|
55
|
+
let n={};for(let[r,o]of Object.entries(t))r==="stream"||r==="metadata"||r==="messages"||r==="system"||(n[r]=o);return n.system=typeof t.system=="string"?"$text":x(t.system).map(ce),n.messages=(Array.isArray(
|
|
56
|
+
t.messages)?t.messages:[]).filter(p).map(r=>({role:r.role,content:x(r.content).map(ce)})),e&&(n["anthropic-beta"]=e),n}function Me(t){let e=t.tool_choice;return p(e)&&(e.type==="any"||e.type==="tool")||
|
|
57
|
+
p(t.output_config)&&t.output_config.format!==void 0?true:t.output_format!==void 0}var T=class{id;texto="";razono=false;reproducible=true;parada;usoInicio;usoDelta;vioDelta=false;vioStop=false;error;herramientas=new Map;toolCallsJson=[];bloque(e){
|
|
58
|
+
F(e.type)?(this.razono=true,this.reproducible=false):e.type==="text"?Array.isArray(e.citations)&&e.citations.length>0&&(this.reproducible=false):e.type!=="tool_use"&&(this.reproducible=false);}json(e){this.id=typeof e.
|
|
59
|
+
id=="string"?e.id:void 0;for(let n of x(e.content))this.bloque(n),n.type==="text"&&typeof n.text=="string"&&(this.texto+=n.text),n.type==="tool_use"&&this.toolCallsJson.push({...typeof n.id=="string"?
|
|
60
|
+
{id:n.id}:{},name:String(n.name??""),arguments:de(n.input)});this.parada=typeof e.stop_reason=="string"?e.stop_reason:void 0,this.usoInicio=p(e.usage)?e.usage:void 0,this.usoDelta=this.usoInicio,this.
|
|
61
|
+
vioDelta=true,this.vioStop=true;}evento(e){let n;try{n=JSON.parse(e.data);}catch{return}if(!p(n))return;switch(e.event!=="message"?e.event:String(n.type??e.event)){case "message_start":{let o=p(n.message)?n.
|
|
62
|
+
message:{};typeof o.id=="string"&&(this.id=o.id),p(o.usage)&&(this.usoInicio=o.usage);return}case "content_block_start":{let o=p(n.content_block)?n.content_block:{};this.bloque(o),o.type==="tool_use"&&
|
|
63
|
+
typeof n.index=="number"&&this.herramientas.set(n.index,{...typeof o.id=="string"?{id:o.id}:{},name:String(o.name??""),json:""});return}case "content_block_delta":{let o=p(n.delta)?n.delta:{};if(o.type===
|
|
64
|
+
"text_delta"&&typeof o.text=="string")return this.texto+=o.text,o.text===""?void 0:o.text;if(o.type==="input_json_delta"&&typeof o.partial_json=="string"&&typeof n.index=="number"){let s=this.herramientas.
|
|
65
|
+
get(n.index);s&&(s.json+=o.partial_json);}o.type==="citations_delta"&&(this.reproducible=false);return}case "message_delta":{this.vioDelta=true;let o=p(n.delta)?n.delta:{};typeof o.stop_reason=="string"&&(this.
|
|
66
|
+
parada=o.stop_reason),p(n.usage)&&(this.usoDelta=q(this.usoDelta,n.usage));return}case "message_stop":this.vioStop=true;return;case "error":{let o=p(n.error)?n.error:{};this.error=`${String(o.type??"error")}\
|
|
67
|
+
: ${String(o.message??"")}`;return}default:return}}get toolCalls(){return this.toolCallsJson.length>0?this.toolCallsJson:[...this.herramientas.entries()].sort((e,n)=>e[0]-n[0]).map(([,e])=>({...e.id?{
|
|
68
|
+
id:e.id}:{},name:e.name,arguments:Le(e.json)})).filter(e=>e.name!=="")}respuesta(){let e=q(this.usoInicio,this.usoDelta),n=this.vioDelta?W(e,this.usoDelta?.output_tokens,this.razono).usage:{inputTokens:0,
|
|
69
|
+
outputTokens:0,complete:false},r=e.iterations;Array.isArray(r)&&r.length>1&&(n.complete=false);let o=this.toolCalls,s=B(e);return {text:this.texto,...o.length>0?{toolCalls:o}:{},...this.parada?{finishReason:V(
|
|
70
|
+
this.parada)}:{},...s?{servedServiceTier:s}:{},usage:n,...this.reproducible&&this.parada==="end_turn"?{}:{replayable:false}}}};function Le(t){try{return JSON.stringify(JSON.parse(t===""?"{}":t))}catch{return t}}
|
|
71
|
+
function Te(t,e){let n=[];return t.text!==""&&n.push({type:"text",text:t.text}),(t.toolCalls??[]).forEach((r,o)=>{let s={};try{s=JSON.parse(r.arguments||"{}");}catch{s={};}n.push({type:"tool_use",id:r.id??
|
|
72
|
+
`toolu_bvsala_${t.requestId}_${o}`,name:r.name,input:s});}),{id:`msg_bvsala_${t.requestId}`,type:"message",role:"assistant",model:e,content:n,stop_reason:(t.toolCalls?.length??0)>0?"tool_use":"end_turn",
|
|
73
|
+
stop_sequence:null,usage:{input_tokens:0,output_tokens:0}}}function ue(t,e,n){let r=Te(t,e),o={"request-id":`bvsala_${t.requestId}`};if(!n)return new Response(JSON.stringify(r),{status:200,headers:{...o,
|
|
74
|
+
"content-type":"application/json"}});let s=(i,u)=>`event: ${i}
|
|
75
|
+
data: ${JSON.stringify(u)}
|
|
76
|
+
|
|
77
|
+
`,a=s("message_start",{type:"message_start",message:{...r,content:[],stop_reason:null,stop_sequence:null}});return r.content.forEach((i,u)=>{i.type==="text"?(a+=s("content_block_start",{type:"content_\
|
|
78
|
+
block_start",index:u,content_block:{type:"text",text:""}}),a+=s("content_block_delta",{type:"content_block_delta",index:u,delta:{type:"text_delta",text:i.text}})):(a+=s("content_block_start",{type:"co\
|
|
79
|
+
ntent_block_start",index:u,content_block:{type:"tool_use",id:i.id,name:i.name,input:{}}}),a+=s("content_block_delta",{type:"content_block_delta",index:u,delta:{type:"input_json_delta",partial_json:JSON.
|
|
80
|
+
stringify(i.input)}})),a+=s("content_block_stop",{type:"content_block_stop",index:u});}),a+=s("message_delta",{type:"message_delta",delta:{stop_reason:r.stop_reason,stop_sequence:null},usage:{output_tokens:0}}),
|
|
81
|
+
a+=s("message_stop",{type:"message_stop"}),new Response(a,{status:200,headers:{...o,"content-type":"text/event-stream"}})}var E=class extends Error{constructor(n){super(`[bvsala] provider responded ${n.
|
|
82
|
+
status}`);this.respuesta=n;}respuesta};function et(t){let e=te("anthropic-sdk",t),n=Math.max(1,Math.floor(t.reportCacheSize??1e3)),r=new Map,o=(a,i)=>{if(a)for(r.delete(a),r.set(a,i);r.size>n;)r.delete(
|
|
83
|
+
r.keys().next().value);};return {middleware:async(a,i,u)=>{if(!De(a))return i(a);if(typeof a.body!="string")throw new Error(I);let d;try{let c=JSON.parse(a.body);if(!p(c))throw new Error(I);d=c;}catch{throw new Error(
|
|
84
|
+
I)}let f=u.options,y=ie(f?.bivelio),b=t.context?.({body:d,requestOptions:f}),_=(Array.isArray(d.tools)?d.tools:[]).filter(p).map(c=>oe(t,{nombre:String(c.name??""),descripcion:typeof c.description=="s\
|
|
85
|
+
tring"?c.description:void 0,parametros:c.input_schema,delProveedor:c.input_schema===void 0&&typeof c.type=="string"&&c.type!=="custom"})),l=await se(t,{model:`anthropic/${String(d.model??"")}`,messages:Ce(
|
|
86
|
+
d),tools:_,temperature:typeof d.temperature=="number"?d.temperature:void 0,context:ae(b,y.context),savings:y.savings,proyeccion:Pe(d,a.headers.get("anthropic-beta")),restricciones:{sinResolvers:Me(d)}}),
|
|
87
|
+
v={model:l.model,messages:l.messages,...l.tools?{tools:l.tools}:{}},h=async c=>{let g;try{g=await i(a);}catch(m){throw c.errorDelMarco={error:m},m}if(!g.ok){let m=new E(g);throw c.errorDelMarco={error:m},
|
|
88
|
+
m}return c.completada=true,g},A=c=>{if(c instanceof E)return c.respuesta;throw c};if(d.stream!==true){let c,g,m=U(v,async()=>{c=await h(m);let D=new T;return D.json(await c.clone().json()),g=D.id,D.respuesta()}),
|
|
89
|
+
R;try{R=await e.generar(l,m);}catch(D){return A(D)}if(R.tipo==="sin-informe")return c;let $=e.informe(R.result.report);return R.tipo==="atajo"?(o(`msg_bvsala_${R.result.requestId}`,$),ue(R.result,d.model,
|
|
90
|
+
false)):(o(g,$),c)}let{abierta:pe,abrir:z}=ne(),j,O,k=Object.assign(U(v,async()=>{let c=await h(k),g=new C;O=le(c,g,e,k,o),z();for await(let m of g)if(m.type==="done")return m.response;throw new Error("[\
|
|
91
|
+
bvsala] the model stream ended before completion; nothing was measured.")},()=>{let c=new C;return h(k).then(g=>{j=le(g,c,e,k,o),z();},g=>c.fail(g)),c}),{abierta:pe}),S;try{S=await e.transmitir(l,k,a.signal??
|
|
92
|
+
void 0);}catch(c){return A(c)}if(S.tipo==="abierto")return j??O;if(S.tipo==="atajo"){let c=e.informe(S.result.report);return o(`msg_bvsala_${S.result.requestId}`,c),ue(S.result,d.model,true)}return j??O},
|
|
93
|
+
reportFor(a){let i=typeof a=="string"?a:a?.id;return typeof i=="string"?r.get(i):void 0},close(){e.close();}}}function le(t,e,n,r,o){let s=new T,a,i=async()=>{try{let l=await r.resultado;o(s.id,n.informe(
|
|
94
|
+
l.report));}catch{}},u=()=>{e.cerrada||(s.error?e.fail(new Error(`[bvsala] provider stream error: ${s.error}`)):s.vioDelta||s.vioStop?(e.push({type:"done",response:s.respuesta()}),e.end(),a=i()):e.fail(
|
|
95
|
+
new Error("[bvsala] the model stream ended before completion; nothing was measured.")));};if((t.headers.get("content-type")??"").includes("application/json"))return t.clone().json().then(l=>{s.json(p(l)?
|
|
96
|
+
l:{}),s.texto!==""&&e.push({type:"text",delta:s.texto}),u();},l=>e.fail(l)),t;let d=t.body;if(!d)return e.fail(new Error("[bvsala] the model stream had no body; nothing was measured.")),t;let f=d.getReader(),
|
|
97
|
+
y=new M,b=l=>{for(let v of l){let h=s.evento(v);h!==void 0&&e.push({type:"text",delta:h}),(s.vioStop||s.error)&&u();}},_=new ReadableStream({async pull(l){let v;try{v=await f.read();}catch(A){e.fail(A),
|
|
98
|
+
l.error(A);return}if(v.done){b(y.end()),u(),await a,l.close();return}let h=v.value;l.enqueue(h),b(y.push(h));},cancel(l){return e.fail(new Error("[bvsala] the stream was cancelled by its reader; nothin\
|
|
99
|
+
g was measured.")),f.cancel(l)}});return new Response(_,{status:t.status,statusText:t.statusText,headers:t.headers})}export{et as anthropicSavings};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AgentMiddleware } from 'langchain';
|
|
2
|
+
import { SavingsAdapterOptions, RequestContext, SavingsReport } from '@bivelio/savings-layer';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link savingsAgentMiddleware}. */
|
|
5
|
+
interface SavingsAgentMiddlewareOptions extends SavingsAdapterOptions {
|
|
6
|
+
/** Cache identity for a model call (tenant, session…), read from the agent's model request. */
|
|
7
|
+
context?: (request: unknown) => RequestContext | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* The model id the report is priced with. Default: `<model type>/<model name>`
|
|
10
|
+
* (for instance `openai/gpt-4o-mini`); a name that already contains "/" is kept.
|
|
11
|
+
*/
|
|
12
|
+
modelId?: (model: unknown) => string;
|
|
13
|
+
/** Put the report in `response_metadata.bivelio.savingsReport` of the AI message (default true). */
|
|
14
|
+
reportInMetadata?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** The agent middleware, plus `close()` to stop the layer's background work when shutting down. */
|
|
17
|
+
type SavingsAgentMiddleware = AgentMiddleware & {
|
|
18
|
+
close(): void;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* The savings layer as a LangChain agent middleware:
|
|
22
|
+
* `createAgent({ model, tools, middleware: [..., savingsAgentMiddleware({ licenseKey })] })`,
|
|
23
|
+
* last in the list, so nothing sits between it and the model.
|
|
24
|
+
*/
|
|
25
|
+
declare function savingsAgentMiddleware(options: SavingsAgentMiddlewareOptions): SavingsAgentMiddleware;
|
|
26
|
+
/** The savings report of an AI message produced through {@link savingsAgentMiddleware}. */
|
|
27
|
+
declare function getSavingsReportFromMessage(message: unknown): SavingsReport | undefined;
|
|
28
|
+
|
|
29
|
+
export { type SavingsAgentMiddleware, type SavingsAgentMiddlewareOptions, getSavingsReportFromMessage, savingsAgentMiddleware };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {createMiddleware}from'langchain';import {AIMessage}from'@langchain/core/messages';import {toJsonSchema}from'@langchain/core/utils/json_schema';import {createSavingsLayer,LicenseError,sha256,stableStringify}from'@bivelio/savings-layer';import {AsyncLocalStorage}from'async_hooks';var D=new Set;function _(e,n,t){e===true||D.has(n)||(D.add(n),console.warn(t));}var K="[bvsala] internal: the layer changed a request this adapter must forward unchanged; noth\
|
|
2
|
+
ing was sent.",H="[bvsala] internal: the layer asked for a second model call within one framework call; nothing more was sent.",G="[bvsala] internal: the layer called the model outside a framework cal\
|
|
3
|
+
l; nothing was sent.";function L(e,n,t){return {renderizado:e,generar:n,...{},invocada:false,completada:false}}async function P(e,n){try{let t=await n();return e.completada=!0,t}catch(t){throw e.
|
|
4
|
+
errorDelMarco={error:t},t}}function X(e,n){if(e===n)return true;try{return stableStringify(e)===stableStringify(n)}catch{return false}}function C(e,n){let t=e??[],r=n??[];return t.length===r.length&&t.every((o,s)=>X(o,r[s]))}function Z(e,n){
|
|
5
|
+
return e.model===n.model&&C(e.messages,n.messages)&&C(e.tools,n.tools)}function T(e,n){let t=r=>{let o=n.getStore();if(!o)throw new Error(G);if(o.invocada)throw new Error(H);if(!Z(r,o.renderizado))throw new Error(
|
|
6
|
+
K);return o.invocada=true,o};return {id:`bivelio-adapter:${e}`,async generate(r,o){return t(r).generar(o?.signal)},async*generateStream(r,o){let s=t(r);if(s.transmitir){yield*s.transmitir(o?.signal);return}
|
|
7
|
+
let a=await s.generar(o?.signal);a.text!==""&&(yield {type:"text",delta:a.text}),yield {type:"done",response:a};}}}function O(){return new AsyncLocalStorage}var ee=["licenseKey","licenseServerUrl","serviceAccountKey","licenseRefresh","licenseRevocation","licensePollIntervalSeconds","licenseFetch","metering","meteringUrl","meteringFetch","costModels","defa\
|
|
8
|
+
ultCostModel","exactCache","exactCacheTtlMs","resolvers","exactTokenizer","silenceWarnings","failOpen"];function I(e,n){return n instanceof LicenseError||e.errorDelMarco&&e.errorDelMarco.error===n?false:e.invocada&&
|
|
9
|
+
e.completada}var j="[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 q(e,n){
|
|
10
|
+
let t=O(),r={};for(let a of ee)n[a]!==void 0&&(r[a]=n[a]);let o=createSavingsLayer({...r,provider:T(e,t)}),s=(a,i)=>_(n.silenceWarnings,`${e}:${a}`,i);return {ejecutar(a,i){return t.run(i,()=>o.generate(a))},async generar(a,i){
|
|
11
|
+
try{let l=await t.run(i,()=>o.generate(a));return i.invocada?{tipo:"vivo",result:l}:{tipo:"atajo",result:l}}catch(l){if(I(i,l))return s("sin-informe",j),{tipo:"sin-informe"};throw l}},async transmitir(a,i,l){
|
|
12
|
+
let u=t.run(i,()=>o.generateStream(a,l?{signal:l}:{})).result;i.resultado=u,u.catch(()=>{});let f;try{f=await Promise.race([i.abierta.then(()=>"abierta"),u.then(()=>"resuelta")]);}catch(h){if(I(i,h))return s(
|
|
13
|
+
"sin-informe",j),{tipo:"sin-informe"};throw h}if(f==="abierta")return {tipo:"abierto"};let g=await u;return i.invocada?{tipo:"entero",result:g}:{tipo:"atajo",result:g}},informe(a){let i=JSON.parse(JSON.
|
|
14
|
+
stringify(a));if(n.onReport)try{n.onReport(i);}catch{s("onreport","[bvsala] `onReport` threw; the error was caught and the model call was not affected.");}return i},avisar:s,close(){o.close();}}}var te={router:false,compression:false,elision:false,serialization:false,toolDiscovery:false,modelCascade:"off",outputCodebook:false,deferrable:false,semanticCache:false,verification:false};
|
|
15
|
+
function re(e,n,t={}){let r=o=>e?.[o]!==false&&n?.[o]!==false;return {...te,exactCache:r("exactCache")&&t.sinReutilizar!==true,singleflight:r("singleflight")&&t.sinReutilizar!==true,deterministicResolvers:r("det\
|
|
16
|
+
erministicResolvers")&&t.sinResolvers!==true}}function oe(e,n){let t=e.readOnlyTools;if(typeof t=="function")try{return t(n)===!0}catch{return false}return Array.isArray(t)?t.includes(n):false}function R(e,n){
|
|
17
|
+
let t=n.delProveedor!==true&&oe(e,n.nombre);return {id:n.nombre,intents:[],risk:t?"read":"write",...n.parametros!==void 0&&n.parametros!==null&&typeof n.parametros=="object"?{parameters:n.parametros}:{},
|
|
18
|
+
...typeof n.descripcion=="string"?{description:n.descripcion}:{}}}function y(e,n,t){if(e===null)return null;switch(typeof e){case "string":case "boolean":return e;case "number":return Number.isFinite(e)?
|
|
19
|
+
e:String(e);case "bigint":return `${e.toString()}n`;case "undefined":case "function":case "symbol":return}let r=e;if(r instanceof Uint8Array)return n.push(r),{$bytes:n.length-1};if(r instanceof ArrayBuffer)
|
|
20
|
+
return n.push(new Uint8Array(r)),{$bytes:n.length-1};if(ArrayBuffer.isView(r))return n.push(new Uint8Array(r.buffer,r.byteOffset,r.byteLength)),{$bytes:n.length-1};if(r instanceof URL)return {$url:r.href};
|
|
21
|
+
if(r instanceof Date)return {$date:Number.isNaN(r.getTime())?"invalid":r.toISOString()};if(t.has(r))return "$cycle";t.add(r);try{if(Array.isArray(r))return r.map(s=>{let a=y(s,n,t);return a===void 0?null:
|
|
22
|
+
a});if(r instanceof Map)return {$map:[...r.entries()].map(s=>y(s,n,t))};if(r instanceof Set)return {$set:[...r.values()].map(s=>y(s,n,t))};let o={};for(let s of Object.keys(r).sort()){let a=y(r[s],n,t);
|
|
23
|
+
a!==void 0&&(o[s]=a);}return o}finally{t.delete(r);}}async function E(e){let n=globalThis.crypto?.subtle;if(n){let r=new Uint8Array(await n.digest("SHA-256",e));return Array.from(r,o=>o.toString(16).padStart(
|
|
24
|
+
2,"0")).join("")}let t="";for(let r=0;r<e.length;r+=32768)t+=String.fromCharCode(...e.subarray(r,r+32768));return sha256(t)}async function ae(e){try{let n=[],t=JSON.stringify(y(e,n,new WeakSet))??"null",r=await Promise.
|
|
25
|
+
all(n.map(E)),o=new TextEncoder().encode(`${t}|${r.join(",")}`);return await E(o)}catch{return null}}async function z(e,n){let t=await ae(n.proyeccion),r=`${n.context?.authorizationScope??"default"}|b\
|
|
26
|
+
vsala-adapter:${t??"none"}`;return {model:n.model,messages:n.messages,...n.tools.length>0?{tools:n.tools}:{},...typeof n.temperature=="number"?{temperature:n.temperature}:{},...typeof n.seed=="number"?
|
|
27
|
+
{seed:n.seed}:{},context:{...n.context??{},authorizationScope:r},savings:re(e.savings,n.savings,{...n.restricciones,...t===null?{sinReutilizar:true}:{}})}}function c(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function N(e){let n=e;try{if(typeof n.getType=="function")return n.getType();if(typeof n._getType=="function")return n._getType()}catch{}
|
|
28
|
+
return typeof n.type=="string"?n.type:""}function v(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>c(n)&&n.type==="text"&&typeof n.text=="string").map(n=>n.text).join(`
|
|
29
|
+
`):""}function U(e){if(typeof e=="string")return e;try{return JSON.stringify(e??{})}catch{return "{}"}}function b(e){return (Array.isArray(e.tool_calls)?e.tool_calls:[]).filter(c).map(t=>({...typeof t.id==
|
|
30
|
+
"string"?{id:t.id}:{},name:String(t.name??""),arguments:U(t.args)}))}function le(e,n){let t=[],r=v(e?.content);r!==""&&t.push({role:"system",content:r});for(let o of n){if(!c(o))continue;let s=N(o);if(s===
|
|
31
|
+
"system")t.push({role:"system",content:v(o.content)});else if(s==="human")t.push({role:"user",content:v(o.content)});else if(s==="ai"){let a=b(o);t.push({role:"assistant",content:v(o.content),...a.length>
|
|
32
|
+
0?{toolCalls:a}:{}});}else s==="tool"&&t.push({role:"tool",content:typeof o.content=="string"?o.content:U(o.content),...typeof o.tool_call_id=="string"?{toolCallId:o.tool_call_id}:{},...typeof o.name==
|
|
33
|
+
"string"?{name:o.name}:{}});}return t}function $(e){if(!c(e))return e;let n=e.content,t=N(e),r={};for(let[o,s]of Object.entries(c(e.additional_kwargs)?e.additional_kwargs:{}))o==="tool_calls"||o==="fun\
|
|
34
|
+
ction_call"||o.startsWith("__")||(r[o]=s);return {type:t,name:e.name,content:t==="tool"?n:typeof n=="string"?"$text":Array.isArray(n)?n.map(o=>c(o)&&o.type==="text"?{...o,text:void 0,id:void 0}:o):n,tool_calls:b(
|
|
35
|
+
e).map(o=>({name:o.name,arguments:o.arguments})),status:e.status,additional_kwargs:r}}function ue(e,n){let t=[],r=[];for(let o of n){if(!c(o))continue;if(typeof o.name=="string"&&"schema"in o){let a,i=true;
|
|
36
|
+
try{a=toJsonSchema(o.schema);}catch{i=false;}let l=R(e,{nombre:o.name,descripcion:typeof o.description=="string"?o.description:void 0,parametros:a});t.push(i?l:{...l,risk:"write"}),r.push({name:o.name,description:o.
|
|
37
|
+
description,parametros:a,returnDirect:o.returnDirect});continue}let s=c(o.function)?o.function:void 0;if(o.type==="function"&&s&&typeof s.name=="string"){t.push(R(e,{nombre:s.name,descripcion:typeof s.
|
|
38
|
+
description=="string"?s.description:void 0,parametros:s.parameters})),r.push(o);continue}t.push(R(e,{nombre:String(o.name??o.type??"server-tool"),delProveedor:true})),r.push(o);}return {tools:t,definiciones:r}}
|
|
39
|
+
function F(e){try{let n=e._llmType?.();return typeof n=="string"?n:""}catch{return ""}}function de(e){if(typeof e=="string")return e.replace(":","/");let n=e,t=typeof n.model=="string"?n.model:typeof n.
|
|
40
|
+
modelName=="string"?n.modelName:"";if(t.includes("/"))return t;let r=F(e);return r!==""?`${r}/${t}`:t}function fe(e){try{return e.invocationParams?.({})??null}catch{return null}}function pe(e){let n=e.
|
|
41
|
+
toolChoice;return n==="required"||c(n)?true:e.responseFormat!==void 0}function p(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function ge(e,n){let t=c(e.usage_metadata)?e.usage_metadata:void 0,
|
|
42
|
+
r=p(t?.input_tokens),o=p(t?.output_tokens),s=c(t?.input_token_details)?t.input_token_details:{},a=c(t?.output_token_details)?t.output_token_details:{},i=p(s.cache_read),l=p(s.cache_creation),d=p(a.reasoning),
|
|
43
|
+
u=r!==void 0&&(i??0)+(l??0)<=r;return {inputTokens:r??0,outputTokens:o??0,...i!==void 0?{cachedInputTokens:i}:{},...l!==void 0?{cacheWriteInputTokens:l}:{},...d!==void 0?{reasoningTokens:d}:{},...n&&r!==
|
|
44
|
+
void 0&&o!==void 0&&u?{}:{complete:false}}}function me(e){let n=c(e.response_metadata)?e.response_metadata:{},t=n.finish_reason??n.stop_reason??n.finishReason;switch(t){case "end_turn":case "stop":case "STO\
|
|
45
|
+
P":return "stop";case "max_tokens":case "length":case "MAX_TOKENS":return "length";case "tool_use":case "tool_calls":return "tool_calls";default:return typeof t=="string"?t:void 0}}function ye(e,n){if(n!=="st\
|
|
46
|
+
op")return false;if(Array.isArray(e.content)){for(let r of e.content)if(!c(r)||r.type!=="text"||Array.isArray(r.citations)&&r.citations.length>0||Array.isArray(r.annotations)&&r.annotations.length>0)return false}
|
|
47
|
+
let t=c(e.additional_kwargs)?e.additional_kwargs:{};return !("reasoning"in t||"reasoning_content"in t||"audio"in t)}function ve(e,n){let t=me(e),r=b(e);return {text:v(e.content),...r.length>0?{toolCalls:r}:
|
|
48
|
+
{},...t?{finishReason:t}:{},usage:ge(e,n),...ye(e,t)?{}:{replayable:false}}}function he(e,n){return new AIMessage({content:e.text,tool_calls:(e.toolCalls??[]).map((t,r)=>{let o={};try{let s=JSON.parse(t.arguments||
|
|
49
|
+
"{}");c(s)&&(o=s);}catch{o={};}return {id:t.id??`bvsala-${e.requestId}-${r}`,name:t.name,args:o,type:"tool_call"}}),usage_metadata:{input_tokens:0,output_tokens:0,total_tokens:0},response_metadata:n?{bivelio:{
|
|
50
|
+
savingsReport:n}}:{}})}var we="[bvsala] this LangChain model has its own `cache` set, so a usage counter can be a cached copy rather than a provider bill; its calls are reported as unmeasured.";function qe(e){
|
|
51
|
+
let n=q("langchain",e),t=e.reportInMetadata!==false,r=createMiddleware({name:"BivelioSavings",wrapModelCall:async(o,s)=>{let a=o,i=a.model,l=F(i),d=c(i)&&i.cache!==void 0&&i.cache!==null&&i.cache!==false;d&&n.avisar("cac\
|
|
52
|
+
he-del-modelo",we);let u=!l.toLowerCase().includes("fake")&&!d,f=e.modelId?e.modelId(i):de(i),g=Array.isArray(a.messages)?a.messages:[],{tools:h,definiciones:J}=ue(e,Array.isArray(a.tools)?a.tools:[]),
|
|
53
|
+
B=pe(a),W=p(i?.temperature),m=await z(e,{model:f,messages:le(a.systemMessage,g),tools:h,temperature:W,context:e.context?.(o),proyeccion:{modelo:f,parametros:fe(i),sistema:$(a.systemMessage),mensajes:g.
|
|
54
|
+
map($),herramientas:J,toolChoice:a.toolChoice,responseFormat:a.responseFormat,modelSettings:a.modelSettings},restricciones:{sinResolvers:B,sinReutilizar:a.responseFormat!==void 0}}),w,x=L({model:m.model,
|
|
55
|
+
messages:m.messages,...m.tools?{tools:m.tools}:{}},async()=>(w=await P(x,async()=>s(o)),ve(w,u))),S=await n.generar(m,x);if(S.tipo==="sin-informe")return w;let k=n.informe(S.result.report);if(S.tipo===
|
|
56
|
+
"atajo")return he(S.result,t?k:void 0);let A=w;return t&&(A.response_metadata={...A.response_metadata??{},bivelio:{savingsReport:k}}),A}});return Object.assign(r,{close:()=>n.close()})}function Ee(e){
|
|
57
|
+
let n=e?.response_metadata,t=c(n)?n.bivelio:void 0,r=c(t)?t.savingsReport:void 0;if(!(!c(r)||typeof r.requestId!="string"))return r}export{Ee as getSavingsReportFromMessage,qe as savingsAgentMiddleware};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Processor } from '@mastra/core/processors';
|
|
2
|
+
import { SavingsAdapterOptions, RequestContext } from '@bivelio/savings-layer';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link savingsProcessor}. */
|
|
5
|
+
interface SavingsProcessorOptions extends SavingsAdapterOptions {
|
|
6
|
+
/** Cache identity for a model call (tenant, session…), from the agent's request context. */
|
|
7
|
+
context?: (args: {
|
|
8
|
+
requestContext?: unknown;
|
|
9
|
+
}) => RequestContext | undefined;
|
|
10
|
+
/** Also emit each report as a `data-bivelio-savings-report` stream part (default false). */
|
|
11
|
+
emitReportPart?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Give up on a model call Mastra never reported back, in ms (default 15 minutes).
|
|
14
|
+
* Nothing is recorded for it.
|
|
15
|
+
*/
|
|
16
|
+
providerTimeoutMs?: number;
|
|
17
|
+
/**
|
|
18
|
+
* The model id the report is priced with. Default: `<provider>/<modelId>`, with
|
|
19
|
+
* the provider's first segment; a model id that already contains "/" is kept.
|
|
20
|
+
*/
|
|
21
|
+
modelId?: (model: {
|
|
22
|
+
provider: string;
|
|
23
|
+
modelId: string;
|
|
24
|
+
}) => string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The processor, plus `close()` to stop the layer's background work when shutting down.
|
|
28
|
+
* It implements the step, request, response and API-error hooks, so it is both an
|
|
29
|
+
* input processor and an error processor.
|
|
30
|
+
*/
|
|
31
|
+
type SavingsProcessor = Processor<"bivelio-savings"> & Required<Pick<Processor<"bivelio-savings">, "processInputStep" | "processLLMRequest" | "processLLMResponse" | "processAPIError">> & {
|
|
32
|
+
close(): void;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The savings layer as a Mastra input processor:
|
|
36
|
+
* `new Agent({ ..., inputProcessors: [..., savingsProcessor({ licenseKey })] })`,
|
|
37
|
+
* last in the list, so nothing sits between it and the model.
|
|
38
|
+
*/
|
|
39
|
+
declare function savingsProcessor(options: SavingsProcessorOptions): SavingsProcessor;
|
|
40
|
+
|
|
41
|
+
export { type SavingsProcessor, type SavingsProcessorOptions, savingsProcessor };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {createSavingsLayer,LicenseError,sha256,stableStringify}from'@bivelio/savings-layer';import {AsyncLocalStorage}from'async_hooks';var N=new Set;function $(e,t,n){e===true||N.has(t)||(N.add(t),console.warn(n));}var fe="[bvsala] internal: the layer changed a request this adapter must forward unchanged; no\
|
|
2
|
+
thing was sent.",ge="[bvsala] internal: the layer asked for a second model call within one framework call; nothing more was sent.",me="[bvsala] internal: the layer called the model outside a framework\
|
|
3
|
+
call; nothing was sent.";function F(e,t,n){return {renderizado:e,generar:t,...{},invocada:false,completada:false}}function ve(e,t){if(e===t)return true;try{return stableStringify(e)===stableStringify(t)}catch{return false}}function _(e,t){let n=e??[],r=t??[];return n.length===r.length&&n.every((a,s)=>ve(a,r[s]))}function ye(e,t){return e.model===t.
|
|
4
|
+
model&&_(e.messages,t.messages)&&_(e.tools,t.tools)}function J(e,t){let n=r=>{let a=t.getStore();if(!a)throw new Error(me);if(a.invocada)throw new Error(ge);if(!ye(r,a.renderizado))throw new Error(fe);
|
|
5
|
+
return a.invocada=true,a};return {id:`bivelio-adapter:${e}`,async generate(r,a){return n(r).generar(a?.signal)},async*generateStream(r,a){let s=n(r);if(s.transmitir){yield*s.transmitir(a?.signal);return}
|
|
6
|
+
let i=await s.generar(a?.signal);i.text!==""&&(yield {type:"text",delta:i.text}),yield {type:"done",response:i};}}}function B(){return new AsyncLocalStorage}var Re=["licenseKey","licenseServerUrl","serviceAccountKey","licenseRefresh","licenseRevocation","licensePollIntervalSeconds","licenseFetch","metering","meteringUrl","meteringFetch","costModels","defa\
|
|
7
|
+
ultCostModel","exactCache","exactCacheTtlMs","resolvers","exactTokenizer","silenceWarnings","failOpen"];function W(e,t){return t instanceof LicenseError||e.errorDelMarco&&e.errorDelMarco.error===t?false:e.invocada&&
|
|
8
|
+
e.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 G(e,t){
|
|
9
|
+
let n=B(),r={};for(let i of Re)t[i]!==void 0&&(r[i]=t[i]);let a=createSavingsLayer({...r,provider:J(e,n)}),s=(i,o)=>$(t.silenceWarnings,`${e}:${i}`,o);return {ejecutar(i,o){return n.run(o,()=>a.generate(i))},async generar(i,o){
|
|
10
|
+
try{let l=await n.run(o,()=>a.generate(i));return o.invocada?{tipo:"vivo",result:l}:{tipo:"atajo",result:l}}catch(l){if(W(o,l))return s("sin-informe",V),{tipo:"sin-informe"};throw l}},async transmitir(i,o,l){
|
|
11
|
+
let d=n.run(o,()=>a.generateStream(i,l?{signal:l}:{})).result;o.resultado=d,d.catch(()=>{});let g;try{g=await Promise.race([o.abierta.then(()=>"abierta"),d.then(()=>"resuelta")]);}catch(p){if(W(o,p))return s(
|
|
12
|
+
"sin-informe",V),{tipo:"sin-informe"};throw p}if(g==="abierta")return {tipo:"abierto"};let u=await d;return o.invocada?{tipo:"entero",result:u}:{tipo:"atajo",result:u}},informe(i){let o=JSON.parse(JSON.
|
|
13
|
+
stringify(i));if(t.onReport)try{t.onReport(o);}catch{s("onreport","[bvsala] `onReport` threw; the error was caught and the model call was not affected.");}return o},avisar:s,close(){a.close();}}}function v(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function H(e){return typeof e=="string"?[{type:"text",text:e}]:Array.isArray(e)?e.filter(v):[]}function T(e){return e.filter(t=>t.type===
|
|
14
|
+
"text"&&typeof t.text=="string").map(t=>t.text).join(`
|
|
15
|
+
`)}function h(e){if(typeof e=="string")return e;try{return JSON.stringify(e??{})}catch{return "{}"}}function we(e){if(!v(e))return h(e);switch(e.type){case "text":case "error-text":return typeof e.value==
|
|
16
|
+
"string"?e.value:h(e.value);case "json":case "error-json":return h(e.value);case "execution-denied":return `execution denied${typeof e.reason=="string"?`: ${e.reason}`:""}`;case "content":return T(t(e.value));default:
|
|
17
|
+
return h(e)}function t(n){return Array.isArray(n)?n.filter(v):[]}}function K(e){let t=[];for(let n of Array.isArray(e)?e:[]){if(!v(n))continue;let r=H(n.content);switch(n.role){case "system":t.push({role:"\
|
|
18
|
+
system",content:typeof n.content=="string"?n.content:T(r)});break;case "user":t.push({role:"user",content:T(r)});break;case "assistant":{let a=r.filter(s=>s.type==="tool-call"&&s.providerExecuted!==true).
|
|
19
|
+
map(s=>({...typeof s.toolCallId=="string"?{id:s.toolCallId}:{},name:String(s.toolName??""),arguments:h(s.input??s.args)}));t.push({role:"assistant",content:T(r),...a.length>0?{toolCalls:a}:{}});break}case "\
|
|
20
|
+
tool":for(let a of r)a.type==="tool-result"&&t.push({role:"tool",content:we(a.output??a.result),...typeof a.toolCallId=="string"?{toolCallId:a.toolCallId}:{},...typeof a.toolName=="string"?{name:a.toolName}:
|
|
21
|
+
{}});break}}return t}var xe=new Set(["bivelio","mastra"]);function x(e){if(!v(e))return e;let t={};for(let[n,r]of Object.entries(e))xe.has(n)||(t[n]=r);return t}function Se(e){let t={};for(let[n,r]of Object.
|
|
22
|
+
entries(e))if(!(n==="toolCallId"||n==="id")&&!(n==="text"&&e.type==="text")){if(n==="providerOptions"||n==="providerMetadata"){t[n]=x(r);continue}t[n]=r;}return t}function Z(e){return (Array.isArray(e)?
|
|
23
|
+
e:[]).map(t=>v(t)?{role:t.role,content:typeof t.content=="string"?"$text":H(t.content).map(Se),providerOptions:x(t.providerOptions)}:t)}var ke=new Set(["anthropic-beta","openai-beta"]);function Q(e){if(!v(
|
|
24
|
+
e))return;let t={};for(let[n,r]of Object.entries(e))ke.has(n.toLowerCase())&&r!==void 0&&(t[n.toLowerCase()]=r);return Object.keys(t).length>0?t:void 0}function y(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function X(e,t){let n=v(e)?e:{},r=v(n.inputTokens)?n.inputTokens:void 0,a=v(n.outputTokens)?n.outputTokens:void 0;if(!r||!a){let g=y(
|
|
25
|
+
n.inputTokens),u=y(n.outputTokens);return {inputTokens:g??0,outputTokens:u??0,complete:false}}let s=y(r.total),i=y(r.cacheRead),o=y(r.cacheWrite),l=y(a.total),c=y(a.reasoning);return {inputTokens:s??0,outputTokens:l??
|
|
26
|
+
0,...i!==void 0?{cachedInputTokens:i}:{},...o!==void 0?{cacheWriteInputTokens:o}:{},...c!==void 0?{reasoningTokens:c}:{},...s!==void 0&&l!==void 0&&!t?{}:{complete:false}}}function Y(e){switch(e){case void 0:return;case "tool-calls":return "tool_calls";case "content-filter":return "content_filter";default:return e}}function ee(e){let t=String(e.modelId??"");if(t.includes("/"))return t;let n=String(e.provider??"").split(".")[0]??"";return n!==""?`${n}/${t}`:t}function te(e){return typeof e.provider=="string"&&e.provider.
|
|
27
|
+
toLowerCase().startsWith("mock")}var De={router:false,compression:false,elision:false,serialization:false,toolDiscovery:false,modelCascade:"off",outputCodebook:false,deferrable:false,semanticCache:false,verification:false};
|
|
28
|
+
function Pe(e,t,n={}){let r=a=>e?.[a]!==false&&t?.[a]!==false;return {...De,exactCache:r("exactCache")&&n.sinReutilizar!==true,singleflight:r("singleflight")&&n.sinReutilizar!==true,deterministicResolvers:r("det\
|
|
29
|
+
erministicResolvers")&&n.sinResolvers!==true}}function Ce(e,t){let n=e.readOnlyTools;if(typeof n=="function")try{return n(t)===!0}catch{return false}return Array.isArray(n)?n.includes(t):false}function re(e,t){
|
|
30
|
+
let n=t.delProveedor!==true&&Ce(e,t.nombre);return {id:t.nombre,intents:[],risk:n?"read":"write",...t.parametros!==void 0&&t.parametros!==null&&typeof t.parametros=="object"?{parameters:t.parametros}:{},
|
|
31
|
+
...typeof t.descripcion=="string"?{description:t.descripcion}:{}}}function S(e,t,n){if(e===null)return null;switch(typeof e){case "string":case "boolean":return e;case "number":return Number.isFinite(e)?
|
|
32
|
+
e:String(e);case "bigint":return `${e.toString()}n`;case "undefined":case "function":case "symbol":return}let r=e;if(r instanceof Uint8Array)return t.push(r),{$bytes:t.length-1};if(r instanceof ArrayBuffer)
|
|
33
|
+
return t.push(new Uint8Array(r)),{$bytes:t.length-1};if(ArrayBuffer.isView(r))return t.push(new Uint8Array(r.buffer,r.byteOffset,r.byteLength)),{$bytes:t.length-1};if(r instanceof URL)return {$url:r.href};
|
|
34
|
+
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(s=>{let i=S(s,t,n);return i===void 0?null:
|
|
35
|
+
i});if(r instanceof Map)return {$map:[...r.entries()].map(s=>S(s,t,n))};if(r instanceof Set)return {$set:[...r.values()].map(s=>S(s,t,n))};let a={};for(let s of Object.keys(r).sort()){let i=S(r[s],t,n);
|
|
36
|
+
i!==void 0&&(a[s]=i);}return a}finally{n.delete(r);}}async function ne(e){let t=globalThis.crypto?.subtle;if(t){let r=new Uint8Array(await t.digest("SHA-256",e));return Array.from(r,a=>a.toString(16).padStart(
|
|
37
|
+
2,"0")).join("")}let n="";for(let r=0;r<e.length;r+=32768)n+=String.fromCharCode(...e.subarray(r,r+32768));return sha256(n)}async function Te(e){try{let t=[],n=JSON.stringify(S(e,t,new WeakSet))??"null",r=await Promise.
|
|
38
|
+
all(t.map(ne)),a=new TextEncoder().encode(`${n}|${r.join(",")}`);return await ne(a)}catch{return null}}async function oe(e,t){let n=await Te(t.proyeccion),r=`${t.context?.authorizationScope??"default"}\
|
|
39
|
+
|bvsala-adapter:${n??"none"}`;return {model:t.model,messages:t.messages,...t.tools.length>0?{tools:t.tools}:{},...typeof t.temperature=="number"?{temperature:t.temperature}:{},...typeof t.seed=="number"?
|
|
40
|
+
{seed:t.seed}:{},context:{...t.context??{},authorizationScope:r},savings:Pe(e.savings,t.savings,{...t.restricciones,...n===null?{sinReutilizar:true}:{}})}}function ae(e,t){if(!(!e&&!t))return {...e??{},...t??
|
|
41
|
+
{}}}function se(e){if(!e||typeof e!="object")return {};let t=e,n={};return t.context&&typeof t.context=="object"&&(n.context=t.context),t.savings&&typeof t.savings=="object"&&(n.savings=t.savings),n}function f(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}var ie="bivelio.paso",k="bivelio.pendiente";function le(e){for(let t of [e.parameters,e.inputSchema]){if(f(t)&&f(t.jsonSchema))return {
|
|
42
|
+
esquema:t.jsonSchema,legible:true};if(f(t)&&(t.type==="object"||f(t.properties)))return {esquema:t,legible:true}}return {legible:false}}function Me(e){let t=[],n=false,r=Array.isArray(e.activeTools)?new Set(e.activeTools.
|
|
43
|
+
map(String)):void 0;for(let[i,o]of Object.entries(f(e.tools)?e.tools:{})){if(r&&!r.has(i)||!f(o))continue;let{esquema:l,legible:c}=le(o),d=c;try{JSON.stringify(l);}catch{d=false;}d||(n=true),t.push({nombre:i,
|
|
44
|
+
...typeof o.description=="string"?{descripcion:o.description}:{},...d?{parametros:l}:{},delProveedor:o.type==="provider-defined"||o.type==="provider"});}let a=f(e.structuredOutput)?e.structuredOutput:void 0,
|
|
45
|
+
s;if(a){let{esquema:i}=le({inputSchema:a.schema});s=i??true;}return {paso:typeof e.stepNumber=="number"?e.stepNumber:-1,herramientas:t,esquemaIlegible:n,toolChoice:e.toolChoice,activeTools:e.activeTools,providerOptions:e.
|
|
46
|
+
providerOptions,modelSettings:e.modelSettings,...s!==void 0?{salidaEstructurada:s}:{}}}function Le(e){if(!f(e))return;let t={};for(let[n,r]of Object.entries(e))n==="maxRetries"||n==="abortSignal"||n===
|
|
47
|
+
"headers"||(t[n]=r);return t.headers=Q(e.headers),t}function Oe(e,t){let n="",r=[],a=true,s;for(let u of e){if(!f(u))continue;let p=f(u.payload)?u.payload:{};switch(u.type){case "error":return {error:p.error??
|
|
48
|
+
new Error("[bvsala] the model call failed")};case "text-delta":typeof p.text=="string"&&(n+=p.text);break;case "tool-call":p.providerExecuted===true?a=false:r.push({...typeof p.toolCallId=="string"?{id:p.toolCallId}:
|
|
49
|
+
{},name:String(p.toolName??""),arguments:h(p.args??p.input)});break;case "reasoning-start":case "reasoning-delta":case "reasoning-end":f(p.providerMetadata)&&Object.keys(x(p.providerMetadata)).length>0&&
|
|
50
|
+
(a=false);break;case "finish":s=p;break;case "step-start":case "response-metadata":case "text-start":case "text-end":case "tool-call-input-streaming-start":case "tool-call-delta":case "tool-call-input-streaming-\
|
|
51
|
+
end":case "raw":break;default:a=false;}}let i=f(s?.stepResult)?s.stepResult:{},o=typeof i.reason=="string"?i.reason:void 0,l=Y(o),c=f(s?.output)?s.output:{},d=f(c.usage)?c.usage:void 0,g=X(d?.raw,t);return {
|
|
52
|
+
text:n,...r.length>0?{toolCalls:r}:{},...l?{finishReason:l}:{},usage:s?g:{inputTokens:0,outputTokens:0,complete:false},...a&&o==="stop"?{}:{replayable:false}}}function Ie(e,t,n){let r=`bvsala-${e.requestId}`,
|
|
53
|
+
a=[{type:"step-start",payload:{request:{},warnings:[],...typeof n=="string"?{messageId:n}:{},startedAt:Date.now()}},{type:"response-metadata",payload:{type:"response-metadata",id:r,modelId:e.report.model,
|
|
54
|
+
timestamp:new Date}}];e.text!==""&&(a.push({type:"text-start",payload:{id:r}}),a.push({type:"text-delta",payload:{id:r,text:e.text}}),a.push({type:"text-end",payload:{type:"text-end",id:r}})),(e.toolCalls??
|
|
55
|
+
[]).forEach((i,o)=>{let l={};try{l=JSON.parse(i.arguments||"{}");}catch{l={};}a.push({type:"tool-call",payload:{toolCallId:i.id??`${r}-${o}`,toolName:i.name,args:l}});});let s=(e.toolCalls?.length??0)>0;
|
|
56
|
+
return a.push({type:"finish",payload:{type:"finish",stepResult:{reason:s?"tool-calls":"stop"},output:{usage:{inputTokens:0,outputTokens:0,totalTokens:0}},metadata:t?{providerMetadata:{bivelio:{savingsReport:t}}}:
|
|
57
|
+
{},messages:{all:[],user:[],nonUser:[]}}}),a}var Ee=900*1e3;function Qe(e){let t=G("mastra",e),n=Math.max(1,e.providerTimeoutMs??Ee),r=new Map,a=0,s=(o,l)=>{let c=r.get(o);c&&(r.delete(o),clearTimeout(
|
|
58
|
+
c.plazo),c.signal&&c.alAbortar&&c.signal.removeEventListener("abort",c.alAbortar),c.llamada.errorDelMarco={error:l},c.rechazar(l));};return {id:"bivelio-savings",name:"BiVelio savings",processInputStep(o){
|
|
59
|
+
let l=o.state;l[ie]=Me(o),typeof o.messageId=="string"&&(l["bivelio.messageId"]=o.messageId);},async processLLMRequest(o){let l=o.state,c=f(o.model)?o.model:{},d=typeof o.stepNumber=="number"?o.stepNumber:
|
|
60
|
+
-1,g=l[ie],u=g&&g.paso===d?g:void 0,p=e.modelId?e.modelId({provider:String(c.provider??""),modelId:String(c.modelId??"")}):ee(c),M=(u?.herramientas??[]).map(m=>re(e,{nombre:m.nombre,descripcion:m.descripcion,
|
|
61
|
+
parametros:m.parametros,delProveedor:m.delProveedor})),b=f(u?.modelSettings)?u.modelSettings:{},O=se(f(u?.providerOptions)?u.providerOptions.bivelio:void 0),A=u?.toolChoice,ue=A==="required"||f(A)&&(A.
|
|
62
|
+
type==="tool"||A.type==="required"),R=await oe(e,{model:p,messages:K(o.prompt),tools:M,temperature:typeof b.temperature=="number"?b.temperature:void 0,seed:typeof b.seed=="number"?b.seed:void 0,context:ae(
|
|
63
|
+
e.context?.({requestContext:o.requestContext}),O.context),savings:{...O.savings,singleflight:false},proyeccion:{modelo:p,prompt:Z(o.prompt),herramientas:u?.herramientas??null,toolChoice:u?.toolChoice,activeTools:u?.
|
|
64
|
+
activeTools,providerOptions:x(u?.providerOptions),ajustes:Le(u?.modelSettings),salidaEstructurada:u?.salidaEstructurada},restricciones:{sinResolvers:u===void 0||ue||u.salidaEstructurada!==void 0,sinReutilizar:u===
|
|
65
|
+
void 0||u.esquemaIlegible}}),I,E,ce=new Promise((m,L)=>{I=m,E=L;}),q,de=new Promise(m=>{q=()=>m("invocada");}),j=F({model:R.model,messages:R.messages,...R.tools?{tools:R.tools}:{}},()=>(q(),ce)),D=t.ejecutar(
|
|
66
|
+
R,j);if(D.catch(()=>{}),await Promise.race([de,D.then(()=>"resuelta")])==="resuelta"){let m=await D,L=t.informe(m.report);return {response:{chunks:Ie(m,L,l["bivelio.messageId"])}}}let P=`bvsala-${++a}-${Date.
|
|
67
|
+
now().toString(36)}`,z=setTimeout(()=>s(P,new Error("[bvsala] Mastra never reported this model call back; nothing was recorded.")),n);z.unref?.();let w={resolver:I,rechazar:E,llamada:j,resultado:D,plazo:z},
|
|
68
|
+
C=o.abortSignal instanceof AbortSignal?o.abortSignal:void 0;C&&(w.signal=C,w.alAbortar=()=>s(P,new Error("[bvsala] the model call was aborted; nothing was recorded.")),C.aborted?w.alAbortar():C.addEventListener(
|
|
69
|
+
"abort",w.alAbortar,{once:true})),r.set(P,w),l[k]=P;},async processLLMResponse(o){if(o.fromCache===true)return;let l=o.state,c=l[k];if(delete l[k],typeof c!="string")return;let d=r.get(c);if(!d)return;r.delete(
|
|
70
|
+
c),clearTimeout(d.plazo),d.signal&&d.alAbortar&&d.signal.removeEventListener("abort",d.alAbortar);let g=f(o.model)?o.model:{},u=Oe(Array.isArray(o.chunks)?o.chunks:[],te(g));if("error"in u){d.llamada.
|
|
71
|
+
errorDelMarco={error:u.error},d.rechazar(u.error);return}d.llamada.completada=true,d.resolver(u);try{let p=await d.resultado,M=t.informe(p.report);e.emitReportPart===!0&&await o.writer?.custom?.({type:"\
|
|
72
|
+
data-bivelio-savings-report",data:M});}catch{t.avisar("sin-informe","[bvsala] the model answered, but the savings layer failed while accounting for it; the answer is unchanged, without a savings report\
|
|
73
|
+
and without a usage record.");}},processAPIError(o){let l=o.state,c=l[k];typeof c=="string"&&(delete l[k],s(c,o.error??new Error("[bvsala] the model call failed")));},close(){for(let o of [...r.keys()])
|
|
74
|
+
s(o,new Error("[bvsala] the savings layer was closed; nothing was recorded."));t.close();}}}export{Qe as savingsProcessor};
|