@bivelio/savings-layer 0.4.10 → 0.4.12

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import {spawn}from'child_process';import {existsSync,readFileSync,mkdirSync,writeFileSync}from'fs';import {homedir}from'os';import {join,dirname,delimiter}from'path';import {fileURLToPath}from'url';import {createServer}from'http';import {randomUUID,createHash}from'crypto';import*as R from'zlib';var Ce=new Set;function T(e,t){Ce.has(e)||(Ce.add(e),console.warn(t));}var O=class{options;now;flushIntervalMs;maxBatch;maxBuffer;buffer=[];seatId;ci;timer;inflight=null;fallosSeguidos=0;constructor(t){this.options=t,this.now=t.now??(()=>Date.now()),this.flushIntervalMs=
2
+ import {spawn}from'child_process';import {existsSync,readFileSync,mkdirSync,writeFileSync}from'fs';import {homedir}from'os';import {join,dirname,delimiter}from'path';import {fileURLToPath}from'url';import {createServer}from'http';import {randomUUID,createHash}from'crypto';import*as I from'zlib';var $e=new Set;function E(e,t){$e.has(e)||($e.add(e),console.warn(t));}var z=class{options;now;flushIntervalMs;maxBatch;maxBuffer;buffer=[];seatId;ci;timer;inflight=null;fallosSeguidos=0;constructor(t){this.options=t,this.now=t.now??(()=>Date.now()),this.flushIntervalMs=
3
3
  t.flushIntervalMs??15e3,this.maxBatch=t.maxBatch??50,this.maxBuffer=t.maxBuffer??1e3,this.ci=t.ci??false;}setSeat(t,n){t&&(this.seatId=t),this.ci=n;}record(t){this.buffer.push({report:t,at:this.now()}),this.
4
4
  buffer.length>this.maxBuffer&&this.buffer.splice(0,this.buffer.length-this.maxBuffer),this.buffer.length>=this.maxBatch&&this.flush();}start(){this.timer||(this.timer=setInterval(()=>{this.flush();},this.
5
5
  flushIntervalMs),this.timer.unref?.());}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0),this.flush();}async stopAndDrain(t){this.timer&&(clearInterval(this.timer),this.timer=void 0);let n=t??
@@ -7,7 +7,7 @@ Math.ceil(this.maxBuffer/this.maxBatch)+4,r=0;for(let o=0;o<n&&this.buffer.lengt
7
7
  inflight)return this.inflight;if(this.buffer.length!==0){this.inflight=this.hacerFlush();try{await this.inflight;}finally{this.inflight=null;}}}async hacerFlush(){let t=this.options.fetchImpl??globalThis.
8
8
  fetch;if(!t)return;let n=this.buffer.splice(0,this.maxBatch);try{let r=n.map(s=>this.toWire(s)),o=await t(this.options.url,{method:"POST",headers:{"content-type":"application/json",authorization:`Bear\
9
9
  er ${this.options.serviceAccountKey}`},body:JSON.stringify(r)});o.ok?this.fallosSeguidos=0:o.status>=500?(this.fallosSeguidos++,this.requeue(n),this.avisarDeFallo(`el servidor respondi\xF3 ${o.status}`)):
10
- o.status===401||o.status===403?(T(`metering-auth-${o.status}`,`[bv-sala] el env\xEDo de uso est\xE1 siendo rechazado con HTTP ${o.status} en ${this.options.url}. Revisa 'serviceAccountKey' (\xBFrotada? \xBF\
10
+ o.status===401||o.status===403?(E(`metering-auth-${o.status}`,`[bv-sala] el env\xEDo de uso est\xE1 siendo rechazado con HTTP ${o.status} en ${this.options.url}. Revisa 'serviceAccountKey' (\xBFrotada? \xBF\
11
11
  revocada? \xBFde otra organizaci\xF3n?). Mientras no funcione NO se reporta uso: el panel dir\xE1 que no ve tr\xE1fico y los asientos facturables saldr\xE1n a cero.`),this.options.onAuthError?.(o.status)):
12
12
  (this.fallosSeguidos++,this.avisarDeFallo(o.status===404||o.status===405?`HTTP ${o.status}: la URL de env\xEDo parece equivocada`:`el servidor rechaz\xF3 el lote con HTTP ${o.status}`));}catch(r){this.
13
13
  fallosSeguidos++,this.requeue(n),this.avisarDeFallo(r instanceof Error?r.message:"error de red");}}avisarDeFallo(t){if(this.options.silenceWarnings)return;let n=this.fallosSeguidos;n<3||(n-3)%12!==0||console.
@@ -17,16 +17,16 @@ length>this.maxBuffer&&(this.buffer.length=this.maxBuffer);}toWire(t){let n=t.re
17
17
  model:n.model,at:t.at,avoidedLlm:n.calls.avoidedLlm,actualLlm:n.calls.actualLlm,baselineInputTokens:n.tokens.baselineInput,actualInputTokens:n.tokens.actualInput,eliminatedInputTokens:n.tokens.eliminatedInput,
18
18
  compressedInputTokens:n.tokens.compressedInput,baselineOutputTokens:n.tokens.baselineOutput,actualOutputTokens:n.tokens.actualOutput,providerCachedInputTokens:n.tokens.providerCachedInput??0,cacheResult:n.
19
19
  cache.result,baselineCost:n.cost.baselineEstimate,actualCost:n.cost.actual,netSavings:n.cost.netSavings,...n.cost.basis?{basis:n.cost.basis}:{},...n.attribution?.sessionId?{sessionId:n.attribution.sessionId}:
20
- {},...n.attribution?.agentId?{agentId:n.attribution.agentId}:{}}}};function U(){return globalThis.process}function rt(e){if(/^[0-9a-f]{12}$/.test(e)||/^\d{1,3}(\.\d{1,3}){3}$/.test(e)||/^ip-\d{1,3}(-\d{1,3}){3}$/i.test(e))return true;let t="[bcdfghjklmnpqrstvwxz2456789]";
21
- return new RegExp(`-${t}{8,10}-${t}{5}$`).test(e)}function st(e){return !!(e.AWS_LAMBDA_FUNCTION_NAME??e.LAMBDA_TASK_ROOT??e.VERCEL??e.VERCEL_ENV??e.K_SERVICE??e.FUNCTION_TARGET??e.FUNCTIONS_WORKER_RUNTIME??
22
- e.NETLIFY)}async function it(){if(U()?.execPath)try{let t=await import(["node","os"].join(":")),n=typeof t.hostname=="function"?t.hostname():"";return n.length>0?n:void 0}catch{return}}async function at(e,t=it){
23
- if(e.KUBERNETES_SERVICE_HOST||st(e))return;let n=e.HOSTNAME??e.COMPUTERNAME??await t();if(!(!n||rt(n)))return n}async function ct(){let e=U();if(!e||!e.env)return;let t=e.env,n=await at(t),r=[e.platform,
24
- e.arch,e.execPath,n,t.USER??t.USERNAME??t.LOGNAME,t.HOME??t.USERPROFILE].filter(o=>typeof o=="string"&&o.length>0);return r.length?r.join("|"):void 0}var lt=["CI","CONTINUOUS_INTEGRATION","GITHUB_ACTI\
25
- ONS","GITLAB_CI","CIRCLECI","TRAVIS","JENKINS_URL","BUILDKITE","TF_BUILD","TEAMCITY_VERSION","BITBUCKET_BUILD_NUMBER","CODEBUILD_BUILD_ID","HEROKU_TEST_RUN_ID","DRONE"];function q(){let e=U()?.env;if(!e)
26
- return false;for(let t of lt){let n=e[t];if(n&&n!=="false"&&n!=="0")return true}return false}async function ut(e,t){let n=globalThis.crypto,r=new TextEncoder;if(n?.subtle)try{let i=await n.subtle.importKey("raw",
27
- r.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),a=await n.subtle.sign("HMAC",i,r.encode(t));return [...new Uint8Array(a)].map(l=>l.toString(16).padStart(2,"0")).join("")}catch{}let o=2166136261,s=`${e}\
28
- |${t}`;for(let i=0;i<s.length;i++)o^=s.charCodeAt(i),o=Math.imul(o,16777619);return (o>>>0).toString(16).padStart(8,"0")}async function K(e){let n=U()?.env?.BVSALA_SEAT_ID;if(n&&dt.test(n))return n;let r=await ct();
29
- if(!r)return;let o=await ut(e,r);if(o)return `m-${o.slice(0,32)}`}var dt=/^[A-Za-z0-9._:/-]{1,128}$/;var ne={"gpt-4.1":{inputPer1k:.002,outputPer1k:.008,cachedInputPer1k:5e-4},"gpt-4.1-mini":{inputPer1k:4e-4,outputPer1k:.0016,cachedInputPer1k:1e-4},"gpt-4.1-nano":{inputPer1k:1e-4,outputPer1k:4e-4,cachedInputPer1k:25e-6},
20
+ {},...n.attribution?.agentId?{agentId:n.attribution.agentId}:{}}}};function X(){return globalThis.process}function Rt(e){if(/^[0-9a-f]{12}$/.test(e)||/^\d{1,3}(\.\d{1,3}){3}$/.test(e)||/^ip-\d{1,3}(-\d{1,3}){3}$/i.test(e))return true;let t="[bcdfghjklmnpqrstvwxz2456789]";
21
+ return new RegExp(`-${t}{8,10}-${t}{5}$`).test(e)}function _t(e){return !!(e.AWS_LAMBDA_FUNCTION_NAME??e.LAMBDA_TASK_ROOT??e.VERCEL??e.VERCEL_ENV??e.K_SERVICE??e.FUNCTION_TARGET??e.FUNCTIONS_WORKER_RUNTIME??
22
+ e.NETLIFY)}async function It(){if(X()?.execPath)try{let t=await import(["node","os"].join(":")),n=typeof t.hostname=="function"?t.hostname():"";return n.length>0?n:void 0}catch{return}}async function At(e,t=It){
23
+ if(e.KUBERNETES_SERVICE_HOST||_t(e))return;let n=e.HOSTNAME??e.COMPUTERNAME??await t();if(!(!n||Rt(n)))return n}async function Pt(){let e=X();if(!e||!e.env)return;let t=e.env,n=await At(t),r=[e.platform,
24
+ e.arch,e.execPath,n,t.USER??t.USERNAME??t.LOGNAME,t.HOME??t.USERPROFILE].filter(o=>typeof o=="string"&&o.length>0);return r.length?r.join("|"):void 0}var Ot=["CI","CONTINUOUS_INTEGRATION","GITHUB_ACTI\
25
+ ONS","GITLAB_CI","CIRCLECI","TRAVIS","JENKINS_URL","BUILDKITE","TF_BUILD","TEAMCITY_VERSION","BITBUCKET_BUILD_NUMBER","CODEBUILD_BUILD_ID","HEROKU_TEST_RUN_ID","DRONE"];function Z(){let e=X()?.env;if(!e)
26
+ return false;for(let t of Ot){let n=e[t];if(n&&n!=="false"&&n!=="0")return true}return false}async function Dt(e,t){let n=globalThis.crypto,r=new TextEncoder;if(n?.subtle)try{let i=await n.subtle.importKey("raw",
27
+ r.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),c=await n.subtle.sign("HMAC",i,r.encode(t));return [...new Uint8Array(c)].map(u=>u.toString(16).padStart(2,"0")).join("")}catch{}let o=2166136261,s=`${e}\
28
+ |${t}`;for(let i=0;i<s.length;i++)o^=s.charCodeAt(i),o=Math.imul(o,16777619);return (o>>>0).toString(16).padStart(8,"0")}async function ee(e){let n=X()?.env?.BVSALA_SEAT_ID;if(n&&Lt.test(n))return n;let r=await Pt();
29
+ if(!r)return;let o=await Dt(e,r);if(o)return `m-${o.slice(0,32)}`}var Lt=/^[A-Za-z0-9._:/-]{1,128}$/;var pe={"gpt-4.1":{inputPer1k:.002,outputPer1k:.008,cachedInputPer1k:5e-4},"gpt-4.1-mini":{inputPer1k:4e-4,outputPer1k:.0016,cachedInputPer1k:1e-4},"gpt-4.1-nano":{inputPer1k:1e-4,outputPer1k:4e-4,cachedInputPer1k:25e-6},
30
30
  "gpt-4o":{inputPer1k:.0025,outputPer1k:.01,cachedInputPer1k:.00125},"gpt-4o-mini":{inputPer1k:15e-5,outputPer1k:6e-4,cachedInputPer1k:75e-6},"gpt-4-turbo":{inputPer1k:.01,outputPer1k:.03},"gpt-4":{inputPer1k:.03,
31
31
  outputPer1k:.06},"gpt-3.5-turbo":{inputPer1k:5e-4,outputPer1k:.0015},"gpt-5":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},"gpt-5-codex":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},
32
32
  "gpt-5-mini":{inputPer1k:25e-5,outputPer1k:.002,cachedInputPer1k:25e-6},"gpt-5-nano":{inputPer1k:5e-5,outputPer1k:4e-4,cachedInputPer1k:5e-6},"gpt-5.1-codex":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},
@@ -42,74 +42,119 @@ able-5":{inputPer1k:.01,outputPer1k:.05,cachedInputPer1k:.001},"claude-sonnet-4"
42
42
  "claude-3-5-sonnet":{inputPer1k:.003,outputPer1k:.015,cachedInputPer1k:3e-4},"claude-3-5-haiku":{inputPer1k:8e-4,outputPer1k:.004,cachedInputPer1k:8e-5},"claude-3-opus":{inputPer1k:.015,outputPer1k:.075,
43
43
  cachedInputPer1k:.0015},"claude-3-haiku":{inputPer1k:25e-5,outputPer1k:.00125,cachedInputPer1k:3e-5},"gemini-3.7-flash":{inputPer1k:75e-5,outputPer1k:.00375,cachedInputPer1k:75e-6},"gemini-3.5-flash":{
44
44
  inputPer1k:.0015,outputPer1k:.009,cachedInputPer1k:15e-5},"gemini-3.5-flash-lite":{inputPer1k:3e-4,outputPer1k:.0025,cachedInputPer1k:3e-5},"gemini-3.1-pro-preview":{inputPer1k:.002,outputPer1k:.012,cachedInputPer1k:2e-4},
45
- "gemini-2.5-pro":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},"gemini-2.5-flash":{inputPer1k:3e-4,outputPer1k:.0025,cachedInputPer1k:3e-5}};function Re(e,t,n){if(!n)return;let r=e[n];if(r)
46
- return r;let o=n.lastIndexOf("/"),s=o>=0?n.slice(o+1):n,i=e[s];if(i)return i;for(let a of t){if(!s.startsWith(a))continue;let l=s.charAt(a.length);if(l!==""&&l!=="-"&&l!=="."&&l!=="_")continue;let p=s.
47
- slice(a.length+1);if(!(/^\d/.test(p)&&!/^\d{4}/.test(p)))return e[a]}}function oe(e){return Object.keys(e).sort((t,n)=>n.length-t.length)}var pt=oe(ne);function j(e){return Re(ne,pt,e)}var N=class{resto="";uso=null;eventos={};observar(t){this.resto+=typeof t=="string"?t:t.toString("utf8");let n;for(;(n=this.resto.indexOf(`
45
+ "gemini-2.5-pro":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},"gemini-2.5-flash":{inputPer1k:3e-4,outputPer1k:.0025,cachedInputPer1k:3e-5}};function Ne(e,t,n){if(!n)return;let r=e[n];if(r)
46
+ return r;let o=n.lastIndexOf("/"),s=o>=0?n.slice(o+1):n,i=e[s];if(i)return i;for(let c of t){if(!s.startsWith(c))continue;let u=s.charAt(c.length);if(u!==""&&u!=="-"&&u!=="."&&u!=="_")continue;let p=s.
47
+ slice(c.length+1);if(!(/^\d/.test(p)&&!/^\d{4}/.test(p)))return e[c]}}function me(e){return Object.keys(e).sort((t,n)=>n.length-t.length)}var Mt=me(pe);function M(e){return Ne(pe,Mt,e)}var $=class{resto="";uso=null;elisionObservada=null;eventos={};observar(t){this.resto+=typeof t=="string"?t:t.toString("utf8");let n;for(;(n=this.resto.indexOf(`
48
48
 
49
49
  `))>=0;){let r=this.resto.slice(0,n);this.resto=this.resto.slice(n+2);let o=/^event: (.+)$/m.exec(r)?.[1];if(o&&(this.eventos[o]=(this.eventos[o]??0)+1),o!=="message_start"&&o!=="message_delta")continue;
50
- let s=/^data: (.+)$/m.exec(r)?.[1];if(s)try{let i=JSON.parse(s),a=i.usage??i.message?.usage;if(a){let l=a.cache_creation||this.uso?.cache_creation?{...this.uso?.cache_creation,...a.cache_creation}:void 0;
51
- this.uso={...this.uso,...a,...l?{cache_creation:l}:{}};}}catch{}}}usage(){return this.uso}usageFinal(){return (this.eventos.message_delta??0)>0?this.uso:null}},H=class{resto="";uso=null;eventos={};observar(t){
52
- this.resto+=typeof t=="string"?t:t.toString("utf8");let n;for(;(n=this.resto.indexOf(`
50
+ let s=/^data: (.+)$/m.exec(r)?.[1];if(s)try{let i=JSON.parse(s),c=ze(i.context_management);c&&(this.elisionObservada=c);let u=i.usage??i.message?.usage;if(u){let p=u.cache_creation||this.uso?.cache_creation?
51
+ {...this.uso?.cache_creation,...u.cache_creation}:void 0;this.uso={...this.uso,...u,...p?{cache_creation:p}:{}};}}catch{}}}usage(){return this.uso}usageFinal(){return (this.eventos.message_delta??0)>0?this.
52
+ uso:null}elision(){return this.elisionObservada}};function ze(e){if(e===null||typeof e!="object")return null;let t=e.applied_edits;if(!Array.isArray(t)||t.length===0)return null;let n=0;for(let r of t){
53
+ let o=r.cleared_input_tokens;typeof o=="number"&&Number.isFinite(o)&&o>0&&(n+=o);}return {borrados:t.length,tokensLimpiados:n}}function Be(e){try{let t=JSON.parse(typeof e=="string"?e:e.toString("utf8"));
54
+ return ze(t.context_management)}catch{return null}}var te=class{resto="";uso=null;eventos={};observar(t){this.resto+=typeof t=="string"?t:t.toString("utf8");let n;for(;(n=this.resto.indexOf(`
53
55
 
54
56
  `))>=0;){let r=this.resto.slice(0,n);this.resto=this.resto.slice(n+2);let o=/^event: (.+)$/m.exec(r)?.[1];o&&(this.eventos[o]=(this.eventos[o]??0)+1);let s=/^data: (.+)$/m.exec(r)?.[1];if(s)try{let i=JSON.
55
- parse(s);if((o??i.type)!=="response.completed")continue;let a=i.response?.usage;a&&(this.uso=mt(a));}catch{}}}usage(){return this.uso}usageFinal(){return this.uso}};function mt(e){let t=Math.max(0,e.input_tokens??
57
+ parse(s);if((o??i.type)!=="response.completed")continue;let c=i.response?.usage;c&&(this.uso=$t(c));}catch{}}}usage(){return this.uso}usageFinal(){return this.uso}};function $t(e){let t=Math.max(0,e.input_tokens??
56
58
  0),n=Math.min(Math.max(0,e.input_tokens_details?.cached_tokens??0),t),r=Math.min(Math.max(0,e.input_tokens_details?.cache_write_tokens??0),t-n);return {input_tokens:t-n-r,output_tokens:Math.max(0,e.output_tokens??
57
- 0),cache_read_input_tokens:n,cache_creation_input_tokens:r}}var Ee=1.25,ft=2;function Ie(e,t){let n=j(e);if(!n)return null;let r=t.input_tokens??0,o=t.output_tokens??0,s=t.cache_read_input_tokens??0,i=t.
58
- cache_creation,a=t.cache_creation_input_tokens??(i?.ephemeral_5m_input_tokens??0)+(i?.ephemeral_1h_input_tokens??0),l=Math.min(i?.ephemeral_1h_input_tokens??0,a),p=n.cachedInputPer1k??n.inputPer1k;return {
59
- costeUsd:r/1e3*n.inputPer1k+s/1e3*p+(a-l)/1e3*n.inputPer1k*gt(e)+l/1e3*n.inputPer1k*ft+o/1e3*n.outputPer1k,precio:n,tokens:{entrada:r,salida:o,cacheLeida:s,cacheEscrita:a,cacheEscrita1h:l}}}function Pe(e,t){
60
- try{let n=e,r={maxOutputLength:ht};switch((t??"").trim().toLowerCase()){case "gzip":case "x-gzip":n=R.gunzipSync(e,r);break;case "deflate":n=R.inflateSync(e,r);break;case "br":n=R.brotliDecompressSync(e,r);
61
- break;case "zstd":{let s=R.zstdDecompressSync;if(typeof s!="function")return "";n=s(e,r);break}default:break}let o=JSON.parse(n.toString("utf8")).model;return typeof o=="string"?o:""}catch{return ""}}var ht=5*
62
- 1024*1024;function Ae(){return typeof R.zstdDecompressSync=="function"}function gt(e){let t=e.toLowerCase();return t.startsWith("gpt-")||t.startsWith("o1")||t.startsWith("o3")||t.startsWith("o4")?/^gpt-5\.6/.
63
- test(t)?Ee:1:t.startsWith("gemini")?1:Ee}function re(e){try{return JSON.parse(typeof e=="string"?e:e.toString("utf8")).usage??null}catch{return null}}function _e(e,t,n,r){return De(e,t,n,false,r)}function Oe(e,t,n,r){
64
- return De(e,t,n,true,r)}function De(e,t,n,r,o){let s=n.tokens.entrada+n.tokens.cacheLeida+n.tokens.cacheEscrita;return {requestId:e,model:t,...o&&(o.sessionId||o.agentId)?{attribution:o}:{},calls:r?{avoidedLlm:1,
65
- actualLlm:0}:{avoidedLlm:0,actualLlm:1},tokens:{baselineInput:s,actualInput:r?0:s,eliminatedInput:0,compressedInput:0,baselineOutput:n.tokens.salida,actualOutput:r?0:n.tokens.salida,providerCachedInput:r?
66
- 0:n.tokens.cacheLeida},cache:{result:r?"singleflight":"miss"},cost:r?{baselineEstimate:n.costeUsd,actual:0,netSavings:1,basis:"estimated"}:{baselineEstimate:n.costeUsd,actual:n.costeUsd,netSavings:0,basis:"\
67
- measured"}}}var se=5*1024*1024,vt=["authorization","x-api-key","anthropic-version","anthropic-beta"];function Le(e,t,n,r=""){return createHash("sha256").update(e).update(`
59
+ 0),cache_read_input_tokens:n,cache_creation_input_tokens:r}}var je=1.25,fe=2;function Ue(e,t){let n=M(e);if(!n)return null;let r=t.input_tokens??0,o=t.output_tokens??0,s=t.cache_read_input_tokens??0,i=t.
60
+ cache_creation,c=t.cache_creation_input_tokens??(i?.ephemeral_5m_input_tokens??0)+(i?.ephemeral_1h_input_tokens??0),u=Math.min(i?.ephemeral_1h_input_tokens??0,c),p=n.cachedInputPer1k??n.inputPer1k;return {
61
+ costeUsd:r/1e3*n.inputPer1k+s/1e3*p+(c-u)/1e3*n.inputPer1k*ge(e)+u/1e3*n.inputPer1k*fe+o/1e3*n.outputPer1k,precio:n,tokens:{entrada:r,salida:o,cacheLeida:s,cacheEscrita:c,cacheEscrita1h:u}}}function Ve(e,t){
62
+ let r=he(e,t)?.model;return typeof r=="string"?r:""}function he(e,t){try{let n=e,r={maxOutputLength:Nt};switch((t??"").trim().toLowerCase()){case "gzip":case "x-gzip":n=I.gunzipSync(e,r);break;case "defl\
63
+ ate":n=I.inflateSync(e,r);break;case "br":n=I.brotliDecompressSync(e,r);break;case "zstd":{let o=I.zstdDecompressSync;if(typeof o!="function")return null;n=o(e,r);break}default:break}return JSON.parse(n.
64
+ toString("utf8"))}catch{return null}}var Nt=5*1024*1024;function Fe(){return typeof I.zstdDecompressSync=="function"}function ge(e){let t=e.toLowerCase();return t.startsWith("gpt-")||t.startsWith("o1")||
65
+ t.startsWith("o3")||t.startsWith("o4")?/^gpt-5\.6/.test(t)?je:1:t.startsWith("gemini")?1:je}function be(e){try{return JSON.parse(typeof e=="string"?e:e.toString("utf8")).usage??null}catch{return null}}
66
+ function qe(e,t,n,r){return Je(e,t,n,false,r)}function Ke(e,t,n,r){return Je(e,t,n,true,r)}function He(e,t,n,r,o){return {requestId:e,model:t,...o&&(o.sessionId||o.agentId)?{attribution:o}:{},calls:{avoidedLlm:0,
67
+ actualLlm:0},tokens:{baselineInput:0,actualInput:0,eliminatedInput:0,compressedInput:0,baselineOutput:0,actualOutput:0,providerCachedInput:0},cache:{result:"miss"},cost:{baselineEstimate:n,actual:r,netSavings:n>
68
+ 0?Math.max(-100,Math.min(1,(n-r)/n)):0,basis:"shadow"}}}function Je(e,t,n,r,o){let s=n.tokens.entrada+n.tokens.cacheLeida+n.tokens.cacheEscrita;return {requestId:e,model:t,...o&&(o.sessionId||o.agentId)?
69
+ {attribution:o}:{},calls:r?{avoidedLlm:1,actualLlm:0}:{avoidedLlm:0,actualLlm:1},tokens:{baselineInput:s,actualInput:r?0:s,eliminatedInput:0,compressedInput:0,baselineOutput:n.tokens.salida,actualOutput:r?
70
+ 0:n.tokens.salida,providerCachedInput:r?0:n.tokens.cacheLeida},cache:{result:r?"singleflight":"miss"},cost:r?{baselineEstimate:n.costeUsd,actual:0,netSavings:1,basis:"estimated"}:{baselineEstimate:n.costeUsd,
71
+ actual:n.costeUsd,netSavings:0,basis:"measured"}}}var zt=1024,q=120,Bt=8,Ut=256*1024,Vt=/error|exception|traceback|warn|fatal|fail|panic|assert|denied|refused|timeout|\bat\s+\S+:\d+/i,Ge=/^\s*(export\s|import\s|function\s|class\s|interface\s|type\s|enum\s|def\s|fn\s|func\s|impl\s|struct\s|trait\s|package\s|module\s|@\w)/;
72
+ function Ft(e){return Buffer.byteLength(typeof e=="string"?e:JSON.stringify(e??""))}function qt(e){return typeof e=="string"?e:Array.isArray(e)?e.map(t=>t&&typeof t=="object"&&typeof t.text=="string"?
73
+ t.text:"").join(`
74
+ `):""}var Kt=/^\s*\d+[\t→]/;function Ye(e){return e.replace(Kt,"")}function Ht(e){if(!e)return "otro";let t=e.split(`
75
+ `),n=Math.max(1,t.length),r=0,o=0,s=0;for(let i of t){let c=Ye(i);(/^[+-](?![+-])/.test(c)||c.startsWith("@@")||c.startsWith("diff --git"))&&(r+=1),Ge.test(c)&&(o+=1),(/^\s*(\d{4}-\d{2}-\d{2}|\[\d|\d{2}:\d{2}:\d{2})/.
76
+ test(c)||/\b(INFO|DEBUG|TRACE|WARN|ERROR)\b/.test(c))&&(s+=1);}return r/n>.25?"diff":s/n>.3?"log":o/n>.08?"codigo":"otro"}function Jt(e,t){if(t==="diff"||t==="otro")return Buffer.byteLength(e);let n=e.
77
+ split(`
78
+ `),r=new Set;for(let s=0;s<n.length;s++){let i=Ye(n[s]);(t==="log"?Vt.test(i):Ge.test(i))&&(r.add(s),t==="log"&&(s>0&&r.add(s-1),s<n.length-1&&r.add(s+1)));}let o=q;for(let s of r)o+=Buffer.byteLength(
79
+ n[s])+1;return Math.min(o,Buffer.byteLength(e))}function Qe(e){let t=[],n=(r,o)=>{let s=Ft(o),i={clave:createHash("sha256").update(typeof o=="string"?o:JSON.stringify(o??"")).digest("hex").slice(0,16),tipo:r,
80
+ bytes:s,bytesV1:s,clase:"otro",esError:false};if(r.endsWith(":tool_result")&&o&&typeof o=="object"){let c=o;i.esError=c.is_error===true;let u=qt(c.content);i.clase=Ht(u);let p=s-Buffer.byteLength(u);i.bytesV1=
81
+ Math.min(s,Math.max(0,p)+Jt(u,i.clase));}t.push(i);};if((e.system??void 0)!==void 0&&n("system",e.system),Array.isArray(e.tools))for(let r of e.tools)n("tools",r);for(let r of Array.isArray(e.messages)?
82
+ e.messages:[]){if(!r||typeof r!="object"){n("?:invalido",r);continue}let o=r,s=typeof o.role=="string"?o.role:"?";if(typeof o.content=="string")n(`${s}:text`,o.content);else if(Array.isArray(o.content))
83
+ for(let i of o.content)n(`${s}:${i?.type??"?"}`,i);}return t}function Wt(){return {nacimiento:new Map,turno:0,elididosV2m:new Set}}function Gt(e,t){let n=e.turno++;for(let r of t)e.nacimiento.has(r.clave)||
84
+ e.nacimiento.set(r.clave,n);return n}function Xe(e,t,n,r,o=Ut){let s=t.reduce((l,a,d)=>a.tipo.endsWith(":tool_result")?d:l,-1),i=(l,a)=>l.tipo.endsWith(":tool_result")&&l.bytes>=zt&&a!==s;return t.map((l,a)=>{if(!i(l,a))return {clave:l.clave,bytes:l.bytes};let d=r-(n.nacimiento.get(l.clave)??r);return d>=2&&d*l.bytes/1024>=Bt?{clave:`${l.clave}:e`,bytes:q}:{clave:l.clave,bytes:l.bytes}});
85
+ }function Yt(e){let t=M(e);return t?{lecturaPer1k:t.cachedInputPer1k??t.inputPer1k,escrituraPer1k:t.
86
+ inputPer1k*ge(e),escritura1hPer1k:t.inputPer1k*fe}:null}function We(){return {lecturaUsd:0,escrituraUsd:0,totalUsd:0,tokensLeidos:0,tokensEscritos:0,tokensInvalidados:0,invalidacionUsd:0}}var Qt={"1h":36e5,
87
+ "5m":3e5},K=class{constructor(t){this.transformar=t;}transformar;estado=Wt();previo=[];hayPrevio=false;atPrevio=0;acumulado=We();paso(t){let n=We(),r=Gt(this.estado,t.bloques),o=Yt(t.model),s=this.transformar(
88
+ t.bloques,this.estado,r);if(!o||t.entradaReal<=0)return this.previo=s,this.hayPrevio=true,this.atPrevio=t.at,n;let i=t.bloques.reduce((h,b)=>h+b.bytes,0),c=i>0?t.entradaReal/i:0,u=Qt[t.escritura1h?"1h":
89
+ "5m"],p=this.hayPrevio&&t.at-this.atPrevio>u,m=0;if(!p)for(;m<s.length&&m<this.previo.length&&s[m].clave===this.previo[m].clave&&s[m].bytes===this.previo[m].bytes;)m+=1;let l=this.previo.slice(m),a=0,
90
+ d=t.escritura1h?o.escritura1hPer1k:o.escrituraPer1k;for(let h=0;h<s.length;h++){let b=s[h],v=b.bytes*c;if(h<m){n.tokensLeidos+=v,n.lecturaUsd+=v/1e3*o.lecturaPer1k;continue}if(n.tokensEscritos+=v,n.escrituraUsd+=
91
+ v/1e3*d,!p){let f=a;for(;f<l.length&&l[f].clave!==b.clave;)f+=1;f<l.length&&(l[f].bytes===b.bytes&&(n.tokensInvalidados+=v,n.invalidacionUsd+=v/1e3*(d-o.lecturaPer1k)),a=f+1);}}return this.previo=s,this.
92
+ hayPrevio=true,this.atPrevio=t.at,n.totalUsd=n.lecturaUsd+n.escrituraUsd,this.acumulado.lecturaUsd+=n.lecturaUsd,this.acumulado.escrituraUsd+=n.escrituraUsd,this.acumulado.totalUsd+=n.totalUsd,this.acumulado.
93
+ tokensLeidos+=n.tokensLeidos,this.acumulado.tokensEscritos+=n.tokensEscritos,this.acumulado.tokensInvalidados+=n.tokensInvalidados,this.acumulado.invalidacionUsd+=n.invalidacionUsd,n}};function Ze(e){return e.map(t=>({clave:t.clave,bytes:t.bytes}))}var Zt=64,ne=class{cadenas=new Map;observar(t){let n=t.uso.cache_creation_input_tokens??(t.uso.cache_creation?.ephemeral_5m_input_tokens??0)+(t.uso.cache_creation?.ephemeral_1h_input_tokens??0),r=(t.uso.
94
+ input_tokens??0)+(t.uso.cache_read_input_tokens??0)+n;if(r<=0)return null;let o={bloques:Qe(t.cuerpo),at:t.at,model:t.model,entradaReal:r,escritura1h:(t.uso.cache_creation?.ephemeral_1h_input_tokens??
95
+ 0)>0};if(o.bloques.length===0)return null;let s=this.cadenaPara(this.clave(t)),i=s.base.paso(o),c=s.v0.paso(o);return i.totalUsd<=0&&c.totalUsd<=0?null:{baselineUsd:i.totalUsd,politicaUsd:c.totalUsd}}clave(t){
96
+ if(t.sessionId)return `s:${t.sessionId}\xB7a:${t.agentId??""}\xB7${t.model}`;let n=Array.isArray(t.cuerpo.messages)?t.cuerpo.messages[0]:void 0;return `m:${createHash("sha256").update(JSON.stringify(n??null)).digest(
97
+ "hex").slice(0,16)}\xB7${t.model}`}cadenaPara(t){let n=this.cadenas.get(t);if(!n&&(n={base:new K(r=>Ze(r)),v0:new K((r,o,s)=>Xe("v0",r,o,s)),ultimoUso:0},this.cadenas.set(t,n),this.cadenas.size>Zt)){let r=null,
98
+ o=1/0;for(let[s,i]of this.cadenas)i.ultimoUso<o&&(o=i.ultimoUso,r=s);r!==null&&this.cadenas.delete(r);}return n.ultimoUso=Date.now(),n}};var oe=class{url;clave;ttlMs;fetchImpl;log;features=new Set;validoHasta=0;enVuelo=null;avisado=false;constructor(t){this.url=t.url,this.clave=t.serviceAccountKey,this.ttlMs=t.ttlMs??3e5,this.fetchImpl=t.
99
+ fetchImpl??fetch,this.log=t.log??(()=>{}),this.refrescar();}tiene(t){return Date.now()>this.validoHasta&&this.enVuelo===null&&this.refrescar(),this.features.has(t)}refrescar(){return this.enVuelo?this.
100
+ enVuelo:(this.enVuelo=this.pedir().finally(()=>{this.enVuelo=null;}),this.enVuelo)}async pedir(){try{let t=await this.fetchImpl(this.url,{method:"GET",headers:{authorization:`Bearer ${this.clave}`},signal:AbortSignal.
101
+ timeout(1e4)});if(!t.ok){this.cerrar(`entitlements HTTP ${t.status}`);return}let n=await t.json();if(!Array.isArray(n.features)||!n.features.every(o=>typeof o=="string")){this.cerrar("entitlements con\
102
+ forma inesperada");return}this.features=new Set(n.features);let r=typeof n.refreshAfterSeconds=="number"&&n.refreshAfterSeconds>0?Math.min(n.refreshAfterSeconds*1e3,this.ttlMs):this.ttlMs;this.validoHasta=
103
+ Date.now()+r,this.avisado=!1;}catch(t){this.cerrar(String(t));}}cerrar(t){this.features=new Set,this.validoHasta=Date.now()+Math.min(6e4,this.ttlMs),this.avisado||(this.avisado=true,this.log(`[gateway] en\
104
+ titlements no disponibles (${t}) \u2014 palanca apagada (fail-closed)`));}};var re="context-management-2025-06-27";function et(){return {edits:[{type:"clear_tool_uses_20250919",trigger:{type:"input_tokens",value:5e4},keep:{type:"tool_uses",value:8},clear_at_least:{type:"input_tokens",value:5e3}}]}}function tt(e,t){if(t!==void 0&&t!==""&&t!=="identity")return null;try{let n=JSON.parse(e.toString("utf8"));return n===null||typeof n!="object"||Array.isArray(n)||typeof n.model!="string"||!Array.isArray(
105
+ n.messages)?null:(n.context_management=et(),Buffer.from(JSON.stringify(n),"utf8"))}catch{return null}}function nt(e){return e===void 0||e.trim()===""?re:e.split(",").map(n=>n.trim()).filter(n=>n.length>
106
+ 0).includes(re)?e:`${e},${re}`}var ve=5*1024*1024,tn=["authorization","x-api-key","anthropic-version","anthropic-beta"];function ot(e,t,n,r=""){return createHash("sha256").update(e).update(`
68
107
  `).update(t).update(`
69
108
  `).update(r).update(`
70
- `).update(n).digest("hex")}function Me(e){return vt.map(t=>`${t}=${e(t)??""}`).join(`
71
- `)}var J=class{enVuelo=new Map;primarias=0;gemelas=0;registrar(t){if(this.enVuelo.has(t))return null;this.primarias+=1;let n,r=new Promise(a=>n=a);this.enVuelo.set(t,{promesa:r,resolver:n});let o=[],s=0,
72
- i=false;return {capturar:a=>{if(!i){if(s+=a.length,s>se){i=true,o.length=0;return}o.push(a);}},terminar:(a,l)=>{let p=!i&&a>=200&&a<300;this.enVuelo.get(t)?.resolver(p?{status:a,headers:l,chunks:o}:null),this.
73
- enVuelo.delete(t);},abortar:()=>{this.enVuelo.get(t)?.resolver(null),this.enVuelo.delete(t);}}}async esperar(t){let n=this.enVuelo.get(t);if(!n)return null;let r=await n.promesa;return r&&(this.gemelas+=
74
- 1),r}tieneEnVuelo(t){return this.enVuelo.has(t)}};var xt=["content-encoding","content-length","transfer-encoding"];async function $e(e={}){let t=(e.upstream??"https://api.anthropic.com").replace(/\/+$/,""),n=e.fetchImpl??fetch,r=e.log??(c=>console.log(
75
- c)),o;if(e.serviceAccountKey){o=new O({url:e.meteringUrl??"https://savings.bivelio.com/api/metering/usage",serviceAccountKey:e.serviceAccountKey,...e.fetchImpl?{fetchImpl:e.fetchImpl}:{},onAuthError:u=>T(
76
- "gateway-ingest-auth",`[bvsala gateway] la ingesta de uso rechaza la credencial (${u}). El tr\xE1fico sigue fluyendo (avisar, nunca romper), pero este uso no est\xE1 llegando al panel. Revisa BIVELIO_SERVIC\
77
- E_KEY y el estado de la suscripci\xF3n en savings.bivelio.com.`)});let c=q();e.seatId?o.setSeat(e.seatId,c):K(e.serviceAccountKey).then(u=>o?.setSeat(u,c)).catch(()=>{}),o.start();}else T("gateway-sin-\
78
- clave","[bvsala gateway] sin BIVELIO_SERVICE_KEY: el gateway reenv\xEDa el tr\xE1fico pero NO mide. Consigue tu clave en savings.bivelio.com/dashboard/install para ver el gasto en tu panel.");let s=e.
79
- coalescer?new J:null,i=c=>c==="/v1/messages"?new N:c.endsWith("/responses")?new H:null,a=(c,u,f,b,m,d,y)=>{if(!o||!f)return;let S=Pe(u,d);if(!S){T(`gateway-sin-modelo:${m}`,`[bvsala gateway] no se pud\
80
- o leer el modelo del cuerpo de ${m} (content-encoding: ${d??"ninguno"}); su uso se reenv\xEDa pero no se mide.`);return}let k=Ie(S,f);k?(o.record(b?Oe(c,S,k,y):_e(c,S,k,y)),r(`[gateway] POST ${m} ${b?
81
- "\xB7 COALESCIDA (llamada evitada)":""} \xB7 ${S} \xB7 $${k.costeUsd.toFixed(6)} (in ${k.tokens.entrada}, cache\u2191${k.tokens.cacheEscrita}${k.tokens.cacheEscrita1h?` (1h ${k.tokens.cacheEscrita1h})`:
82
- ""} cache\u2193${k.tokens.cacheLeida}, out ${k.tokens.salida})`)):T(`gateway-sin-precio:${S}`,`[bvsala gateway] el modelo "${S}" no est\xE1 en el cat\xE1logo de precios; su uso se reenv\xEDa pero no se mide.`);},
83
- l=createServer(async(c,u)=>{let f=randomUUID(),b=new AbortController;u.on("close",()=>{u.writableEnded||b.abort();});let m=null,d=new URL(c.url??"/",t),y=null,S=Buffer.alloc(0),k=false,M=c.headers["content-encoding"],V=Array.
84
- isArray(M)?M[0]:M,ye=C=>{let x=Array.isArray(C)?C[0]:C;return x!==void 0&&/^[A-Za-z0-9._:/-]{1,128}$/.test(x)?x:void 0},Q=ye(c.headers["x-claude-code-session-id"]),X=ye(c.headers["x-claude-code-agent-\
85
- id"]),F=Q!==void 0||X!==void 0?{...Q!==void 0?{sessionId:Q}:{},...X!==void 0?{agentId:X}:{}}:void 0;try{let C=[];for await(let h of c)C.push(h);let x=Buffer.concat(C);S=x,d=new URL(c.url??"/",t);let ke=s!==
86
- null&&c.method==="POST"&&x.length>0,nt=Me(h=>{let v=c.headers[h];return Array.isArray(v)?v.join(", "):v}),Z=ke?Le("POST",d.pathname+d.search,x,nt):"";if(ke)if(s.tieneEnVuelo(Z)){let h=await s.esperar(
87
- Z);if(h){u.writeHead(h.status,h.headers);let v=i(d.pathname)??new N;for(let Te of h.chunks)u.write(Te),v.observar(Te);u.end();let ot=v.usage()??(d.pathname==="/v1/messages"?re(Buffer.concat(h.chunks)):
88
- null);a(f,x,ot,!0,d.pathname,V,F);return}}else m=s.registrar(Z);let xe={};for(let[h,v]of Object.entries(c.headers))h==="host"||h==="content-length"||v===void 0||(xe[h]=Array.isArray(v)?v.join(", "):v);
89
- let w;try{w=await n(d,{method:c.method,headers:xe,body:["GET","HEAD"].includes(c.method??"")?void 0:x,redirect:"manual",signal:b.signal});}catch(h){m?.abortar(),u.headersSent||(u.writeHead(502,{"conten\
90
- t-type":"application/json"}),u.end(JSON.stringify({error:"bvsala gateway: upstream unreachable",detail:String(h)}))),r(`[gateway] ${c.method} ${d.pathname} \u2192 upstream inalcanzable: ${String(h)}`);
91
- return}let ee=Object.fromEntries(w.headers.entries());for(let h of xt)delete ee[h];u.writeHead(w.status,ee);let Se=w.headers.get("content-type")??"",te=Se.includes("text/event-stream")||Se===""&&w.ok&&
92
- i(d.pathname)!==null;y=te?i(d.pathname):null;let $=!te&&w.ok&&o!==void 0&&c.method==="POST"&&d.pathname==="/v1/messages"&&(w.headers.get("content-type")??"").includes("application/json")?[]:null,we=0;
93
- if(w.body)for await(let h of w.body){let v=Buffer.from(h);u.write(v),y?.observar(v),$&&(we+=v.length,we>se?$=null:$.push(v)),m?.capturar(v);}u.end(),m?.terminar(w.status,ee),y&&w.ok?(k=!0,a(f,x,y.usage(),
94
- !1,d.pathname,V,F)):$?a(f,x,re(Buffer.concat($)),!1,d.pathname,V,F):te||r(`[gateway] ${c.method} ${d.pathname} \u2192 ${w.status}`);}catch(C){if(m?.abortar(),b.signal.aborted){let x=!k&&y?y.usageFinal():
95
- null;x?(r(`[gateway] ${c.method} ${d.pathname} \u2192 el cliente cerr\xF3 tras el usage final; se mide igual`),a(f,S,x,false,d.pathname,V,F)):r(`[gateway] ${c.method} ${d.pathname} \u2192 el cliente abort\xF3; u\
96
- pstream cancelado`);}else if(r(`[gateway] ${c.method} ${d.pathname} \u2192 error sirviendo: ${String(C)}`),!u.headersSent){u.writeHead(502,{"content-type":"application/json"}),u.end(JSON.stringify({error:"\
97
- bvsala gateway: stream interrupted",detail:String(C)}));return}u.writableEnded||u.end();}});return l.on("upgrade",(c,u)=>{r(`[gateway] ${c.method} ${new URL(c.url??"/","http://x").pathname} \u2192 426 (WebS\
98
- ocket no soportado; el cliente cae a HTTP)`),u.once("error",()=>{}),u.once("finish",()=>u.destroy()),u.end(`HTTP/1.1 426 Upgrade Required\r
109
+ `).update(n).digest("hex")}function rt(e){return tn.map(t=>`${t}=${e(t)??""}`).join(`
110
+ `)}var se=class{enVuelo=new Map;primarias=0;gemelas=0;registrar(t){if(this.enVuelo.has(t))return null;this.primarias+=1;let n,r=new Promise(c=>n=c);this.enVuelo.set(t,{promesa:r,resolver:n});let o=[],
111
+ s=0,i=false;return {capturar:c=>{if(!i){if(s+=c.length,s>ve){i=true,o.length=0;return}o.push(c);}},terminar:(c,u)=>{let p=!i&&c>=200&&c<300;this.enVuelo.get(t)?.resolver(p?{status:c,headers:u,chunks:o}:null),
112
+ this.enVuelo.delete(t);},abortar:()=>{this.enVuelo.get(t)?.resolver(null),this.enVuelo.delete(t);}}}async esperar(t){let n=this.enVuelo.get(t);if(!n)return null;let r=await n.promesa;return r&&(this.gemelas+=
113
+ 1),r}tieneEnVuelo(t){return this.enVuelo.has(t)}};var rn=["content-encoding","content-length","transfer-encoding"];async function st(e={}){let t=(e.upstream??"https://api.anthropic.com").replace(/\/+$/,""),n=e.fetchImpl??fetch,r=e.log??(a=>console.log(
114
+ a)),o;if(e.serviceAccountKey){o=new z({url:e.meteringUrl??"https://savings.bivelio.com/api/metering/usage",serviceAccountKey:e.serviceAccountKey,...e.fetchImpl?{fetchImpl:e.fetchImpl}:{},onAuthError:d=>E(
115
+ "gateway-ingest-auth",`[bvsala gateway] la ingesta de uso rechaza la credencial (${d}). El tr\xE1fico sigue fluyendo (avisar, nunca romper), pero este uso no est\xE1 llegando al panel. Revisa BIVELIO_SERVIC\
116
+ E_KEY y el estado de la suscripci\xF3n en savings.bivelio.com.`)});let a=Z();e.seatId?o.setSeat(e.seatId,a):ee(e.serviceAccountKey).then(d=>o?.setSeat(d,a)).catch(()=>{}),o.start();}else E("gateway-sin\
117
+ -clave","[bvsala gateway] sin BIVELIO_SERVICE_KEY: el gateway reenv\xEDa el tr\xE1fico pero NO mide. Consigue tu clave en savings.bivelio.com/dashboard/install para ver el gasto en tu panel.");let s=e.
118
+ coalescer?new se:null,i=e.sombra&&o?new ne:null,c=e.elision&&e.serviceAccountKey?new oe({url:new URL("/api/org/entitlements",e.meteringUrl??"https://savings.bivelio.com/api/metering/usage").toString(),
119
+ serviceAccountKey:e.serviceAccountKey,...e.fetchImpl?{fetchImpl:e.fetchImpl}:{},log:r}):null,u=a=>a==="/v1/messages"?new $:a.endsWith("/responses")?new te:null,p=(a,d,h,b,v,f,y,D)=>{if(!o||!h)return;let W=o,
120
+ V=h,S=Ve(d,f);if(!S){E(`gateway-sin-modelo:${v}`,`[bvsala gateway] no se pudo leer el modelo del cuerpo de ${v} (content-encoding: ${f??"ninguno"}); su uso se reenv\xEDa pero no se mide.`);return}let T=Ue(
121
+ S,h);T?(o.record(b?Ke(a,S,T,y):qe(a,S,T,y)),r(`[gateway] POST ${v} ${b?"\xB7 COALESCIDA (llamada evitada)":""} \xB7 ${S} \xB7 $${T.costeUsd.toFixed(6)} (in ${T.tokens.entrada}, cache\u2191${T.tokens.cacheEscrita}${T.
122
+ tokens.cacheEscrita1h?` (1h ${T.tokens.cacheEscrita1h})`:""} cache\u2193${T.tokens.cacheLeida}, out ${T.tokens.salida})`+(D?` \xB7 elisi\xF3n: ${D.borrados} borrado(s), ${D.tokensLimpiados} tok limpia\
123
+ dos por el proveedor`:"")),i&&!b&&v==="/v1/messages"&&setImmediate(()=>{try{let L=he(d,f);if(!L||typeof L!="object")return;let R=i.observar({cuerpo:L,uso:V,model:S,at:Date.now(),...y?.sessionId!==void 0?
124
+ {sessionId:y.sessionId}:{},...y?.agentId!==void 0?{agentId:y.agentId}:{}});if(!R)return;W.record(He(`${a}:shadow`,S,R.baselineUsd,R.politicaUsd,y)),r(`[gateway] sombra \xB7 ${S} \xB7 baseline $${R.baselineUsd.
125
+ toFixed(6)} \u2192 v0 $${R.politicaUsd.toFixed(6)}`);}catch{}})):E(`gateway-sin-precio:${S}`,`[bvsala gateway] el modelo "${S}" no est\xE1 en el cat\xE1logo de precios; su uso se reenv\xEDa pero no se mide.`);},
126
+ m=createServer(async(a,d)=>{let h=randomUUID(),b=new AbortController;d.on("close",()=>{d.writableEnded||b.abort();});let v=null,f=new URL(a.url??"/",t),y=null,D=Buffer.alloc(0),W=false,V=a.headers["content-encoding"],S=Array.
127
+ isArray(V)?V[0]:V,T=_=>{let w=Array.isArray(_)?_[0]:_;return w!==void 0&&/^[A-Za-z0-9._:/-]{1,128}$/.test(w)?w:void 0},L=T(a.headers["x-claude-code-session-id"]),R=T(a.headers["x-claude-code-agent-id"]),
128
+ G=L!==void 0||R!==void 0?{...L!==void 0?{sessionId:L}:{},...R!==void 0?{agentId:R}:{}}:void 0;try{let _=[];for await(let g of a)_.push(g);let w=Buffer.concat(_);D=w,f=new URL(a.url??"/",t);let Y=s!==null&&
129
+ a.method==="POST"&&w.length>0,Ct=rt(g=>{let x=a.headers[g];return Array.isArray(x)?x.join(", "):x}),le=Y?ot("POST",f.pathname+f.search,w,Ct):"";if(Y)if(s.tieneEnVuelo(le)){let g=await s.esperar(le);if(g){
130
+ d.writeHead(g.status,g.headers);let x=u(f.pathname)??new $;for(let Me of g.chunks)d.write(Me),x.observar(Me);d.end();let Et=x.usage()??(f.pathname==="/v1/messages"?be(Buffer.concat(g.chunks)):null);p(
131
+ h,w,Et,!0,f.pathname,S,G);return}}else v=s.registrar(le);let Q={};for(let[g,x]of Object.entries(a.headers))g==="host"||g==="content-length"||x===void 0||(Q[g]=Array.isArray(x)?x.join(", "):x);let Oe=w;
132
+ if(c!==null&&a.method==="POST"&&f.pathname==="/v1/messages"&&c.tiene("context_elision"))try{let g=tt(w,S);g!==null&&(Oe=g,Q["anthropic-beta"]=nt(Q["anthropic-beta"]));}catch{}let C;try{C=await n(f,{method:a.
133
+ method,headers:Q,body:["GET","HEAD"].includes(a.method??"")?void 0:Oe,redirect:"manual",signal:b.signal});}catch(g){v?.abortar(),d.headersSent||(d.writeHead(502,{"content-type":"application/json"}),d.end(
134
+ JSON.stringify({error:"bvsala gateway: upstream unreachable",detail:String(g)}))),r(`[gateway] ${a.method} ${f.pathname} \u2192 upstream inalcanzable: ${String(g)}`);return}let ue=Object.fromEntries(C.
135
+ headers.entries());for(let g of rn)delete ue[g];d.writeHead(C.status,ue);let De=C.headers.get("content-type")??"",de=De.includes("text/event-stream")||De===""&&C.ok&&u(f.pathname)!==null;y=de?u(f.pathname):
136
+ null;let F=!de&&C.ok&&o!==void 0&&a.method==="POST"&&f.pathname==="/v1/messages"&&(C.headers.get("content-type")??"").includes("application/json")?[]:null,Le=0;if(C.body)for await(let g of C.body){let x=Buffer.
137
+ from(g);d.write(x),y?.observar(x),F&&(Le+=x.length,Le>ve?F=null:F.push(x)),v?.capturar(x);}if(d.end(),v?.terminar(C.status,ue),y&&C.ok){W=!0;let g=y instanceof $?y.elision():null;p(h,w,y.usage(),!1,f.pathname,
138
+ S,G,g);}else if(F){let g=Buffer.concat(F);p(h,w,be(g),!1,f.pathname,S,G,Be(g));}else de||r(`[gateway] ${a.method} ${f.pathname} \u2192 ${C.status}`);}catch(_){if(v?.abortar(),b.signal.aborted){let w=!W&&
139
+ y?y.usageFinal():null;if(w){r(`[gateway] ${a.method} ${f.pathname} \u2192 el cliente cerr\xF3 tras el usage final; se mide igual`);let Y=y instanceof $?y.elision():null;p(h,D,w,false,f.pathname,S,G,Y);}else
140
+ r(`[gateway] ${a.method} ${f.pathname} \u2192 el cliente abort\xF3; upstream cancelado`);}else if(r(`[gateway] ${a.method} ${f.pathname} \u2192 error sirviendo: ${String(_)}`),!d.headersSent){d.writeHead(
141
+ 502,{"content-type":"application/json"}),d.end(JSON.stringify({error:"bvsala gateway: stream interrupted",detail:String(_)}));return}d.writableEnded||d.end();}});return m.on("upgrade",(a,d)=>{r(`[gatew\
142
+ ay] ${a.method} ${new URL(a.url??"/","http://x").pathname} \u2192 426 (WebSocket no soportado; el cliente cae a HTTP)`),d.once("error",()=>{}),d.once("finish",()=>d.destroy()),d.end(`HTTP/1.1 426 Upgr\
143
+ ade Required\r
99
144
  connection: close\r
100
145
  content-length: 0\r
101
146
  \r
102
- `);}),await new Promise((c,u)=>{l.once("error",u),l.listen(e.puerto??8402,"127.0.0.1",()=>c());}),{puerto:l.address().port,cerrar:async()=>{await o?.stopAndDrain(),await new Promise(c=>l.close(()=>c()));}}}var ie=["claude","codex","goose","qwen"];function Ne(e){return ie.includes(e??"")}function ze(e,t={}){let n=t.path??process.env.PATH??"",r=t.
103
- existe??existsSync,o=null;for(let s of n.split(";").filter(i=>i.length>0)){for(let i of [".exe",".com"]){let a=join(s,e+i);if(r(a))return {tipo:"exe",ruta:a}}if(o===null)for(let i of [".cmd",".bat"]){let a=join(s,e+
104
- i);if(r(a)){o=a;break}}}return o!==null?{tipo:"solo-shim",ruta:o}:{tipo:"no-encontrado"}}function Be(e={}){let n=(e.env??process.env).BVSALA_CODEX_AUTH?.toLowerCase();if(n==="api-key"||n==="apikey")return "\
147
+ `);}),await new Promise((a,d)=>{m.once("error",d),m.listen(e.puerto??8402,"127.0.0.1",()=>a());}),{puerto:m.address().port,cerrar:async()=>{await o?.stopAndDrain(),await new Promise(a=>m.close(()=>a()));}}}var ye=["claude","codex","goose","qwen"];function at(e){return ye.includes(e??"")}function ct(e,t={}){let n=t.path??process.env.PATH??"",r=t.
148
+ existe??existsSync,o=null;for(let s of n.split(";").filter(i=>i.length>0)){for(let i of [".exe",".com"]){let c=join(s,e+i);if(r(c))return {tipo:"exe",ruta:c}}if(o===null)for(let i of [".cmd",".bat"]){let c=join(s,e+
149
+ i);if(r(c)){o=c;break}}}return o!==null?{tipo:"solo-shim",ruta:o}:{tipo:"no-encontrado"}}function lt(e={}){let n=(e.env??process.env).BVSALA_CODEX_AUTH?.toLowerCase();if(n==="api-key"||n==="apikey")return "\
105
150
  api-key";if(n==="chatgpt")return "chatgpt";let r=null;try{r=e.leerAuth?e.leerAuth():null;}catch{r=null;}if(r===null)return "api-key";try{let o=JSON.parse(r);return typeof o.auth_mode=="string"?o.auth_mode.
106
- toLowerCase().replace(/[^a-z]/g,"")==="apikey"?"api-key":"chatgpt":o.tokens!==void 0&&o.tokens!==null?"chatgpt":"api-key"}catch{return "api-key"}}var wt={"api-key":{upstream:"https://api.openai.com",prefijo:"\
107
- /v1"},chatgpt:{upstream:"https://chatgpt.com",prefijo:"/backend-api/codex"}};function ae(e,t,n,r={}){let o=`http://127.0.0.1:${t}`;switch(e){case "claude":return {bin:"claude",args:n,env:{ANTHROPIC_BASE_URL:o}};case "\
151
+ toLowerCase().replace(/[^a-z]/g,"")==="apikey"?"api-key":"chatgpt":o.tokens!==void 0&&o.tokens!==null?"chatgpt":"api-key"}catch{return "api-key"}}var an={"api-key":{upstream:"https://api.openai.com",prefijo:"\
152
+ /v1"},chatgpt:{upstream:"https://chatgpt.com",prefijo:"/backend-api/codex"}};function ke(e,t,n,r={}){let o=`http://127.0.0.1:${t}`;switch(e){case "claude":return {bin:"claude",args:n,env:{ANTHROPIC_BASE_URL:o}};case "\
108
153
  goose":return {bin:"goose",args:n,env:{ANTHROPIC_HOST:o}};case "qwen":return {bin:"qwen",args:n,env:{ANTHROPIC_BASE_URL:o},nota:'Qwen Code solo enruta por aqu\xED con `security.auth.selectedType: "anthropic\
109
- "` en ~/.qwen/settings.json (ver `bvsala doctor`).'};case "codex":{let s=r.modoCodex??"api-key",i=wt[s];return {bin:"codex",args:["-c",`openai_base_url="${o}${i.prefijo}"`,...n],env:{},upstream:i.upstream,
154
+ "` en ~/.qwen/settings.json (ver `bvsala doctor`).'};case "codex":{let s=r.modoCodex??"api-key",i=an[s];return {bin:"codex",args:["-c",`openai_base_url="${o}${i.prefijo}"`,...n],env:{},upstream:i.upstream,
110
155
  nota:s==="chatgpt"?"Auth ChatGPT detectada: el gateway enruta a chatgpt.com/backend-api/codex. El tr\xE1fico de suscripci\xF3n se mide (equivalente a precio de lista) pero no se monetiza: no hay factura por\
111
- tokens.":"Auth por API key: el gateway enruta a api.openai.com/v1."}}}}var Et="comprobar: en el log del gateway debe aparecer `[gateway] POST /v1/messages \u2026`; si ve\
112
- s `/v1/v1/messages`, sobra un /v1; si ves `POST /messages` a secas, falta uno.",It=[{id:"claude",nombre:"Claude Code",binario:"claude",configs:[],detectable:true,receta:({base:e})=>["usa `bvsala claude`\
156
+ tokens.":"Auth por API key: el gateway enruta a api.openai.com/v1."}}}}var dn="comprobar: en el log del gateway debe aparecer `[gateway] POST /v1/messages \u2026`; si ve\
157
+ s `/v1/v1/messages`, sobra un /v1; si ves `POST /messages` a secas, falta uno.",pn=[{id:"claude",nombre:"Claude Code",binario:"claude",configs:[],detectable:true,receta:({base:e})=>["usa `bvsala claude`\
113
158
  \u2014 arranca el gateway en un puerto ef\xEDmero, lanza `claude` apunt\xE1ndole y lo apaga al salir.",`a mano: ANTHROPIC_BASE_URL=${e} claude (sin /v1: el cliente a\xF1ade /v1/messages)`]},{id:"co\
114
159
  dex",nombre:"Codex CLI",binario:"codex",configs:[join(".codex","config.toml"),join(".codex","auth.json")],detectable:true,receta:({base:e,rutas:t})=>["usa `bvsala codex` \u2014 el prefijo del base URL depende del \
115
160
  modo de auth y lo resuelve el envoltorio:",` API key \u2192 openai_base_url=${e}/v1`,` suscripci\xF3n ChatGPT \u2192 openai_base_url=${e}/backend-api/codex (tiene que terminar exactament\
@@ -125,40 +170,40 @@ Droid (Factory)",binario:"droid",configs:[join(".factory","settings.json")],dete
125
170
  idar en mano contra el log del gateway].`,"{",' "customModels": ['," {",' "model": "<id de modelo Anthropic>",',' "displayName": "<nombre visible>",',' "provider": "anthropic",',` \
126
171
  "baseUrl": "${e}",`,' "apiKey": "<tu API key de Anthropic>"'," }"," ]","}"]},{id:"cline",nombre:"Cline",configs:[],detectable:false,receta:({baseV1:e})=>["mecanismo: UI \u2192 proveedor Anthropic\
127
172
  \u2192 marca \xABUse custom base URL\xBB. CON /v1 (Cline fija https://api.anthropic.com/v1 y solo normaliza la URL oficial exacta).",`Base URL: ${e}`]},{id:"kilo",nombre:"Kilo Code",configs:[],detectable:false,
128
- receta:({baseV1:e})=>["mecanismo: UI \u2192 proveedor custom, Provider API \xABAnthropic Messages\xBB. Probar CON /v1 primero (linaje Cline) [inferido: validar en mano].",`Base URL: ${e}`]}];function Pt(e,t){
129
- let n=e.split(delimiter).filter(o=>o.length>0),r=process.platform==="win32"?["",".exe",".cmd",".bat"]:[""];return o=>n.some(s=>r.some(i=>t(join(s,o+i))))}async function Ve(e,t={}){if(!Number.isInteger(e)||e<1||
130
- e>65535)throw new RangeError(`[bvsala doctor] puerto inv\xE1lido: ${String(e)}`);let n=t.home??homedir(),r=t.existe??existsSync,o=t.enPath??Pt(t.path??process.env.PATH??"",r),s=`http://127.0.0.1:${e}`,i=`${s}/v1`,
131
- a=[],l=[`bvsala doctor \u2014 gateway local en ${s}`,"Solo imprime: no escribe ninguna configuraci\xF3n. Detecci\xF3n por existencia (binarios en PATH y","archivos de configuraci\xF3n de usuario); nunca \
132
- se lee el contenido de ning\xFAn archivo.",""];for(let p of It){let c=p.configs.map(d=>join(n,d)),u=p.binario!==void 0&&o(p.binario),f=c.filter(d=>r(d)),b=u||f.length>0;b&&a.push(p.id);let m;p.detectable?
133
- b?m=`detectado \u2014 ${[...u?[`binario \`${p.binario}\` en PATH`]:[],...f.map(y=>`config presente: ${y}`)].join("; ")}`:m="no detectado":m="sin detecci\xF3n autom\xE1tica (extensi\xF3n de editor)",l.
134
- push(`\xBB ${p.id}: ${m}`),l.push(` ${p.nombre}`);for(let d of p.receta({base:s,baseV1:i,rutas:c}))l.push(` ${d}`);l.push(` ${Et}`),l.push("");}return l.push("Regla BYOK: las recetas del anillo Anth\
173
+ receta:({baseV1:e})=>["mecanismo: UI \u2192 proveedor custom, Provider API \xABAnthropic Messages\xBB. Probar CON /v1 primero (linaje Cline) [inferido: validar en mano].",`Base URL: ${e}`]}];function mn(e,t){
174
+ let n=e.split(delimiter).filter(o=>o.length>0),r=process.platform==="win32"?["",".exe",".cmd",".bat"]:[""];return o=>n.some(s=>r.some(i=>t(join(s,o+i))))}async function ut(e,t={}){if(!Number.isInteger(e)||e<1||
175
+ e>65535)throw new RangeError(`[bvsala doctor] puerto inv\xE1lido: ${String(e)}`);let n=t.home??homedir(),r=t.existe??existsSync,o=t.enPath??mn(t.path??process.env.PATH??"",r),s=`http://127.0.0.1:${e}`,i=`${s}/v1`,
176
+ c=[],u=[`bvsala doctor \u2014 gateway local en ${s}`,"Solo imprime: no escribe ninguna configuraci\xF3n. Detecci\xF3n por existencia (binarios en PATH y","archivos de configuraci\xF3n de usuario); nunca \
177
+ se lee el contenido de ning\xFAn archivo.",""];for(let p of pn){let m=p.configs.map(b=>join(n,b)),l=p.binario!==void 0&&o(p.binario),a=m.filter(b=>r(b)),d=l||a.length>0;d&&c.push(p.id);let h;p.detectable?
178
+ d?h=`detectado \u2014 ${[...l?[`binario \`${p.binario}\` en PATH`]:[],...a.map(v=>`config presente: ${v}`)].join("; ")}`:h="no detectado":h="sin detecci\xF3n autom\xE1tica (extensi\xF3n de editor)",u.
179
+ push(`\xBB ${p.id}: ${h}`),u.push(` ${p.nombre}`);for(let b of p.receta({base:s,baseV1:i,rutas:m}))u.push(` ${b}`);u.push(` ${dn}`),u.push("");}return u.push("Regla BYOK: las recetas del anillo Anth\
135
180
  ropic (Goose, Qwen Code, opencode, Crush, Droid, Cline, Kilo) son","para API key. Nunca enrutes por el gateway el OAuth de una suscripci\xF3n Claude Pro/Max desde un harness","de terceros \u2014 Anthropic \
136
- lo proh\xEDbe. Claude Code y Codex con suscripci\xF3n se enrutan y se miden, pero no","se monetizan: no hay factura por tokens.","Detalle por terminal: docs/terminales/<terminal>.md"),{texto:l.join(`
137
- `),detectados:a}}var Fe="savings-mode";function Ue(e,t){for(let n of e){let r=join(n,"skills",Fe,"SKILL.md");if(t.existe(r))return r}return null}var qe="<!-- bvsala:savings-mode:inicio -->",W="\
138
- <!-- bvsala:savings-mode:fin -->";function At(e){let t=e.replace(/^---\n[\s\S]*?\n---\n*/,"").trim();return `${qe}
181
+ lo proh\xEDbe. Claude Code y Codex con suscripci\xF3n se enrutan y se miden, pero no","se monetizan: no hay factura por tokens.","Detalle por terminal: docs/terminales/<terminal>.md"),{texto:u.join(`
182
+ `),detectados:c}}var dt="savings-mode";function pt(e,t){for(let n of e){let r=join(n,"skills",dt,"SKILL.md");if(t.existe(r))return r}return null}var mt="<!-- bvsala:savings-mode:inicio -->",ie="\
183
+ <!-- bvsala:savings-mode:fin -->";function fn(e){let t=e.replace(/^---\n[\s\S]*?\n---\n*/,"").trim();return `${mt}
139
184
  ${t}
140
185
 
141
186
  _Always on (AGENTS.md has no activation step). Delete this block to turn it off; \`bvsala skill --codex --forzar\` restores it._
142
- ${W}`}function Ke(e){let t=Ue(e.origenes,e.fs);if(!t)return {ok:false,destino:"",mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${e.origenes.join(", ")})`};let n=At(e.fs.
187
+ ${ie}`}function ft(e){let t=pt(e.origenes,e.fs);if(!t)return {ok:false,destino:"",mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${e.origenes.join(", ")})`};let n=fn(e.fs.
143
188
  leer(t)),r=e.proyecto?e.cwd:join(e.home,".codex"),o=join(r,"AGENTS.md");if(!e.fs.existe(o))return e.fs.crearDir(r),e.fs.escribir(o,n+`
144
- `),{ok:true,destino:o,mensaje:ce(o,"instalado")};let s=e.fs.leer(o),i=s.indexOf(qe),a=s.indexOf(W);return i===-1||a===-1||a<i?(e.fs.escribir(o,s.trimEnd()+`
189
+ `),{ok:true,destino:o,mensaje:xe(o,"instalado")};let s=e.fs.leer(o),i=s.indexOf(mt),c=s.indexOf(ie);return i===-1||c===-1||c<i?(e.fs.escribir(o,s.trimEnd()+`
145
190
 
146
191
  `+n+`
147
- `),{ok:true,destino:o,mensaje:ce(o,"a\xF1adido al AGENTS.md existente")}):s.slice(i,a+W.length)===n?{ok:true,destino:o,mensaje:`[bvsala skill] ya instalado y al d\xEDa: ${o}`}:e.forzar?(e.fs.escribir(o,s.
148
- slice(0,i)+n+s.slice(a+W.length)),{ok:true,destino:o,mensaje:ce(o,"bloque actualizado")}):{ok:false,destino:o,mensaje:`[bvsala skill] el bloque savings-mode de ${o} tiene contenido DISTINTO \u2014 no lo piso; u\
149
- sa --forzar para actualizarlo`}}function ce(e,t){return `[bvsala skill] ${t}: ${e}
192
+ `),{ok:true,destino:o,mensaje:xe(o,"a\xF1adido al AGENTS.md existente")}):s.slice(i,c+ie.length)===n?{ok:true,destino:o,mensaje:`[bvsala skill] ya instalado y al d\xEDa: ${o}`}:e.forzar?(e.fs.escribir(o,s.
193
+ slice(0,i)+n+s.slice(c+ie.length)),{ok:true,destino:o,mensaje:xe(o,"bloque actualizado")}):{ok:false,destino:o,mensaje:`[bvsala skill] el bloque savings-mode de ${o} tiene contenido DISTINTO \u2014 no lo piso; \
194
+ usa --forzar para actualizarlo`}}function xe(e,t){return `[bvsala skill] ${t}: ${e}
150
195
  [bvsala skill] AGENTS.md va SIEMPRE activo en Codex (no hay paso de activaci\xF3n); borra el bloque para apagarlo.
151
- [bvsala skill] para medir su efecto: trabaja unos d\xEDas con \xE9l y otros sin \xE9l bajo \`bvsala codex\`, y compara en el panel.`}function He(e){let t=Ue(e.origenes,e.fs);if(!t)return {ok:false,destino:"",
152
- mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${e.origenes.join(", ")})`};let n=e.proyecto?join(e.cwd,".claude","skills"):join(e.home,".claude","skills"),r=join(n,Fe),o=join(r,
196
+ [bvsala skill] para medir su efecto: trabaja unos d\xEDas con \xE9l y otros sin \xE9l bajo \`bvsala codex\`, y compara en el panel.`}function ht(e){let t=pt(e.origenes,e.fs);if(!t)return {ok:false,destino:"",
197
+ mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${e.origenes.join(", ")})`};let n=e.proyecto?join(e.cwd,".claude","skills"):join(e.home,".claude","skills"),r=join(n,dt),o=join(r,
153
198
  "SKILL.md"),s=e.fs.leer(t);if(e.fs.existe(o)&&!e.forzar){let i=e.fs.leer(o)===s;return {ok:i,destino:o,mensaje:i?`[bvsala skill] ya instalado y al d\xEDa: ${o}`:`[bvsala skill] ya existe ${o} con conte\
154
199
  nido DISTINTO \u2014 no lo piso; usa --forzar para sobrescribir`}}return e.fs.crearDir(r),e.fs.escribir(o,s),{ok:true,destino:o,mensaje:`[bvsala skill] instalado: ${o}
155
200
  [bvsala skill] arranca (o reinicia) Claude Code y p\xEDdele \xABsavings mode\xBB \u2014 o deja que se active solo al hablar de l\xEDmites.
156
- [bvsala skill] para medir su efecto de verdad: trabaja unos d\xEDas con \xE9l y otros sin \xE9l bajo \`bvsala claude\`, y compara en el panel.`}}var le=class{id;exact=false;constructor(t="heuristic"){this.id=t;}count(t){if(t.length===0)return 0;let n=t.match(/[A-Za-z]+|\d+|\s+|[^\sA-Za-z\d]/g)??[],r=0;for(let o of n){let s=o[0];if(/\s/.test(s)){let i=(o.
201
+ [bvsala skill] para medir su efecto de verdad: trabaja unos d\xEDas con \xE9l y otros sin \xE9l bajo \`bvsala claude\`, y compara en el panel.`}}var Se=class{id;exact=false;constructor(t="heuristic"){this.id=t;}count(t){if(t.length===0)return 0;let n=t.match(/[A-Za-z]+|\d+|\s+|[^\sA-Za-z\d]/g)??[],r=0;for(let o of n){let s=o[0];if(/\s/.test(s)){let i=(o.
157
202
  match(/\n/g)??[]).length;r+=i+Math.floor(Math.max(0,o.length-1)/2);}else /[A-Za-z]/.test(s)?r+=Math.max(1,Math.ceil(o.length/4)):/\d/.test(s)?r+=Math.max(1,Math.ceil(o.length/2)):r+=1;}return Math.max(r,
158
- Math.ceil(t.length/4))}},ue=new le;var de=class{estimators=new Map;modelToTokenizer=new Map;fallbackId;constructor(t=ue){this.fallbackId=t.id,this.estimators.set(t.id,t);}register(t){return this.estimators.set(t.id,t),this}mapModel(t,n){
203
+ Math.ceil(t.length/4))}},we=new Se;var Te=class{estimators=new Map;modelToTokenizer=new Map;fallbackId;constructor(t=we){this.fallbackId=t.id,this.estimators.set(t.id,t);}register(t){return this.estimators.set(t.id,t),this}mapModel(t,n){
159
204
  return this.modelToTokenizer.set(t,n),this}resolve(t){let n=t.tokenizer?this.estimators.get(t.tokenizer):void 0;if(n)return n;if(t.model){let r=this.modelToTokenizer.get(t.model);if(r){let o=this.estimators.
160
- get(r);if(o)return o}}return this.estimators.get(this.fallbackId)}count(t,n){return this.resolve(n).count(t)}};new de;new TextEncoder;new TextDecoder;new TextDecoder;var Ht={"gpt-4o-mini":{deltaTokens:-16,salidaDelBrazoA:72,contrato:"triage (6 fields, long enums)",pares:8},"gpt-4o":{deltaTokens:3,salidaDelBrazoA:75,contrato:"triage (6 fields, long enums)",pares:8}};
161
- oe(Ht);var he="0.4.10";var[,,g,...I]=process.argv;function Zt(){console.log(`bvsala ${he} \u2014 BiVelio Savings Layer
205
+ get(r);if(o)return o}}return this.estimators.get(this.fallbackId)}count(t,n){return this.resolve(n).count(t)}};new Te;new TextEncoder;new TextDecoder;new TextDecoder;var An={"gpt-4o-mini":{deltaTokens:-16,salidaDelBrazoA:72,contrato:"triage (6 fields, long enums)",pares:8},"gpt-4o":{deltaTokens:3,salidaDelBrazoA:75,contrato:"triage (6 fields, long enums)",pares:8}};
206
+ me(An);var _e="0.4.12";var[,,k,...P]=process.argv;function Nn(){console.log(`bvsala ${_e} \u2014 BiVelio Savings Layer
162
207
 
163
208
  Comandos:
164
209
  gateway [--puerto N] Proxy local medidor (por defecto 8402) para terminales que
@@ -183,27 +228,37 @@ Entorno:
183
228
  BVSALA_SEAT_ID Identidad de asiento estable por r\xE9plica (opcional).
184
229
  BVSALA_GATEWAY_UPSTREAM Upstream alternativo (por defecto el del terminal).
185
230
  BVSALA_GATEWAY_COALESCE =1 enciende la coalescencia de duplicados (F2, experimental).
231
+ BVSALA_GATEWAY_SHADOW =1 enciende el carril sombra de la elisi\xF3n (S2): calcula qu\xE9
232
+ habr\xEDa ahorrado la pol\xEDtica v0 SIN tocar el tr\xE1fico y lo
233
+ reporta aparte (jam\xE1s entra en la comisi\xF3n).
234
+ BVSALA_GATEWAY_ELISION =1 arma la palanca de diales del proveedor (S4a). Solo se
235
+ enciende de verdad si adem\xE1s la licencia de tu organizaci\xF3n
236
+ trae el feature context_elision (consulta fail-closed): ajusta
237
+ SOLO el bloque context_management de cada petici\xF3n /v1/messages
238
+ y el borrado lo hace el propio proveedor. Ante cualquier duda,
239
+ la petici\xF3n viaja intacta.
186
240
  BVSALA_CODEX_AUTH api-key | chatgpt \u2014 fuerza el modo de auth de Codex.
187
241
  BVSALA_GATEWAY_LOG =1 ense\xF1a el log por petici\xF3n tambi\xE9n dentro de los envoltorios
188
242
  (por defecto va silenciado para no pisar el TUI; mira el panel).
189
243
  CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 (Claude Code, solo API key) tus modelos en /model.
190
244
 
191
245
  El gateway nunca corta el tr\xE1fico: sin clave o con la ingesta ca\xEDda, reenv\xEDa y avisa.
192
- Tus prompts jam\xE1s salen de tu m\xE1quina \u2014 solo cuentas y coste. M\xE1s: savings.bivelio.com`);}var B=Ne(g);g!=="gateway"&&g!=="doctor"&&g!=="skill"&&!B&&(Zt(),process.exit(g===void 0||g==="hel\
193
- p"||g==="--help"?0:1));if(g==="skill"){let e=dirname(fileURLToPath(import.meta.url)),t={origenes:[join(e,"..",".."),join(e,"..")],home:homedir(),cwd:process.cwd(),proyecto:I.includes("--proyecto"),forzar:I.includes("--forzar"),
194
- fs:{existe:existsSync,leer:r=>readFileSync(r,"utf8"),escribir:(r,o)=>writeFileSync(r,o),crearDir:r=>mkdirSync(r,{recursive:true})}},n=I.includes("--codex")?Ke(t):He(t);console.log(n.mensaje),process.exit(n.ok?0:1);}var be=I.indexOf("--puer\
195
- to"),L=B?0:be>=0?Number(I[be+1]):8402;(!Number.isInteger(L)||(g==="doctor"?L<1:L<0)||L>65535)&&(console.error(`[bvsala ${g}] puerto inv\xE1lido: ${I[be+1]}`),process.exit(1));if(g==="doctor"){I.includes(
196
- "--write")&&(console.error("[bvsala doctor] --write todav\xEDa no existe: el doctor solo imprime; copia el bloque a mano."),process.exit(1));let e=await Ve(L);console.log(e.texto),process.exit(0);}var P=B?
197
- ae(g,0,I,{modoCodex:g==="codex"?Be({leerAuth:()=>readFileSync(join(homedir(),".codex","auth.json"),"utf8")}):void 0}):null,ve=process.env.BIVELIO_SERVICE_KEY,en=B&&process.env.BVSALA_GATEWAY_LOG!=="1",_=await $e({puerto:L,
198
- ...en?{log:()=>{}}:{},...ve?{serviceAccountKey:ve}:{},...process.env.BVSALA_SEAT_ID?{seatId:process.env.BVSALA_SEAT_ID}:{},...process.env.BVSALA_GATEWAY_UPSTREAM?{upstream:process.env.BVSALA_GATEWAY_UPSTREAM}:
199
- P?.upstream?{upstream:P.upstream}:{},...process.env.BVSALA_GATEWAY_COALESCE==="1"?{coalescer:true}:{},...process.env.BVSALA_METERING_URL?{meteringUrl:process.env.BVSALA_METERING_URL}:{}}),tn=process.env.
200
- BVSALA_GATEWAY_UPSTREAM??P?.upstream??"https://api.anthropic.com";console.log(`[bvsala gateway] v${he} escuchando en http://127.0.0.1:${_.puerto} \u2192 ${tn}`);console.log(`[bvsala gateway] medici\xF3n:\
201
- ${ve?"ACTIVA (clave de servicio presente)":"APAGADA (falta BIVELIO_SERVICE_KEY)"}`);process.env.BVSALA_GATEWAY_UPSTREAM&&P?.upstream&&process.env.BVSALA_GATEWAY_UPSTREAM!==P.upstream&&console.error(`\
202
- [bvsala ${g}] AVISO: BVSALA_GATEWAY_UPSTREAM=${process.env.BVSALA_GATEWAY_UPSTREAM} pisa el upstream de este terminal (${P.upstream}). Si no es lo que quieres, quita la variable.`);g==="codex"&&!Ae()&&
203
- console.error(`[bvsala codex] AVISO: este Node (${process.version}) no descomprime zstd y Codex manda el cuerpo en zstd: el tr\xE1fico pasa pero NO se mide. Usa Node \u2265 22.15.`);if(P&&B){let e=ae(
204
- g,_.puerto,I,{...P.upstream?{modoCodex:P.upstream.includes("chatgpt.com")?"chatgpt":"api-key"}:{}});e.nota&&console.log(`[bvsala ${g}] ${e.nota}`);let t=e.bin;if(process.platform==="win32"){let r=ze(e.
205
- bin);r.tipo==="exe"?t=r.ruta:r.tipo==="solo-shim"&&(console.error(`[bvsala ${g}] \`${e.bin}\` est\xE1 instalado como shim de npm (${r.ruta}) y Windows no puede lanzarlo de forma segura con argumentos \
206
- (CVE-2024-27980). Inst\xE1lalo con su instalador nativo (deja un ${e.bin}.exe en el PATH) o usa la receta manual de docs/terminales/.`),await _.cerrar(),process.exit(127));}let n=spawn(t,e.args,{stdio:"in\
207
- herit",env:{...process.env,...e.env}});n.on("error",r=>{console.error(`[bvsala ${g}] no se pudo lanzar \`${e.bin}\`: ${String(r)}. \xBFEst\xE1 instalado y en el PATH?`),_.cerrar().then(()=>process.exit(
208
- 127));}),n.on("exit",(r,o)=>{_.cerrar().then(()=>process.exit(r??(o?1:0)));});}else console.log(`[bvsala gateway] apunta tu terminal (o usa \`bvsala ${ie.join("|")}\`): ANTHROPIC_BASE_URL=http://127.0.0.\
209
- 1:${_.puerto} claude \xB7 bvsala doctor para el resto`);var tt=async()=>{await _.cerrar(),process.exit(0);};process.on("SIGINT",()=>{tt();});process.on("SIGTERM",()=>{tt();});
246
+ Tus prompts jam\xE1s salen de tu m\xE1quina \u2014 solo cuentas y coste. M\xE1s: savings.bivelio.com`);}var J=at(k);k!=="gateway"&&k!=="doctor"&&k!=="skill"&&!J&&(Nn(),process.exit(k===void 0||k==="hel\
247
+ p"||k==="--help"?0:1));if(k==="skill"){let e=dirname(fileURLToPath(import.meta.url)),t={origenes:[join(e,"..",".."),join(e,"..")],home:homedir(),cwd:process.cwd(),proyecto:P.includes("--proyecto"),forzar:P.includes("--forzar"),
248
+ fs:{existe:existsSync,leer:r=>readFileSync(r,"utf8"),escribir:(r,o)=>writeFileSync(r,o),crearDir:r=>mkdirSync(r,{recursive:true})}},n=P.includes("--codex")?ft(t):ht(t);console.log(n.mensaje),process.exit(n.ok?0:1);}var Ae=P.indexOf("--puer\
249
+ to"),U=J?0:Ae>=0?Number(P[Ae+1]):8402;(!Number.isInteger(U)||(k==="doctor"?U<1:U<0)||U>65535)&&(console.error(`[bvsala ${k}] puerto inv\xE1lido: ${P[Ae+1]}`),process.exit(1));if(k==="doctor"){P.includes(
250
+ "--write")&&(console.error("[bvsala doctor] --write todav\xEDa no existe: el doctor solo imprime; copia el bloque a mano."),process.exit(1));let e=await ut(U);console.log(e.texto),process.exit(0);}var O=J?
251
+ ke(k,0,P,{modoCodex:k==="codex"?lt({leerAuth:()=>readFileSync(join(homedir(),".codex","auth.json"),"utf8")}):void 0}):null,Pe=process.env.BIVELIO_SERVICE_KEY,jn=J&&process.env.BVSALA_GATEWAY_LOG!=="1",j=await st({puerto:U,
252
+ ...jn?{log:()=>{}}:{},...Pe?{serviceAccountKey:Pe}:{},...process.env.BVSALA_SEAT_ID?{seatId:process.env.BVSALA_SEAT_ID}:{},...process.env.BVSALA_GATEWAY_UPSTREAM?{upstream:process.env.BVSALA_GATEWAY_UPSTREAM}:
253
+ O?.upstream?{upstream:O.upstream}:{},...process.env.BVSALA_GATEWAY_COALESCE==="1"?{coalescer:true}:{},...process.env.BVSALA_GATEWAY_SHADOW==="1"?{sombra:true}:{},...process.env.BVSALA_GATEWAY_ELISION==="1"?
254
+ {elision:true}:{},...process.env.BVSALA_METERING_URL?{meteringUrl:process.env.BVSALA_METERING_URL}:{}}),zn=process.env.BVSALA_GATEWAY_UPSTREAM??O?.upstream??"https://api.anthropic.com";console.log(`[bvs\
255
+ ala gateway] v${_e} escuchando en http://127.0.0.1:${j.puerto} \u2192 ${zn}`);console.log(`[bvsala gateway] medici\xF3n: ${Pe?"ACTIVA (clave de servicio presente)":"APAGADA (falta BIVELIO_SERVICE_KEY)"}`);
256
+ process.env.BVSALA_GATEWAY_UPSTREAM&&O?.upstream&&process.env.BVSALA_GATEWAY_UPSTREAM!==O.upstream&&console.error(`[bvsala ${k}] AVISO: BVSALA_GATEWAY_UPSTREAM=${process.env.BVSALA_GATEWAY_UPSTREAM} p\
257
+ isa el upstream de este terminal (${O.upstream}). Si no es lo que quieres, quita la variable.`);k==="codex"&&!Fe()&&console.error(`[bvsala codex] AVISO: este Node (${process.version}) no descomprime z\
258
+ std y Codex manda el cuerpo en zstd: el tr\xE1fico pasa pero NO se mide. Usa Node \u2265 22.15.`);if(O&&J){let e=ke(k,j.puerto,P,{...O.upstream?{modoCodex:O.upstream.includes("chatgpt.com")?"chatgpt":
259
+ "api-key"}:{}});e.nota&&console.log(`[bvsala ${k}] ${e.nota}`);let t=e.bin;if(process.platform==="win32"){let r=ct(e.bin);r.tipo==="exe"?t=r.ruta:r.tipo==="solo-shim"&&(console.error(`[bvsala ${k}] \`${e.
260
+ bin}\` est\xE1 instalado como shim de npm (${r.ruta}) y Windows no puede lanzarlo de forma segura con argumentos (CVE-2024-27980). Inst\xE1lalo con su instalador nativo (deja un ${e.bin}.exe en el PAT\
261
+ H) o usa la receta manual de docs/terminales/.`),await j.cerrar(),process.exit(127));}let n=spawn(t,e.args,{stdio:"inherit",env:{...process.env,...e.env}});n.on("error",r=>{console.error(`[bvsala ${k}] no\
262
+ se pudo lanzar \`${e.bin}\`: ${String(r)}. \xBFEst\xE1 instalado y en el PATH?`),j.cerrar().then(()=>process.exit(127));}),n.on("exit",(r,o)=>{j.cerrar().then(()=>process.exit(r??(o?1:0)));});}else console.
263
+ log(`[bvsala gateway] apunta tu terminal (o usa \`bvsala ${ye.join("|")}\`): ANTHROPIC_BASE_URL=http://127.0.0.1:${j.puerto} claude \xB7 bvsala doctor para el resto`);var Tt=async()=>{await j.cerrar(),
264
+ process.exit(0);};process.on("SIGINT",()=>{Tt();});process.on("SIGTERM",()=>{Tt();});
package/dist/index.d.ts CHANGED
@@ -8,18 +8,23 @@
8
8
  * increment is driven by an explicit pipeline decision.
9
9
  */
10
10
  /**
11
- * De dónde sale el baseline con el que se compara el coste.
12
- *
13
- * - `measured` — reconstruido desde el contador del proveedor. Es dinero.
14
- * - `estimated` — llamada EVITADA: nunca se ejecutó, así que no hay contador
15
- * del proveedor y el baseline es del estimador local. Sigue
16
- * siendo la mejor cifra disponible, pero no está medida.
17
- * - `unmeasured` — el proveedor no reportó uso. No se reclama nada.
18
- *
19
- * Sumar `measured` y `estimated` en una misma cifra de "dinero ahorrado" es
20
- * exactamente lo que un producto verify-don't-trust no puede hacer.
21
- */
22
- type CostBasis = "measured" | "estimated" | "unmeasured";
11
+ * Where the baseline being compared against comes from.
12
+ *
13
+ * - `measured` — reconstructed from this request's provider counter. Real money.
14
+ * - `estimated` — the call was AVOIDED: it never ran, so there is no provider
15
+ * counter and the baseline comes from the local estimator. Still
16
+ * the best figure available, but not measured.
17
+ * - `unmeasured` — the provider reported no usage. Nothing is claimed.
18
+ * - `shadow` — HYPOTHETICAL: what would have happened with a lever turned on
19
+ * (the shadow lane). Never enters the commission base, never
20
+ * added to measured or to any total; shadow reports are built
21
+ * separately and `estimateCost` must never produce this value.
22
+ *
23
+ * Summing `measured` and `estimated` into a single "money saved" figure is
24
+ * exactly what a verify-don't-trust product cannot do — and adding `shadow` to
25
+ * either would be making the savings up.
26
+ */
27
+ type CostBasis = "measured" | "estimated" | "unmeasured" | "shadow";
23
28
  interface CostModel {
24
29
  /** Cost per 1K input tokens, in the caller's currency unit. */
25
30
  inputPer1k: number;
@@ -860,17 +865,24 @@ interface SavingsReport {
860
865
  actual: number;
861
866
  netSavings: number;
862
867
  /**
863
- * De dónde sale el baseline. Es lo que separa el dinero medido del estimado.
868
+ * Where the baseline comes from. It is what separates measured money from
869
+ * estimated money.
864
870
  *
865
- * - `measured` — reconstruido desde el contador del proveedor de ESTA
866
- * petición. Es dinero, y se puede contrastar con la factura.
867
- * - `estimated` — la llamada se EVITÓ, así que nunca hubo contador del
868
- * proveedor y el baseline sale del estimador local. Es la
869
- * mejor cifra disponible, pero no está medida.
870
- * - `unmeasured` — el proveedor no reportó uso. No se reclama nada.
871
+ * - `measured` — reconstructed from THIS request's provider counter. Real
872
+ * money, checkable against the provider invoice.
873
+ * - `estimated` — the call was AVOIDED, so there never was a provider
874
+ * counter and the baseline comes from the local estimator.
875
+ * The best figure available, but not measured.
876
+ * - `unmeasured` — the provider reported no usage. Nothing is claimed.
877
+ * - `shadow` — HYPOTHETICAL: the shadow lane (what would have happened
878
+ * with a lever turned on). Never in the commission base,
879
+ * never added to `measured` or to totals; shadow reports
880
+ * are built separately and `estimateCost` never produces
881
+ * this value.
871
882
  *
872
- * Un panel que sume `measured` y `estimated` en una sola cifra de "dinero
873
- * ahorrado" está haciendo justo lo que este producto promete no hacer.
883
+ * A dashboard that sums `measured` and `estimated` into a single "money
884
+ * saved" figure is doing exactly what this product promises not to do —
885
+ * and adding `shadow` to either would be making the savings up.
874
886
  */
875
887
  basis: CostBasis;
876
888
  };
@@ -3250,6 +3262,6 @@ declare function createSavingsLayer(config: Omit<SavingsLayerConfig, "tokenizer"
3250
3262
  * constant to package.json so the two can never drift.
3251
3263
  */
3252
3264
 
3253
- declare const BV_SALA_VERSION = "0.4.10";
3265
+ declare const BV_SALA_VERSION = "0.4.12";
3254
3266
 
3255
3267
  export { type AnthropicOptions, AnthropicProvider, BV_SALA_VERSION, type BivelioHandoff, CATALOGO, COMPACT_ROWS_INSTRUCTION, type CacheOutcome, type CacheTier, type CachedAnswer, type CanonicalRequest, type ChatMessage, type CompactRowsDecodeOptions, type CompactRowsOptions, type CompactVerification, type CompressionEconomics, type CompressionPolicyInput, type CompressionRequest, type CompressionResult, type Compressor, type ConstraintBackend, type ConstraintBackendId, type ConstraintPlan, type ConversationState, type CostBasis, type CostModel, DEFAULT_COST_MODEL, DEFAULT_MAX_STALENESS_SECONDS, type DeferredExecutionReport, type DeterministicResolver, EMBEDDED_PUBLIC_KEY, type EmbeddingFn, type EvidenceDoc, type ExactCache, ExactTokenizer, type ExecutionClass, ExecutionRouter, type FormatChoice, FormatSelector, type FormatSelectorOptions, type HandoffFact, HeuristicEstimator, InMemoryExactCache, InMemorySemanticCache, type JsonSchema, LicenseError, type LicenseGate, type LicenseKeyset, type LicenseStatus, type LicenseTokenPayload, type LocalClassifier, MODELOS_POR_CODIFICACION, MODELS_BY_ENCODING, type MemoryDelta, type MessageRole, MockProvider, type MockProviderOptions, type ModelCascadeMode, type ModelCascadeReport, type ModelCascadeSettings, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OutputContract, PRECIOS_AL_DIA, type Policy, type ProtectedSpan, type Provider, type ProviderRequest, type ProviderResponse, type ProviderUsage, QUALITY_STATUSES, type QualityStatus, type RequestContext, type Reranker, type ResolvedDeps, type ResolvedGate, type ResolvedLicense, ResolverRegistry, type ResolverResult, type RetrievalOptions, type RetrievalOutcome, type RetrievalPlan, type Retriever, type RevocationListBody, type RevocationListVerification, type RevocationPollEvent, RevocationPoller, type RevocationPollerOptions, RevocationSnapshot, type RouteDecision, type SavingsLayer, type SavingsLayerConfig, SavingsLedger, type SavingsReport, type SavingsRequest, type SavingsResult, type SavingsToggles, SchemaRegistry, type SemanticCacheOptions, type SemanticHit, type SemanticRecord, type SemanticVerifier, type SerializationFormat, type Serializer, Singleflight, type TokenEstimator, TokenizerRegistry, type ToolCallRequest, type ToolDescriptor, type ToolRisk, type ToolSelection, ToolSelector, type ToolSelectorOptions, TraceCollector, type TraceEvent, UMBRAL_LOCAL, UsageEmitter, type UsageEmitterOptions, type ValidationError, type ValidationResult, adaptiveK, arithmeticResolver, buildExactKey, buildInflightKey, canonicalize, compactRowsSerializer, compresionFiel, computeNextDelay, cosine, createCompactRowsSerializer, createDefaultResolvers, createHandoff, createMockProvider, createSavingsLayer, csvSerializer, decodeCompactRows, dedupe, defaultTokenizerRegistry, deriveSeatId, deriveStatus, detectCi, embebedorLocal, emptyState, encodeCompactRows, evalArithmetic, evaluatePolicy, executeRetrievalPlan, gateFromKey, heuristicEstimator, isKeyset, isStrictCompatible, jsonCompactSerializer, keyTokensMatch, liveGateFromKey, mergeDelta, modelFamilyOf, multisetEqual, negationCount, noopCompressor, normalizeText, numericTokens, precioDeLista, projectContext, providerNativeBackend, randomId, registerExactTokenizer, registrarTokenizadorExacto, renderState, resolveConstraintBackend, resolveDependencies, resolveLicense, sha256, shouldCompress, stableStringify, uniformColumns, validateAgainstSchema, vectorLocal, verifyCompactSignature, verifyLicenseToken, verifyRevocationList, withProtectedSpans, words };
package/dist/index.js CHANGED
@@ -782,7 +782,7 @@ ng/usage`:void 0);if(a){i=new dt({url:a,serviceAccountKey:t.serviceAccountKey,..
782
782
  {},...t.metering?.maxBatch!=null?{maxBatch:t.metering.maxBatch}:{},...t.metering?.maxBuffer!=null?{maxBuffer:t.metering.maxBuffer}:{},...t.meteringFetch?{fetchImpl:t.meteringFetch}:t.licenseFetch?{fetchImpl:t.
783
783
  licenseFetch}:{},...t.now?{now:t.now}:{},...t.metering?.ci!=null?{ci:t.metering.ci}:{},...t.silenceWarnings!=null?{silenceWarnings:t.silenceWarnings}:{}});let c=t.metering?.ci??cr();if(t.metering?.seatId)
784
784
  i.setSeat(t.metering.seatId,c);else {let l=i;lr(t.serviceAccountKey).then(u=>l.setSeat(u,c)).catch(()=>{});}i.start();}}return {generate:async a=>{let c=await s.generate(a);if(i)try{i.record(c.report);}catch{}
785
- return c},close:()=>{r?.stop(),o?.stop(),i?.stop();}}}var af="0.4.10";/*! Bundled license information:
785
+ return c},close:()=>{r?.stop(),o?.stop(),i?.stop();}}}var af="0.4.12";/*! Bundled license information:
786
786
 
787
787
  @noble/curves/utils.js:
788
788
  @noble/curves/abstract/modular.js:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bivelio/savings-layer",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "BV-SALA — provider-neutral LLM execution optimizer. A decision layer in front of any LLM provider that cuts the cost of every request while preserving required quality, and reports the saving per call with token-level accounting you can check against your bill. Proprietary and confidential — property of BiVelio Inc.",
5
5
  "keywords": [
6
6
  "llm",
@@ -76,7 +76,10 @@
76
76
  "prepublishOnly": "pnpm run build",
77
77
  "ab:publish": "tsx benchmarks/publish.ts",
78
78
  "corpus:arnes": "tsx corpus/arnes/informe.ts",
79
- "corpus:auditar": "tsx corpus/auditoria/auditar.ts"
79
+ "corpus:auditar": "tsx corpus/auditoria/auditar.ts",
80
+ "sombra:corpus": "tsx benchmarks/sombra-corpus.ts",
81
+ "sombra:diales": "tsx --env-file-if-exists=.env.bench benchmarks/sombra-diales.ts",
82
+ "anillo1": "tsx --env-file-if-exists=.env.bench benchmarks/anillo1/arnes.ts"
80
83
  },
81
84
  "devDependencies": {
82
85
  "@noble/curves": "^2.2.0",