@bivelio/savings-layer 0.4.17 → 0.4.19

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,44 +1,16 @@
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 j from'zlib';import {connect}from'net';var de="context-management-2025-06-27";function Pe(){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 ut(t,e){if(e!==void 0&&e!==""&&e!=="identity")return null;try{let n=JSON.parse(t.toString("utf8"));if(n===null||typeof n!="object"||Array.isArray(n)||typeof n.model!="string"||!Array.isArray(
3
- n.messages))return null;let o=cn(n.context_management),r=ln(n.context_management);return n.context_management=un(n.context_management),{cuerpo:Buffer.from(JSON.stringify(n),"utf8"),nuestros:o,triggerDelCliente:r}}catch{
4
- return null}}function cn(t){let e=t!==null&&typeof t=="object"&&!Array.isArray(t)?t.edits:void 0,n=(Array.isArray(e)?e:[]).filter(o=>o!==null&&typeof o=="object"&&!Array.isArray(o)&&o.type===Oe);return ct(
5
- n)!==ct([Pe().edits[0]])}function ln(t){let e=t!==null&&typeof t=="object"&&!Array.isArray(t)?t.edits:void 0,n=(Array.isArray(e)?e:[]).filter(r=>r!==null&&typeof r=="object"&&!Array.isArray(r)&&r.type===
6
- Oe);if(n.length===0)return null;let o=Number.POSITIVE_INFINITY;for(let r of n){let s=r.trigger,i=s!==null&&typeof s=="object"&&s.type==="input_tokens"&&typeof s.value=="number"&&Number.isFinite(s.value)&&
7
- s.value>0?s.value:1e5;i<o&&(o=i);}return o}function ct(t){return JSON.stringify(t,(e,n)=>n!==null&&typeof n=="object"&&!Array.isArray(n)?Object.fromEntries(Object.keys(n).sort().map(o=>[o,n[o]])):n)}var Oe="\
8
- clear_tool_uses_20250919",lt="clear_thinking_20251015";function un(t){let e=Pe().edits[0],n=t!==null&&typeof t=="object"&&!Array.isArray(t)?{...t}:{},o=(Array.isArray(n.edits)?n.edits:[]).filter(i=>i!==
9
- null&&typeof i=="object"&&!Array.isArray(i)&&i.type!==Oe),r=o.filter(i=>i.type===lt),s=o.filter(i=>i.type!==lt);return {...n,edits:[...r,...s,e]}}function dt(t,e){let n=" (se enciende solo si la licenc\
10
- ia de la org trae context_elision; fail-closed)";return t==="0"?{linea:"elisi\xF3n S4a: APAGADA (BVSALA_GATEWAY_ELISION=0) \u2014 brazo CONTROL",aviso:false}:e?t==="1"?{linea:"elisi\xF3n S4a: ARMADA (BVSALA\
11
- _GATEWAY_ELISION=1) \u2014 brazo PALANCA"+n,aviso:false}:{linea:"elisi\xF3n S4a: ARMADA por defecto (sin bandera; =0 la apaga) \u2014 brazo PALANCA"+n,aviso:false}:{linea:"elisi\xF3n S4a: NO SE ARMA \u2014 falta BI\
12
- VELIO_SERVICE_KEY (sin clave no hay org que consultar); este proceso es brazo CONTROL"+(t==="1"?" AUNQUE la bandera diga =1. Abre un terminal nuevo o exporta la clave y relanza":""),aviso:t==="1"}}function pt(t){
13
- return t===void 0||t.trim()===""?de:t.split(",").map(n=>n.trim()).filter(n=>n.length>0).includes(de)?t:`${t},${de}`}var mt=new Set;function O(t,e){mt.has(t)||(mt.add(t),console.warn(e));}var K="0.4.17",ft="x-bvsala-version";var J=class{options;now;flushIntervalMs;maxBatch;maxBuffer;buffer=[];seatId;ci;timer;inflight=null;fallosSeguidos=0;constructor(e){this.options=e,this.now=e.now??(()=>Date.now()),this.flushIntervalMs=
14
- e.flushIntervalMs??15e3,this.maxBatch=e.maxBatch??50,this.maxBuffer=e.maxBuffer??1e3,this.ci=e.ci??false;}setSeat(e,n){e&&(this.seatId=e),this.ci=n;}record(e){this.buffer.push({report:e,at:this.now()}),this.
15
- 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.
16
- flushIntervalMs),this.timer.unref?.());}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0),this.flush();}async stopAndDrain(e){this.timer&&(clearInterval(this.timer),this.timer=void 0);let n=e??
17
- Math.ceil(this.maxBuffer/this.maxBatch)+4,o=0;for(let r=0;r<n&&this.buffer.length>0;r++){let s=this.buffer.length;if(await this.flush(),o=this.buffer.length>=s?o+1:0,o>=2)break}}async flush(){if(this.
18
- inflight)return this.inflight;if(this.buffer.length!==0){this.inflight=this.hacerFlush();try{await this.inflight;}finally{this.inflight=null;}}}async hacerFlush(){let e=this.options.fetchImpl??globalThis.
19
- fetch;if(!e)return;let n=this.buffer.splice(0,this.maxBatch);try{let o=n.map(s=>this.toWire(s)),r=await e(this.options.url,{method:"POST",headers:{"content-type":"application/json",authorization:`Bear\
20
- er ${this.options.serviceAccountKey}`,[ft]:`${this.options.surface??"sdk"}/${K}`},body:JSON.stringify(o)});r.ok?this.fallosSeguidos=0:r.status>=500?(this.fallosSeguidos++,this.requeue(n),this.avisarDeFallo(
21
- `el servidor respondi\xF3 ${r.status}`)):r.status===401||r.status===403?(O(`metering-auth-${r.status}`,`[bv-sala] el env\xEDo de uso est\xE1 siendo rechazado con HTTP ${r.status} en ${this.options.url}\
22
- . Revisa 'serviceAccountKey' (\xBFrotada? \xBFrevocada? \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.`),
23
- this.options.onAuthError?.(r.status)):(this.fallosSeguidos++,this.avisarDeFallo(r.status===404||r.status===405?`HTTP ${r.status}: la URL de env\xEDo parece equivocada`:`el servidor rechaz\xF3 el lote con\
24
- HTTP ${r.status}`));}catch(o){this.fallosSeguidos++,this.requeue(n),this.avisarDeFallo(o instanceof Error?o.message:"error de red");}}avisarDeFallo(e){if(this.options.silenceWarnings)return;let n=this.
25
- fallosSeguidos;n<3||(n-3)%12!==0||console.warn(`[bv-sala] el env\xEDo de uso lleva ${n} intentos seguidos fallando contra ${this.options.url} (${e}). Las peticiones SIGUEN funcionando, pero el uso no \
26
- est\xE1 llegando: el panel dir\xE1 que no ve tr\xE1fico y los asientos facturables saldr\xE1n a cero. Comprueba 'meteringUrl' \u2014 por defecto es \`\${licenseServerUrl}/api/metering/usage\`.`);}requeue(e){
27
- this.buffer=[...e,...this.buffer],this.buffer.length>this.maxBuffer&&(this.buffer.length=this.maxBuffer);}toWire(e){let n=e.report;return {orgId:this.options.orgId??"self",...this.seatId?{seatId:this.seatId}:
28
- {},...this.ci?{ci:true}:{},requestId:n.requestId,model:n.model,at:e.at,avoidedLlm:n.calls.avoidedLlm,actualLlm:n.calls.actualLlm,baselineInputTokens:n.tokens.baselineInput,actualInputTokens:n.tokens.actualInput,
29
- eliminatedInputTokens:n.tokens.eliminatedInput,compressedInputTokens:n.tokens.compressedInput,baselineOutputTokens:n.tokens.baselineOutput,actualOutputTokens:n.tokens.actualOutput,providerCachedInputTokens:n.
30
- tokens.providerCachedInput??0,cacheResult:n.cache.result,...n.cost.eliminatedInputFloorCost!==void 0&&Number.isFinite(n.cost.eliminatedInputFloorCost)&&n.cost.eliminatedInputFloorCost>0&&n.tokens.eliminatedInput>
31
- 0?{eliminatedInputFloorCost:n.cost.eliminatedInputFloorCost}:{},baselineCost:n.cost.baselineEstimate,actualCost:n.cost.actual,netSavings:n.cost.netSavings,...n.cost.basis?{basis:n.cost.basis}:{},...n.
32
- attribution?.sessionId?{sessionId:n.attribution.sessionId}:{},...n.attribution?.agentId?{agentId:n.attribution.agentId}:{}}}};function pe(){return globalThis.process}function dn(t){if(/^[0-9a-f]{12}$/.test(t)||/^\d{1,3}(\.\d{1,3}){3}$/.test(t)||/^ip-\d{1,3}(-\d{1,3}){3}$/i.test(t))return true;let e="[bcdfghjklmnpqrstvwxz2456789\
33
- ]";return new RegExp(`-${e}{8,10}-${e}{5}$`).test(t)}function pn(t){return !!(t.AWS_LAMBDA_FUNCTION_NAME??t.LAMBDA_TASK_ROOT??t.VERCEL??t.VERCEL_ENV??t.K_SERVICE??t.FUNCTION_TARGET??t.FUNCTIONS_WORKER_RUNTIME??
34
- t.NETLIFY)}async function mn(){if(pe()?.execPath)try{let e=await import(["node","os"].join(":")),n=typeof e.hostname=="function"?e.hostname():"";return n.length>0?n:void 0}catch{return}}async function fn(t,e=mn){
35
- if(t.KUBERNETES_SERVICE_HOST||pn(t))return;let n=t.HOSTNAME??t.COMPUTERNAME??await e();if(!(!n||dn(n)))return n}async function hn(){let t=pe();if(!t||!t.env)return;let e=t.env,n=await fn(e),o=[t.platform,
36
- t.arch,t.execPath,n,e.USER??e.USERNAME??e.LOGNAME,e.HOME??e.USERPROFILE].filter(r=>typeof r=="string"&&r.length>0);return o.length?o.join("|"):void 0}var gn=["CI","CONTINUOUS_INTEGRATION","GITHUB_ACTI\
37
- ONS","GITLAB_CI","CIRCLECI","TRAVIS","JENKINS_URL","BUILDKITE","TF_BUILD","TEAMCITY_VERSION","BITBUCKET_BUILD_NUMBER","CODEBUILD_BUILD_ID","HEROKU_TEST_RUN_ID","DRONE"];function me(){let t=pe()?.env;if(!t)
38
- return false;for(let e of gn){let n=t[e];if(n&&n!=="false"&&n!=="0")return true}return false}async function bn(t,e){let n=globalThis.crypto,o=new TextEncoder;if(n?.subtle)try{let i=await n.subtle.importKey("raw",
39
- o.encode(t),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),a=await n.subtle.sign("HMAC",i,o.encode(e));return [...new Uint8Array(a)].map(c=>c.toString(16).padStart(2,"0")).join("")}catch{}let r=2166136261,s=`${t}\
40
- |${e}`;for(let i=0;i<s.length;i++)r^=s.charCodeAt(i),r=Math.imul(r,16777619);return (r>>>0).toString(16).padStart(8,"0")}async function fe(t){let n=pe()?.env?.BVSALA_SEAT_ID;if(n&&vn.test(n))return n;let o=await hn();
41
- if(!o)return;let r=await bn(t,o);if(r)return `m-${r.slice(0,32)}`}var vn=/^[A-Za-z0-9._:/-]{1,128}$/;var he={"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},
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 {randomUUID,createHash}from'crypto';import {createServer}from'http';import*as N from'zlib';import {connect}from'net';var he="context-management-2025-06-27";function De(){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 ft(t,e){if(e!==void 0&&e!==""&&e!=="identity")return null;try{let n=JSON.parse(t.toString("utf8"));if(n===null||typeof n!="object"||Array.isArray(n)||typeof n.model!="string"||!Array.isArray(
3
+ n.messages))return null;let o=bn(n.context_management),r=vn(n.context_management);return n.context_management=yn(n.context_management),{cuerpo:Buffer.from(JSON.stringify(n),"utf8"),nuestros:o,triggerDelCliente:r}}catch{
4
+ return null}}function bn(t){let e=t!==null&&typeof t=="object"&&!Array.isArray(t)?t.edits:void 0,n=(Array.isArray(e)?e:[]).filter(o=>o!==null&&typeof o=="object"&&!Array.isArray(o)&&o.type===Me);return pt(
5
+ n)!==pt([De().edits[0]])}function vn(t){let e=t!==null&&typeof t=="object"&&!Array.isArray(t)?t.edits:void 0,n=(Array.isArray(e)?e:[]).filter(r=>r!==null&&typeof r=="object"&&!Array.isArray(r)&&r.type===
6
+ Me);if(n.length===0)return null;let o=Number.POSITIVE_INFINITY;for(let r of n){let s=r.trigger,i=s!==null&&typeof s=="object"&&s.type==="input_tokens"&&typeof s.value=="number"&&Number.isFinite(s.value)&&
7
+ s.value>0?s.value:1e5;i<o&&(o=i);}return o}function pt(t){return JSON.stringify(t,(e,n)=>n!==null&&typeof n=="object"&&!Array.isArray(n)?Object.fromEntries(Object.keys(n).sort().map(o=>[o,n[o]])):n)}var Me="\
8
+ clear_tool_uses_20250919",mt="clear_thinking_20251015";function yn(t){let e=De().edits[0],n=t!==null&&typeof t=="object"&&!Array.isArray(t)?{...t}:{},o=(Array.isArray(n.edits)?n.edits:[]).filter(i=>i!==
9
+ null&&typeof i=="object"&&!Array.isArray(i)&&i.type!==Me),r=o.filter(i=>i.type===mt),s=o.filter(i=>i.type!==mt);return {...n,edits:[...r,...s,e]}}function ht(t,e,n=false){let o=" (rebaja de TTL activa si \
10
+ la licencia trae cache_ttl_tuning; fail-closed)",r=n?" \xB7 DIALES DE ELISI\xD3N ARMADOS A MANO (BVSALA_GATEWAY_DIALES_ELISION=1): miden p\xE9rdida, R=4,05 vs R*=0,0127":" \xB7 diales de elisi\xF3n APAGADOS";
11
+ return t==="0"?{linea:"canal S4a: CERRADO (BVSALA_GATEWAY_ELISION=0) \u2014 sin rebaja de TTL y sin diales",aviso:false}:e?{linea:(t==="1"?"canal S4a: ABIERTO (BVSALA_GATEWAY_ELISION=1)":"canal S4a: ABIE\
12
+ RTO por defecto (=0 lo cierra)")+o+r,aviso:n}:{linea:"canal S4a: NO SE ABRE \u2014 falta BIVELIO_SERVICE_KEY (sin clave no hay org que consultar); ni rebaja de TTL ni diales"+(t==="1"?". Abre un termi\
13
+ nal nuevo o exporta la clave y relanza":""),aviso:t==="1"}}function gt(t){return t===void 0||t.trim()===""?he:t.split(",").map(n=>n.trim()).filter(n=>n.length>0).includes(he)?t:`${t},${he}`}var ge={"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},
42
14
  "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,
43
15
  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},
44
16
  "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},
@@ -55,158 +27,202 @@ able-5":{inputPer1k:.01,outputPer1k:.05,cachedInputPer1k:.001},"claude-fable-5-1
55
27
  cachedInputPer1k:1e-4},"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,
56
28
  outputPer1k:.075,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},"g\
57
29
  emini-3.5-flash":{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,
58
- outputPer1k:.012,cachedInputPer1k:2e-4},"gemini-2.5-pro":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},"gemini-2.5-flash":{inputPer1k:3e-4,outputPer1k:.0025,cachedInputPer1k:3e-5}};function ht(t,e,n){
30
+ outputPer1k:.012,cachedInputPer1k:2e-4},"gemini-2.5-pro":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},"gemini-2.5-flash":{inputPer1k:3e-4,outputPer1k:.0025,cachedInputPer1k:3e-5}};function Le(t,e,n){
59
31
  if(!n)return;let o=t[n];if(o)return o;let r=n.lastIndexOf("/"),s=r>=0?n.slice(r+1):n,i=t[s];if(i)return i;for(let a of e){if(!s.startsWith(a))continue;let c=s.charAt(a.length);if(c!==""&&c!=="-"&&c!==
60
- "."&&c!=="_")continue;let p=s.slice(a.length+1);if(!(/^\d/.test(p)&&!/^\d{4}/.test(p)))return t[a]}}function De(t){return Object.keys(t).sort((e,n)=>n.length-e.length)}var yn=De(he);function B(t){return ht(
61
- he,yn,t)}Object.fromEntries(Object.keys(he).map(t=>[t,t]));function W(t){let e=t.toLowerCase();return e.startsWith("gpt-")||e.startsWith("o1")||e.startsWith("o3")||e.startsWith("o4")?/^gpt-5\.6/.test(e)?1.25:1:e.startsWith("gemini")?1:1.25}function Me(t){let e=t.
62
- toLowerCase();return e.startsWith("claude")||e.startsWith("anthropic/")?2:W(t)}var U=class{resto="";uso=null;elisionObservada=null;eventos={};observar(e){this.resto+=typeof e=="string"?e:e.toString("utf8");let n;for(;(n=this.resto.indexOf(`
32
+ "."&&c!=="_")continue;let m=s.slice(a.length+1);if(!(/^\d/.test(m)&&!/^\d{4}/.test(m)))return t[a]}}function je(t){return Object.keys(t).sort((e,n)=>n.length-e.length)}var bt=je(ge);function L(t){return Le(
33
+ ge,bt,t)}var kn=Object.fromEntries(Object.keys(ge).map(t=>[t,t]));function vt(t){return Le(kn,bt,t)}function $(t){let e=t.toLowerCase();return e.startsWith("gpt-")||e.startsWith("o1")||e.startsWith("o3")||e.startsWith("o4")?/^gpt-5\.6/.test(e)?1.25:1:e.startsWith("gemini")?1:1.25}function $e(t){let e=t.
34
+ toLowerCase();return e.startsWith("claude")||e.startsWith("anthropic/")?2:$(t)}var Sn=.3,wn=4096,En=(t,e)=>t==="cache_control"?void 0:e;function Ne(t){return t===void 0?"":JSON.stringify(t,En)??""}function Tn(t){return Array.isArray(t)?t.filter(e=>!(e!==null&&typeof e=="object"&&
35
+ e.defer_loading===true)):t}function ze(t){return createHash("sha1").update(t).digest("base64url").slice(0,16)}function ie(t,e){if(e!==void 0&&e!==""&&e!=="identity")return null;try{let n=JSON.parse(t.toString("\
36
+ utf8"));if(n===null||typeof n!="object"||Array.isArray(n))return null;let o=n;return typeof o.model!="string"||!Array.isArray(o.messages)?null:o}catch{return null}}function yt(t){let e=Ne(t.system),n=Ne(
37
+ Tn(t.tools)),o=Array.isArray(t.messages)?t.messages.slice(0,wn):[],r=[],s=[];for(let i of o){let a=Ne(i);r.push(ze(a)),s.push(Buffer.byteLength(a,"utf8"));}return {system:ze(e),tools:ze(n),mensajes:r,bytes:s,
38
+ bytesFijos:Buffer.byteLength(e,"utf8")+Buffer.byteLength(n,"utf8")}}function kt(t,e){if(t===void 0||t.system!==e.system||t.tools!==e.tools)return 1;let n=e.bytesFijos;for(let s of e.bytes)n+=s;if(n<=0)
39
+ return 1;let o=0;for(;o<t.mensajes.length&&o<e.mensajes.length&&t.mensajes[o]===e.mensajes[o];)o++;let r=0;for(let s=o;s<e.bytes.length;s++)r+=e.bytes[s]??0;return r/n}function xt(t){let{fraccionNueva:e,
40
+ umbral:n=Sn}=t;return e>=n}function Be(t,e){if(t===null||typeof t!="object")return;if(Array.isArray(t)){for(let r of t)Be(r,e);return}let n=t,o=n.cache_control;if(o!==null&&typeof o=="object"&&!Array.
41
+ isArray(o)){let r=o;r.ttl==="1h"?(r.ttl="5m",e.rebajadas++):(r.ttl==="5m"||r.ttl===void 0)&&e.yaEran5m++;}for(let[r,s]of Object.entries(n))r!=="cache_control"&&s!==null&&typeof s=="object"&&Be(s,e);}function St(t,e){
42
+ let n=Buffer.isBuffer(t)?ie(t,e):t;if(n===null)return null;try{let o={rebajadas:0,yaEran5m:0};for(let r of ["system","messages","tools"])Be(n[r],o);return o.rebajadas===0?null:{cuerpo:Buffer.from(JSON.
43
+ stringify(n),"utf8"),rebajadas:o.rebajadas,yaEran5m:o.yaEran5m}}catch{return null}}var be=class{constructor(e=512,n=3600*1e3){this.maxEntradas=e;this.maxEdadMs=n;}maxEntradas;maxEdadMs;visto=new Map;ultima(e,n){let o=this.visto.get(e);if(o!==void 0){if(n-o.vistoMs>this.maxEdadMs){this.
44
+ visto.delete(e);return}return o.huella}}anotar(e,n,o){for(this.visto.delete(e),this.visto.set(e,{huella:n,vistoMs:o});this.visto.size>this.maxEntradas;){let r=this.visto.keys().next();if(r.done===true)break;
45
+ this.visto.delete(r.value);}}get tamano(){return this.visto.size}};var wt={"claude-fable-5":"claude-fable-5-1"};function An(t,e){let n=L(t),o=L(e);if(n===void 0||o===void 0||n.inputPer1k!==o.inputPer1k||n.outputPer1k!==o.outputPer1k||$(t)!==$(e))return false;let r=n.cachedInputPer1k??
46
+ n.inputPer1k;return (o.cachedInputPer1k??o.inputPer1k)<r}function Cn(t){let e=vt(t);if(e===void 0||e!==t)return null;let n=wt[e];return n===void 0||n===e||!An(e,n)?null:{solicitado:t,servido:n}}var _n=/(^|,)\s*context-1m/i;
47
+ function Rn(t){let e=t.tool_choice;if(e===null||typeof e!="object")return false;let n=e.type;return n==="any"||n==="tool"}function Et(t,e,n={}){if(n.betas!==void 0&&_n.test(n.betas))return null;let o=ie(t,
48
+ e);if(o===null||Rn(o))return null;let r=Cn(o.model);return r===null?null:(o.model=r.servido,{cuerpo:Buffer.from(JSON.stringify(o),"utf8"),cambio:r})}function Tt(t,e,n){let o=Object.entries(wt).map(([r,
49
+ s])=>`${r}\u2192${s}`).join(", ");return t!=="1"?{linea:"modelo hermano (C): APAGADO (BVSALA_GATEWAY_MODELO_HERMANO=1 lo arma)",aviso:false}:e?n?{linea:`modelo hermano (C): ARMADO (${o}; activo si la lic\
50
+ encia trae sibling_model_routing; fail-closed). Cambia el model que ves en la respuesta; lectura de cach\xE9 a 0,025\xD7 en vez de 0,1\xD7 (cat\xE1logo). Encendido a mitad de un hilo paga una escritura fr\xEDa del p\
51
+ refijo una vez. Si el proveedor rechaza (400) la petici\xF3n reescrita, se reenv\xEDa intacta una vez`,aviso:false}:{linea:"modelo hermano (C): NO SE ARMA \u2014 el canal S4a est\xE1 CERRADO (BVSALA_GATEWAY_ELIS\
52
+ ION=0 apaga las tres palancas)",aviso:true}:{linea:"modelo hermano (C): NO SE ARMA \u2014 falta BIVELIO_SERVICE_KEY (sin clave no hay org que consultar). Abre un terminal nuevo o exporta la clave y relanza",
53
+ aviso:true}}var At=new Set;function M(t,e){At.has(t)||(At.add(t),console.warn(e));}var Y="0.4.19",Ct="x-bvsala-version";var Q=class{options;now;flushIntervalMs;maxBatch;maxBuffer;buffer=[];seatId;ci;timer;inflight=null;fallosSeguidos=0;constructor(e){this.options=e,this.now=e.now??(()=>Date.now()),this.flushIntervalMs=
54
+ e.flushIntervalMs??15e3,this.maxBatch=e.maxBatch??50,this.maxBuffer=e.maxBuffer??1e3,this.ci=e.ci??false;}setSeat(e,n){e&&(this.seatId=e),this.ci=n;}record(e){this.buffer.push({report:e,at:this.now()}),this.
55
+ 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.
56
+ flushIntervalMs),this.timer.unref?.());}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0),this.flush();}async stopAndDrain(e){this.timer&&(clearInterval(this.timer),this.timer=void 0);let n=e??
57
+ Math.ceil(this.maxBuffer/this.maxBatch)+4,o=0;for(let r=0;r<n&&this.buffer.length>0;r++){let s=this.buffer.length;if(await this.flush(),o=this.buffer.length>=s?o+1:0,o>=2)break}}async flush(){if(this.
58
+ inflight)return this.inflight;if(this.buffer.length!==0){this.inflight=this.hacerFlush();try{await this.inflight;}finally{this.inflight=null;}}}async hacerFlush(){let e=this.options.fetchImpl??globalThis.
59
+ fetch;if(!e)return;let n=this.buffer.splice(0,this.maxBatch);try{let o=n.map(s=>this.toWire(s)),r=await e(this.options.url,{method:"POST",headers:{"content-type":"application/json",authorization:`Bear\
60
+ er ${this.options.serviceAccountKey}`,[Ct]:`${this.options.surface??"sdk"}/${Y}`},body:JSON.stringify(o)});r.ok?this.fallosSeguidos=0:r.status>=500?(this.fallosSeguidos++,this.requeue(n),this.avisarDeFallo(
61
+ `el servidor respondi\xF3 ${r.status}`)):r.status===401||r.status===403?(M(`metering-auth-${r.status}`,`[bv-sala] el env\xEDo de uso est\xE1 siendo rechazado con HTTP ${r.status} en ${this.options.url}\
62
+ . Revisa 'serviceAccountKey' (\xBFrotada? \xBFrevocada? \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.`),
63
+ this.options.onAuthError?.(r.status)):(this.fallosSeguidos++,this.avisarDeFallo(r.status===404||r.status===405?`HTTP ${r.status}: la URL de env\xEDo parece equivocada`:`el servidor rechaz\xF3 el lote con\
64
+ HTTP ${r.status}`));}catch(o){this.fallosSeguidos++,this.requeue(n),this.avisarDeFallo(o instanceof Error?o.message:"error de red");}}avisarDeFallo(e){if(this.options.silenceWarnings)return;let n=this.
65
+ fallosSeguidos;n<3||(n-3)%12!==0||console.warn(`[bv-sala] el env\xEDo de uso lleva ${n} intentos seguidos fallando contra ${this.options.url} (${e}). Las peticiones SIGUEN funcionando, pero el uso no \
66
+ est\xE1 llegando: el panel dir\xE1 que no ve tr\xE1fico y los asientos facturables saldr\xE1n a cero. Comprueba 'meteringUrl' \u2014 por defecto es \`\${licenseServerUrl}/api/metering/usage\`.`);}requeue(e){
67
+ this.buffer=[...e,...this.buffer],this.buffer.length>this.maxBuffer&&(this.buffer.length=this.maxBuffer);}toWire(e){let n=e.report;return {orgId:this.options.orgId??"self",...this.seatId?{seatId:this.seatId}:
68
+ {},...this.ci?{ci:true}:{},requestId:n.requestId,model:n.model,at:e.at,avoidedLlm:n.calls.avoidedLlm,actualLlm:n.calls.actualLlm,baselineInputTokens:n.tokens.baselineInput,actualInputTokens:n.tokens.actualInput,
69
+ eliminatedInputTokens:n.tokens.eliminatedInput,compressedInputTokens:n.tokens.compressedInput,baselineOutputTokens:n.tokens.baselineOutput,actualOutputTokens:n.tokens.actualOutput,providerCachedInputTokens:n.
70
+ tokens.providerCachedInput??0,cacheResult:n.cache.result,...n.cost.eliminatedInputFloorCost!==void 0&&Number.isFinite(n.cost.eliminatedInputFloorCost)&&n.cost.eliminatedInputFloorCost>0&&n.tokens.eliminatedInput>
71
+ 0?{eliminatedInputFloorCost:n.cost.eliminatedInputFloorCost}:{},baselineCost:n.cost.baselineEstimate,actualCost:n.cost.actual,netSavings:n.cost.netSavings,...n.cost.basis?{basis:n.cost.basis}:{},...n.
72
+ attribution?.sessionId?{sessionId:n.attribution.sessionId}:{},...n.attribution?.agentId?{agentId:n.attribution.agentId}:{}}}};function ye(){return globalThis.process}function In(t){if(/^[0-9a-f]{12}$/.test(t)||/^\d{1,3}(\.\d{1,3}){3}$/.test(t)||/^ip-\d{1,3}(-\d{1,3}){3}$/i.test(t))return true;let e="[bcdfghjklmnpqrstvwxz2456789\
73
+ ]";return new RegExp(`-${e}{8,10}-${e}{5}$`).test(t)}function Pn(t){return !!(t.AWS_LAMBDA_FUNCTION_NAME??t.LAMBDA_TASK_ROOT??t.VERCEL??t.VERCEL_ENV??t.K_SERVICE??t.FUNCTION_TARGET??t.FUNCTIONS_WORKER_RUNTIME??
74
+ t.NETLIFY)}async function On(){if(ye()?.execPath)try{let e=await import(["node","os"].join(":")),n=typeof e.hostname=="function"?e.hostname():"";return n.length>0?n:void 0}catch{return}}async function Dn(t,e=On){
75
+ if(t.KUBERNETES_SERVICE_HOST||Pn(t))return;let n=t.HOSTNAME??t.COMPUTERNAME??await e();if(!(!n||In(n)))return n}async function Mn(){let t=ye();if(!t||!t.env)return;let e=t.env,n=await Dn(e),o=[t.platform,
76
+ t.arch,t.execPath,n,e.USER??e.USERNAME??e.LOGNAME,e.HOME??e.USERPROFILE].filter(r=>typeof r=="string"&&r.length>0);return o.length?o.join("|"):void 0}var Ln=["CI","CONTINUOUS_INTEGRATION","GITHUB_ACTI\
77
+ ONS","GITLAB_CI","CIRCLECI","TRAVIS","JENKINS_URL","BUILDKITE","TF_BUILD","TEAMCITY_VERSION","BITBUCKET_BUILD_NUMBER","CODEBUILD_BUILD_ID","HEROKU_TEST_RUN_ID","DRONE"];function ke(){let t=ye()?.env;if(!t)
78
+ return false;for(let e of Ln){let n=t[e];if(n&&n!=="false"&&n!=="0")return true}return false}async function jn(t,e){let n=globalThis.crypto,o=new TextEncoder;if(n?.subtle)try{let i=await n.subtle.importKey("raw",
79
+ o.encode(t),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),a=await n.subtle.sign("HMAC",i,o.encode(e));return [...new Uint8Array(a)].map(c=>c.toString(16).padStart(2,"0")).join("")}catch{}let r=2166136261,s=`${t}\
80
+ |${e}`;for(let i=0;i<s.length;i++)r^=s.charCodeAt(i),r=Math.imul(r,16777619);return (r>>>0).toString(16).padStart(8,"0")}async function xe(t){let n=ye()?.env?.BVSALA_SEAT_ID;if(n&&$n.test(n))return n;let o=await Mn();
81
+ if(!o)return;let r=await jn(t,o);if(r)return `m-${r.slice(0,32)}`}var $n=/^[A-Za-z0-9._:/-]{1,128}$/;var q=class{resto="";uso=null;elisionObservada=null;eventos={};observar(e){this.resto+=typeof e=="string"?e:e.toString("utf8");let n;for(;(n=this.resto.indexOf(`
63
82
 
64
83
  `))>=0;){let o=this.resto.slice(0,n);this.resto=this.resto.slice(n+2);let r=/^event: (.+)$/m.exec(o)?.[1];if(r&&(this.eventos[r]=(this.eventos[r]??0)+1),r!=="message_start"&&r!=="message_delta")continue;
65
- let s=/^data: (.+)$/m.exec(o)?.[1];if(s)try{let i=JSON.parse(s),a=gt(i.context_management);a&&(this.elisionObservada=a);let c=i.usage??i.message?.usage;if(c){let p=c.cache_creation||this.uso?.cache_creation?
66
- {...this.uso?.cache_creation,...c.cache_creation}:void 0;this.uso={...this.uso,...c,...p?{cache_creation:p}:{}};}}catch{}}}usage(){return this.uso}usageFinal(){return (this.eventos.message_delta??0)>0?this.
67
- uso:null}elision(){return this.elisionObservada}};function kn(t,e){if(!e||e.atribuible!==true||!(e.tokensLimpiadosToolUses>0))return 0;let n=t.cachedInputPer1k;return typeof n!="number"||!Number.isFinite(
68
- n)||n<=0?0:e.tokensLimpiadosToolUses/1e3*n}function gt(t){if(t===null||typeof t!="object")return null;let e=t.applied_edits;if(!Array.isArray(e)||e.length===0)return null;let n=0,o=0;for(let r of e){let s=r.
69
- cleared_input_tokens;typeof s=="number"&&Number.isFinite(s)&&s>0&&(n+=s,r.type==="clear_tool_uses_20250919"&&(o+=s));}return {borrados:e.length,tokensLimpiados:n,tokensLimpiadosToolUses:o}}function bt(t){
70
- try{let e=JSON.parse(typeof t=="string"?t:t.toString("utf8"));return gt(e.context_management)}catch{return null}}var ge=class{resto="";uso=null;eventos={};observar(e){this.resto+=typeof e=="string"?e:
84
+ let s=/^data: (.+)$/m.exec(o)?.[1];if(s)try{let i=JSON.parse(s),a=_t(i.context_management);a&&(this.elisionObservada=a);let c=i.usage??i.message?.usage;if(c){let m=c.cache_creation||this.uso?.cache_creation?
85
+ {...this.uso?.cache_creation,...c.cache_creation}:void 0;this.uso={...this.uso,...c,...m?{cache_creation:m}:{}};}}catch{}}}usage(){return this.uso}usageFinal(){return (this.eventos.message_delta??0)>0?this.
86
+ uso:null}elision(){return this.elisionObservada}};function Nn(t,e){if(!e||e.atribuible!==true||!(e.tokensLimpiadosToolUses>0))return 0;let n=t.cachedInputPer1k;return typeof n!="number"||!Number.isFinite(
87
+ n)||n<=0?0:e.tokensLimpiadosToolUses/1e3*n}function _t(t){if(t===null||typeof t!="object")return null;let e=t.applied_edits;if(!Array.isArray(e)||e.length===0)return null;let n=0,o=0;for(let r of e){let s=r.
88
+ cleared_input_tokens;typeof s=="number"&&Number.isFinite(s)&&s>0&&(n+=s,r.type==="clear_tool_uses_20250919"&&(o+=s));}return {borrados:e.length,tokensLimpiados:n,tokensLimpiadosToolUses:o}}function Rt(t){
89
+ try{let e=JSON.parse(typeof t=="string"?t:t.toString("utf8"));return _t(e.context_management)}catch{return null}}var Se=class{resto="";uso=null;eventos={};observar(e){this.resto+=typeof e=="string"?e:
71
90
  e.toString("utf8");let n;for(;(n=this.resto.indexOf(`
72
91
 
73
92
  `))>=0;){let o=this.resto.slice(0,n);this.resto=this.resto.slice(n+2);let r=/^event: (.+)$/m.exec(o)?.[1];r&&(this.eventos[r]=(this.eventos[r]??0)+1);let s=/^data: (.+)$/m.exec(o)?.[1];if(s)try{let i=JSON.
74
- parse(s);if((r??i.type)!=="response.completed")continue;let a=i.response?.usage;a&&(this.uso=xn(a));}catch{}}}usage(){return this.uso}usageFinal(){return this.uso}};function xn(t){let e=Math.max(0,t.input_tokens??
93
+ parse(s);if((r??i.type)!=="response.completed")continue;let a=i.response?.usage;a&&(this.uso=zn(a));}catch{}}}usage(){return this.uso}usageFinal(){return this.uso}};function zn(t){let e=Math.max(0,t.input_tokens??
75
94
  0),n=Math.min(Math.max(0,t.input_tokens_details?.cached_tokens??0),e),o=Math.min(Math.max(0,t.input_tokens_details?.cache_write_tokens??0),e-n);return {input_tokens:e-n-o,output_tokens:Math.max(0,t.output_tokens??
76
- 0),cache_read_input_tokens:n,cache_creation_input_tokens:o}}function vt(t,e){let n=B(t);if(!n)return null;let o=e.input_tokens??0,r=e.output_tokens??0,s=e.cache_read_input_tokens??0,i=e.cache_creation,
77
- a=e.cache_creation_input_tokens??(i?.ephemeral_5m_input_tokens??0)+(i?.ephemeral_1h_input_tokens??0),c=Math.min(i?.ephemeral_1h_input_tokens??0,a),p=n.cachedInputPer1k??n.inputPer1k;return {costeUsd:o/
78
- 1e3*n.inputPer1k+s/1e3*p+(a-c)/1e3*n.inputPer1k*W(t)+c/1e3*n.inputPer1k*2+r/1e3*n.outputPer1k,precio:n,tokens:{entrada:o,salida:r,cacheLeida:s,cacheEscrita:a,cacheEscrita1h:c}}}function yt(t,e){let o=je(
79
- t,e)?.model;return typeof o=="string"?o:""}function je(t,e){try{let n=t,o={maxOutputLength:Sn};switch((e??"").trim().toLowerCase()){case "gzip":case "x-gzip":n=j.gunzipSync(t,o);break;case "deflate":n=j.inflateSync(
80
- t,o);break;case "br":n=j.brotliDecompressSync(t,o);break;case "zstd":{let r=j.zstdDecompressSync;if(typeof r!="function")return null;n=r(t,o);break}default:break}return JSON.parse(n.toString("utf8"))}catch{
81
- return null}}var Sn=5*1024*1024;function kt(){return typeof j.zstdDecompressSync=="function"}function $e(t){try{return JSON.parse(typeof t=="string"?t:t.toString("utf8")).usage??null}catch{return null}}
82
- function xt(t,e,n,o,r,s){return Tt(t,e,n,false,o,r,s)}function St(t,e,n,o){return Tt(t,e,n,true,o)}function wt(t,e,n,o,r){return {requestId:t,model:e,...r&&(r.sessionId||r.agentId)?{attribution:r}:{},calls:{
83
- avoidedLlm:0,actualLlm:0},tokens:{baselineInput:0,actualInput:0,eliminatedInput:0,compressedInput:0,baselineOutput:0,actualOutput:0,providerCachedInput:0},cache:{result:"miss"},cost:{baselineEstimate:n,
84
- actual:o,netSavings:n>0?Math.max(-100,Math.min(1,(n-o)/n)):0,basis:"shadow"}}}function Tt(t,e,n,o,r,s,i){let a=n.tokens.entrada+n.tokens.cacheLeida+n.tokens.cacheEscrita,c=n.tokens.cacheEscrita-n.tokens.
85
- cacheEscrita1h,p=!o&&i&&i.rebajadas>0&&i.yaEran5m===0&&c>0?c/1e3*n.precio.inputPer1k*(2-1.25):0,f=n.costeUsd+p,l=o?0:kn(n.precio,s);return {requestId:t,model:e,...r&&(r.sessionId||r.agentId)?{attribution:r}:
86
- {},calls:o?{avoidedLlm:1,actualLlm:0}:{avoidedLlm:0,actualLlm:1},tokens:{baselineInput:a,actualInput:o?0:a,eliminatedInput:o?0:s?.tokensLimpiados??0,compressedInput:0,baselineOutput:n.tokens.salida,actualOutput:o?
87
- 0:n.tokens.salida,providerCachedInput:o?0:n.tokens.cacheLeida},cache:{result:o?"singleflight":"miss"},cost:o?{baselineEstimate:n.costeUsd,actual:0,netSavings:1,basis:"estimated"}:{baselineEstimate:f,actual:n.
88
- costeUsd,netSavings:f>0?Math.max(-100,Math.min(1,p/f)):0,basis:"measured",...l>0?{eliminatedInputFloorCost:l}:{}}}}var wn=1024,se=120,Tn=8,En=256*1024,Cn=/error|exception|traceback|warn|fatal|fail|panic|assert|denied|refused|timeout|\bat\s+\S+:\d+/i,At=/^\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)/;
89
- function An(t){return Buffer.byteLength(typeof t=="string"?t:JSON.stringify(t??""))}function _n(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>e&&typeof e=="object"&&typeof e.text=="string"?
95
+ 0),cache_read_input_tokens:n,cache_creation_input_tokens:o}}function It(t,e,n){let o=t.cachedInputPer1k??t.inputPer1k;return e.entrada/1e3*t.inputPer1k+e.cacheLeida/1e3*o+(e.cacheEscrita-e.cacheEscrita1h)/
96
+ 1e3*t.inputPer1k*$(n)+e.cacheEscrita1h/1e3*t.inputPer1k*2+e.salida/1e3*t.outputPer1k}function Pt(t,e){let n=L(t);if(!n)return null;let o=e.input_tokens??0,r=e.output_tokens??0,s=e.cache_read_input_tokens??
97
+ 0,i=e.cache_creation,a=e.cache_creation_input_tokens??(i?.ephemeral_5m_input_tokens??0)+(i?.ephemeral_1h_input_tokens??0),c=Math.min(i?.ephemeral_1h_input_tokens??0,a),m={entrada:o,salida:r,cacheLeida:s,
98
+ cacheEscrita:a,cacheEscrita1h:c};return {costeUsd:It(n,m,t),precio:n,tokens:m}}function Ot(t,e){let o=Ve(t,e)?.model;return typeof o=="string"?o:""}function Ve(t,e){try{let n=t,o={maxOutputLength:Bn};switch((e??
99
+ "").trim().toLowerCase()){case "gzip":case "x-gzip":n=N.gunzipSync(t,o);break;case "deflate":n=N.inflateSync(t,o);break;case "br":n=N.brotliDecompressSync(t,o);break;case "zstd":{let r=N.zstdDecompressSync;
100
+ if(typeof r!="function")return null;n=r(t,o);break}default:break}return JSON.parse(n.toString("utf8"))}catch{return null}}var Bn=5*1024*1024;function Dt(){return typeof N.zstdDecompressSync=="function"}
101
+ function Fe(t){try{return JSON.parse(typeof t=="string"?t:t.toString("utf8")).usage??null}catch{return null}}function Mt(t,e,n,o,r,s,i){return $t(t,e,n,false,o,r,s,i)}function Lt(t,e,n,o){return $t(t,e,n,
102
+ true,o)}function jt(t,e,n,o,r){return {requestId:t,model:e,...r&&(r.sessionId||r.agentId)?{attribution:r}:{},calls:{avoidedLlm:0,actualLlm:0},tokens:{baselineInput:0,actualInput:0,eliminatedInput:0,compressedInput:0,
103
+ baselineOutput:0,actualOutput:0,providerCachedInput:0},cache:{result:"miss"},cost:{baselineEstimate:n,actual:o,netSavings:n>0?Math.max(-100,Math.min(1,(n-o)/n)):0,basis:"shadow"}}}function Un(t,e){let n=L(
104
+ t.solicitado);return n===void 0?0:Math.max(0,It(n,e.tokens,t.solicitado)-e.costeUsd)}function $t(t,e,n,o,r,s,i,a){let c=n.tokens.entrada+n.tokens.cacheLeida+n.tokens.cacheEscrita,m=n.tokens.cacheEscrita-
105
+ n.tokens.cacheEscrita1h,h=!o&&i&&i.rebajadas>0&&i.yaEran5m===0&&m>0?m/1e3*n.precio.inputPer1k*(2-1.25):0,l=!o&&a?Un(a,n):0,f=n.costeUsd+h+l,u=h+l,d=o?0:Nn(n.precio,s);return {requestId:t,model:e,...r&&
106
+ (r.sessionId||r.agentId)?{attribution:r}:{},calls:o?{avoidedLlm:1,actualLlm:0}:{avoidedLlm:0,actualLlm:1},tokens:{baselineInput:c,actualInput:o?0:c,eliminatedInput:o?0:s?.tokensLimpiados??0,compressedInput:0,
107
+ baselineOutput:n.tokens.salida,actualOutput:o?0:n.tokens.salida,providerCachedInput:o?0:n.tokens.cacheLeida},cache:{result:o?"singleflight":"miss"},cost:o?{baselineEstimate:n.costeUsd,actual:0,netSavings:1,
108
+ basis:"estimated"}:{baselineEstimate:f,actual:n.costeUsd,netSavings:f>0?Math.max(-100,Math.min(1,u/f)):0,basis:"measured",...d>0?{eliminatedInputFloorCost:d}:{}}}}var Vn=1024,ae=120,Fn=8,Hn=256*1024,qn=/error|exception|traceback|warn|fatal|fail|panic|assert|denied|refused|timeout|\bat\s+\S+:\d+/i,Bt=/^\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)/;
109
+ function Kn(t){return Buffer.byteLength(typeof t=="string"?t:JSON.stringify(t??""))}function Jn(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>e&&typeof e=="object"&&typeof e.text=="string"?
90
110
  e.text:"").join(`
91
- `):""}var Rn=/^\s*\d+[\t→]/;function _t(t){return t.replace(Rn,"")}function In(t){if(!t)return "otro";let e=t.split(`
92
- `),n=Math.max(1,e.length),o=0,r=0,s=0;for(let i of e){let a=_t(i);(/^[+-](?![+-])/.test(a)||a.startsWith("@@")||a.startsWith("diff --git"))&&(o+=1),At.test(a)&&(r+=1),(/^\s*(\d{4}-\d{2}-\d{2}|\[\d|\d{2}:\d{2}:\d{2})/.
93
- test(a)||/\b(INFO|DEBUG|TRACE|WARN|ERROR)\b/.test(a))&&(s+=1);}return o/n>.25?"diff":s/n>.3?"log":r/n>.08?"codigo":"otro"}function Pn(t,e){if(e==="diff"||e==="otro")return Buffer.byteLength(t);let n=t.
111
+ `):""}var Wn=/^\s*\d+[\t→]/;function Ut(t){return t.replace(Wn,"")}function Gn(t){if(!t)return "otro";let e=t.split(`
112
+ `),n=Math.max(1,e.length),o=0,r=0,s=0;for(let i of e){let a=Ut(i);(/^[+-](?![+-])/.test(a)||a.startsWith("@@")||a.startsWith("diff --git"))&&(o+=1),Bt.test(a)&&(r+=1),(/^\s*(\d{4}-\d{2}-\d{2}|\[\d|\d{2}:\d{2}:\d{2})/.
113
+ test(a)||/\b(INFO|DEBUG|TRACE|WARN|ERROR)\b/.test(a))&&(s+=1);}return o/n>.25?"diff":s/n>.3?"log":r/n>.08?"codigo":"otro"}function Yn(t,e){if(e==="diff"||e==="otro")return Buffer.byteLength(t);let n=t.
94
114
  split(`
95
- `),o=new Set;for(let s=0;s<n.length;s++){let i=_t(n[s]);(e==="log"?Cn.test(i):At.test(i))&&(o.add(s),e==="log"&&(s>0&&o.add(s-1),s<n.length-1&&o.add(s+1)));}let r=se;for(let s of o)r+=Buffer.byteLength(
96
- n[s])+1;return Math.min(r,Buffer.byteLength(t))}var On=(t,e)=>t==="cache_control"?void 0:e;function Dn(t){if(typeof t=="string")return `text:${t}`;if(!t||typeof t!="object"||Array.isArray(t))return `jso\
97
- n:${JSON.stringify(t??"")}`;let e=t;return e.type==="text"&&typeof e.text=="string"&&Object.keys(e).every(n=>n==="type"||n==="text"||n==="cache_control")?`text:${e.text}`:`json:${JSON.stringify(e,On)}`}
98
- function Mn(t){return createHash("sha256").update(Dn(t)).digest("hex").slice(0,16)}function Ln(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t.cache_control;return !e||typeof e!="object"?null:
99
- e.ttl==="1h"?"1h":"5m"}function Rt(t){let e=[],n=(o,r)=>{let s=An(r),i={clave:Mn(r),tipo:o,marca:Ln(r),bytes:s,bytesV1:s,clase:"otro",esError:false};if(o.endsWith(":tool_result")&&r&&typeof r=="object"){
100
- let a=r;i.esError=a.is_error===true;let c=_n(a.content);i.clase=In(c);let p=s-Buffer.byteLength(c);i.bytesV1=Math.min(s,Math.max(0,p)+Pn(c,i.clase));}e.push(i);};if(Array.isArray(t.tools))for(let o of t.tools)
115
+ `),o=new Set;for(let s=0;s<n.length;s++){let i=Ut(n[s]);(e==="log"?qn.test(i):Bt.test(i))&&(o.add(s),e==="log"&&(s>0&&o.add(s-1),s<n.length-1&&o.add(s+1)));}let r=ae;for(let s of o)r+=Buffer.byteLength(
116
+ n[s])+1;return Math.min(r,Buffer.byteLength(t))}var Qn=(t,e)=>t==="cache_control"?void 0:e;function Xn(t){if(typeof t=="string")return `text:${t}`;if(!t||typeof t!="object"||Array.isArray(t))return `jso\
117
+ n:${JSON.stringify(t??"")}`;let e=t;return e.type==="text"&&typeof e.text=="string"&&Object.keys(e).every(n=>n==="type"||n==="text"||n==="cache_control")?`text:${e.text}`:`json:${JSON.stringify(e,Qn)}`}
118
+ function Zn(t){return createHash("sha256").update(Xn(t)).digest("hex").slice(0,16)}function eo(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t.cache_control;return !e||typeof e!="object"?null:
119
+ e.ttl==="1h"?"1h":"5m"}function Vt(t){let e=[],n=(o,r)=>{let s=Kn(r),i={clave:Zn(r),tipo:o,marca:eo(r),bytes:s,bytesV1:s,clase:"otro",esError:false};if(o.endsWith(":tool_result")&&r&&typeof r=="object"){
120
+ let a=r;i.esError=a.is_error===true;let c=Jn(a.content);i.clase=Gn(c);let m=s-Buffer.byteLength(c);i.bytesV1=Math.min(s,Math.max(0,m)+Yn(c,i.clase));}e.push(i);};if(Array.isArray(t.tools))for(let o of t.tools)
101
121
  n("tools",o);if(Array.isArray(t.system))for(let o of t.system)n("system",o);else (t.system??void 0)!==void 0&&n("system",t.system);for(let o of Array.isArray(t.messages)?t.messages:[]){if(!o||typeof o!=
102
122
  "object"){n("?:invalido",o);continue}let r=o,s=typeof r.role=="string"?r.role:"?";if(typeof r.content=="string")n(`${s}:text`,r.content);else if(Array.isArray(r.content))for(let i of r.content)n(`${s}\
103
- :${i?.type??"?"}`,i);}return e}function jn(){return {nacimiento:new Map,turno:0,elididosV2m:new Set}}function $n(t,e){let n=t.turno++;for(let o of e)t.nacimiento.has(o.clave)||t.nacimiento.set(o.clave,n);
104
- return n}function It(t,e,n,o,r=En){let s=e.reduce((l,h,u)=>h.tipo.endsWith(":tool_result")?u:l,-1),i=(l,h)=>l.tipo.endsWith(":tool_result")&&l.bytes>=wn&&h!==s;return e.map((l,h)=>{if(!i(l,
105
- h))return {clave:l.clave,bytes:l.bytes};let u=o-(n.nacimiento.get(l.clave)??o);return u>=2&&u*l.bytes/1024>=Tn?{clave:`${l.clave}:e`,bytes:se}:{clave:l.clave,bytes:l.bytes}});}function Nn(t){let e=B(t);return e?{inputPer1k:e.inputPer1k,lecturaPer1k:e.cachedInputPer1k??e.inputPer1k,escrituraPer1k:e.inputPer1k*
106
- W(t),escritura1hPer1k:e.inputPer1k*Me(t)}:null}function Et(){return {lecturaUsd:0,escrituraUsd:0,entradaUsd:0,totalUsd:0,tokensLeidos:0,tokensEscritos:0,tokensEntrada:0,tokensInvalidados:0,invalidacionUsd:0}}
107
- var ze={"1h":36e5,"5m":3e5},zn=20,Bn=6e3,Un=2e4,G=class{constructor(e=Un){this.tope=e;}tope;entradas=new Map;get size(){return this.entradas.size}viva(e,n){let o=this.entradas.get(e);return o&&n<=o.expira?
108
- o:null}escribir(e,n,o){this.entradas.delete(e),this.entradas.set(e,{expira:n+ze[o],ttl:o}),this.entradas.size>this.tope&&this.podar(n);}refrescar(e,n){let o=this.entradas.get(e);o&&(this.entradas.delete(
109
- e),this.entradas.set(e,{expira:n+ze[o.ttl],ttl:o.ttl}));}podar(e){for(let[n,o]of this.entradas)e>o.expira&&this.entradas.delete(n);for(;this.entradas.size>this.tope;){let n=this.entradas.keys().next().
110
- value;if(n===void 0)break;this.entradas.delete(n);}}};function Vn(t,e){let n=new Array(e.length),o=createHash("sha256").update(`model:${t}`).digest("hex");for(let r=0;r<e.length;r++)o=createHash("sha256").update(o).update(
111
- "|").update(e[r]).digest("hex").slice(0,32),n[r]=o;return n}function Fn(t){let e=new Array(t.length),n=-1,o="";for(let r=0;r<t.length;r++){let s=t[r],i=s.endsWith(":tool_use")||s.endsWith(":tool_resul\
112
- t");i&&s===o||(n+=1),o=i?s:"",e[r]=n;}return e}function Ct(t,e){return t.endsWith(":image")?Math.min(e,Bn):e}var ie=class{constructor(e,n){this.transformar=e;this.cache=n??new G;}transformar;estado=jn();cache;previo=[];previoUltimoBp=-1;previoTtl="\
113
- 5m";hayPrevio=false;atPrevio=0;acumulado=Et();paso(e){let n=Et(),o=$n(this.estado,e.bloques),r=Nn(e.model),s=this.transformar(e.bloques,this.estado,o);if(!r||e.entradaReal<=0||s.length===0)return this.previo=
114
- s,this.previoUltimoBp=-1,this.previoTtl="5m",this.hayPrevio=true,this.atPrevio=e.at,n;let i=s.map((d,x)=>e.bloques[x]?.tipo??""),a=s.map((d,x)=>e.bloques[x]?.marca??null),c=e.bloques.reduce((d,x)=>d+Ct(
115
- x.tipo,x.bytes),0),p=c>0?e.entradaReal/c:0,f=s.map((d,x)=>Ct(i[x],d.bytes)*p),l=Vn(e.model,s.map(d=>d.clave)),h=Fn(i),u=a.map((d,x)=>d?x:-1).filter(d=>d>=0);if(u.length===0){for(let d=0;d<s.length;d++)
116
- n.tokensEntrada+=f[d],n.entradaUsd+=f[d]/1e3*r.inputPer1k;return n.totalUsd=n.entradaUsd,this.previo=s,this.previoUltimoBp=-1,this.previoTtl="5m",this.hayPrevio=true,this.atPrevio=e.at,this.acumulado.tokensEntrada+=
117
- n.tokensEntrada,this.acumulado.entradaUsd+=n.entradaUsd,this.acumulado.totalUsd+=n.totalUsd,n}let m=-1;for(let d of u){let x=h[d]-(zn-1);for(let S=d;S>=0&&h[S]>=x;S--)if(this.cache.viva(l[S],e.at)){S>
118
- m&&(m=S);break}}for(let d=0;d<=m;d++)this.cache.refrescar(l[d],e.at);let v=u[u.length-1];for(let d of u)d>m&&this.cache.escribir(l[d],e.at,a[d]);let E=0,A=this.hayPrevio&&e.at-this.atPrevio>ze[this.previoTtl]?
119
- []:this.previo.slice(m+1,this.previoUltimoBp+1),g=0;for(let d=0;d<s.length;d++){let x=s[d],S=f[d];if(d<=m){n.tokensLeidos+=S,n.lecturaUsd+=S/1e3*r.lecturaPer1k;continue}if(d>v){n.tokensEntrada+=S,n.entradaUsd+=
120
- S/1e3*r.inputPer1k;continue}for(;u[E]<d;)E+=1;let D=a[u[E]]==="1h"?r.escritura1hPer1k:r.escrituraPer1k;n.tokensEscritos+=S,n.escrituraUsd+=S/1e3*D;let I=g;for(;I<A.length&&A[I].clave!==x.clave;)I+=1;I<
121
- A.length&&(A[I].bytes===x.bytes&&(n.tokensInvalidados+=S,n.invalidacionUsd+=S/1e3*(D-r.lecturaPer1k)),g=I+1);}return this.previo=s,this.previoUltimoBp=v,this.previoTtl=a[v]??"5m",this.hayPrevio=true,this.
123
+ :${i?.type??"?"}`,i);}return e}function to(){return {nacimiento:new Map,turno:0,elididosV2m:new Set}}function no(t,e){let n=t.turno++;for(let o of e)t.nacimiento.has(o.clave)||t.nacimiento.set(o.clave,n);
124
+ return n}function Ft(t,e,n,o,r=Hn){let s=e.reduce((l,f,u)=>f.tipo.endsWith(":tool_result")?u:l,-1),i=(l,f)=>l.tipo.endsWith(":tool_result")&&l.bytes>=Vn&&f!==s;return e.map((l,f)=>{if(!i(l,
125
+ f))return {clave:l.clave,bytes:l.bytes};let u=o-(n.nacimiento.get(l.clave)??o);return u>=2&&u*l.bytes/1024>=Fn?{clave:`${l.clave}:e`,bytes:ae}:{clave:l.clave,bytes:l.bytes}});}function oo(t){let e=L(t);return e?{inputPer1k:e.inputPer1k,lecturaPer1k:e.cachedInputPer1k??e.inputPer1k,escrituraPer1k:e.inputPer1k*
126
+ $(t),escritura1hPer1k:e.inputPer1k*$e(t)}:null}function Nt(){return {lecturaUsd:0,escrituraUsd:0,entradaUsd:0,totalUsd:0,tokensLeidos:0,tokensEscritos:0,tokensEntrada:0,tokensInvalidados:0,invalidacionUsd:0}}
127
+ var qe={"1h":36e5,"5m":3e5},ro=20,so=6e3,io=2e4,X=class{constructor(e=io){this.tope=e;}tope;entradas=new Map;get size(){return this.entradas.size}viva(e,n){let o=this.entradas.get(e);return o&&n<=o.expira?
128
+ o:null}escribir(e,n,o){this.entradas.delete(e),this.entradas.set(e,{expira:n+qe[o],ttl:o}),this.entradas.size>this.tope&&this.podar(n);}refrescar(e,n){let o=this.entradas.get(e);o&&(this.entradas.delete(
129
+ e),this.entradas.set(e,{expira:n+qe[o.ttl],ttl:o.ttl}));}podar(e){for(let[n,o]of this.entradas)e>o.expira&&this.entradas.delete(n);for(;this.entradas.size>this.tope;){let n=this.entradas.keys().next().
130
+ value;if(n===void 0)break;this.entradas.delete(n);}}};function ao(t,e){let n=new Array(e.length),o=createHash("sha256").update(`model:${t}`).digest("hex");for(let r=0;r<e.length;r++)o=createHash("sha256").update(o).update(
131
+ "|").update(e[r]).digest("hex").slice(0,32),n[r]=o;return n}function co(t){let e=new Array(t.length),n=-1,o="";for(let r=0;r<t.length;r++){let s=t[r],i=s.endsWith(":tool_use")||s.endsWith(":tool_resul\
132
+ t");i&&s===o||(n+=1),o=i?s:"",e[r]=n;}return e}function zt(t,e){return t.endsWith(":image")?Math.min(e,so):e}var ce=class{constructor(e,n){this.transformar=e;this.cache=n??new X;}transformar;estado=to();cache;previo=[];previoUltimoBp=-1;previoTtl="\
133
+ 5m";hayPrevio=false;atPrevio=0;acumulado=Nt();paso(e){let n=Nt(),o=no(this.estado,e.bloques),r=oo(e.model),s=this.transformar(e.bloques,this.estado,o);if(!r||e.entradaReal<=0||s.length===0)return this.previo=
134
+ s,this.previoUltimoBp=-1,this.previoTtl="5m",this.hayPrevio=true,this.atPrevio=e.at,n;let i=s.map((p,x)=>e.bloques[x]?.tipo??""),a=s.map((p,x)=>e.bloques[x]?.marca??null),c=e.bloques.reduce((p,x)=>p+zt(
135
+ x.tipo,x.bytes),0),m=c>0?e.entradaReal/c:0,h=s.map((p,x)=>zt(i[x],p.bytes)*m),l=ao(e.model,s.map(p=>p.clave)),f=co(i),u=a.map((p,x)=>p?x:-1).filter(p=>p>=0);if(u.length===0){for(let p=0;p<s.length;p++)
136
+ n.tokensEntrada+=h[p],n.entradaUsd+=h[p]/1e3*r.inputPer1k;return n.totalUsd=n.entradaUsd,this.previo=s,this.previoUltimoBp=-1,this.previoTtl="5m",this.hayPrevio=true,this.atPrevio=e.at,this.acumulado.tokensEntrada+=
137
+ n.tokensEntrada,this.acumulado.entradaUsd+=n.entradaUsd,this.acumulado.totalUsd+=n.totalUsd,n}let d=-1;for(let p of u){let x=f[p]-(ro-1);for(let S=p;S>=0&&f[S]>=x;S--)if(this.cache.viva(l[S],e.at)){S>
138
+ d&&(d=S);break}}for(let p=0;p<=d;p++)this.cache.refrescar(l[p],e.at);let k=u[u.length-1];for(let p of u)p>d&&this.cache.escribir(l[p],e.at,a[p]);let E=0,A=this.hayPrevio&&e.at-this.atPrevio>qe[this.previoTtl]?
139
+ []:this.previo.slice(d+1,this.previoUltimoBp+1),g=0;for(let p=0;p<s.length;p++){let x=s[p],S=h[p];if(p<=d){n.tokensLeidos+=S,n.lecturaUsd+=S/1e3*r.lecturaPer1k;continue}if(p>k){n.tokensEntrada+=S,n.entradaUsd+=
140
+ S/1e3*r.inputPer1k;continue}for(;u[E]<p;)E+=1;let P=a[u[E]]==="1h"?r.escritura1hPer1k:r.escrituraPer1k;n.tokensEscritos+=S,n.escrituraUsd+=S/1e3*P;let C=g;for(;C<A.length&&A[C].clave!==x.clave;)C+=1;C<
141
+ A.length&&(A[C].bytes===x.bytes&&(n.tokensInvalidados+=S,n.invalidacionUsd+=S/1e3*(P-r.lecturaPer1k)),g=C+1);}return this.previo=s,this.previoUltimoBp=k,this.previoTtl=a[k]??"5m",this.hayPrevio=true,this.
122
142
  atPrevio=e.at,n.totalUsd=n.lecturaUsd+n.escrituraUsd+n.entradaUsd,this.acumulado.lecturaUsd+=n.lecturaUsd,this.acumulado.escrituraUsd+=n.escrituraUsd,this.acumulado.entradaUsd+=n.entradaUsd,this.acumulado.
123
143
  totalUsd+=n.totalUsd,this.acumulado.tokensLeidos+=n.tokensLeidos,this.acumulado.tokensEscritos+=n.tokensEscritos,this.acumulado.tokensEntrada+=n.tokensEntrada,this.acumulado.tokensInvalidados+=n.tokensInvalidados,
124
- this.acumulado.invalidacionUsd+=n.invalidacionUsd,n}};function Pt(t){return t.map(e=>({clave:e.clave,bytes:e.bytes}))}var Hn=64,ve=class{cadenas=new Map;cachesPorModelo=new Map;observar(e){let n=e.uso.cache_creation_input_tokens??(e.uso.cache_creation?.ephemeral_5m_input_tokens??0)+(e.uso.cache_creation?.ephemeral_1h_input_tokens??
125
- 0),o=(e.uso.input_tokens??0)+(e.uso.cache_read_input_tokens??0)+n;if(o<=0)return null;let r={bloques:Rt(e.cuerpo),at:e.at,model:e.model,entradaReal:o,escritura1h:(e.uso.cache_creation?.ephemeral_1h_input_tokens??
144
+ this.acumulado.invalidacionUsd+=n.invalidacionUsd,n}};function Ht(t){return t.map(e=>({clave:e.clave,bytes:e.bytes}))}var uo=64,we=class{cadenas=new Map;cachesPorModelo=new Map;observar(e){let n=e.uso.cache_creation_input_tokens??(e.uso.cache_creation?.ephemeral_5m_input_tokens??0)+(e.uso.cache_creation?.ephemeral_1h_input_tokens??
145
+ 0),o=(e.uso.input_tokens??0)+(e.uso.cache_read_input_tokens??0)+n;if(o<=0)return null;let r={bloques:Vt(e.cuerpo),at:e.at,model:e.model,entradaReal:o,escritura1h:(e.uso.cache_creation?.ephemeral_1h_input_tokens??
126
146
  0)>0};if(r.bloques.length===0)return null;let s=this.cadenaPara(this.clave(e),e.model),i=s.base.paso(r),a=s.v0.paso(r);return i.totalUsd<=0&&a.totalUsd<=0?null:{baselineUsd:i.totalUsd,politicaUsd:a.totalUsd}}clave(e){
127
147
  if(e.sessionId)return `s:${e.sessionId}\xB7a:${e.agentId??""}\xB7${e.model}`;let n=Array.isArray(e.cuerpo.messages)?e.cuerpo.messages[0]:void 0;return `m:${createHash("sha256").update(JSON.stringify(n??null)).digest(
128
- "hex").slice(0,16)}\xB7${e.model}`}cachesDe(e){let n=this.cachesPorModelo.get(e);return n||(n={base:new G,v0:new G},this.cachesPorModelo.set(e,n)),n}cadenaPara(e,n){let o=this.cadenas.get(e);if(!o){let r=this.
129
- cachesDe(n);if(o={base:new ie(s=>Pt(s),r.base),v0:new ie((s,i,a)=>It("v0",s,i,a),r.v0),ultimoUso:0},this.cadenas.set(e,o),this.cadenas.size>Hn){let s=null,i=1/0;for(let[a,c]of this.cadenas)c.ultimoUso<
130
- i&&(i=c.ultimoUso,s=a);s!==null&&this.cadenas.delete(s);}}return o.ultimoUso=Date.now(),o}};var ye=class{url;clave;ttlMs;fetchImpl;log;features=new Set;validoHasta=0;enVuelo=null;avisado=false;constructor(e){this.url=e.url,this.clave=e.serviceAccountKey,this.ttlMs=e.ttlMs??3e5,this.fetchImpl=e.
148
+ "hex").slice(0,16)}\xB7${e.model}`}cachesDe(e){let n=this.cachesPorModelo.get(e);return n||(n={base:new X,v0:new X},this.cachesPorModelo.set(e,n)),n}cadenaPara(e,n){let o=this.cadenas.get(e);if(!o){let r=this.
149
+ cachesDe(n);if(o={base:new ce(s=>Ht(s),r.base),v0:new ce((s,i,a)=>Ft("v0",s,i,a),r.v0),ultimoUso:0},this.cadenas.set(e,o),this.cadenas.size>uo){let s=null,i=1/0;for(let[a,c]of this.cadenas)c.ultimoUso<
150
+ i&&(i=c.ultimoUso,s=a);s!==null&&this.cadenas.delete(s);}}return o.ultimoUso=Date.now(),o}};var Ee=class{url;clave;ttlMs;fetchImpl;log;features=new Set;validoHasta=0;enVuelo=null;avisado=false;constructor(e){this.url=e.url,this.clave=e.serviceAccountKey,this.ttlMs=e.ttlMs??3e5,this.fetchImpl=e.
131
151
  fetchImpl??fetch,this.log=e.log??(()=>{}),this.refrescar();}tiene(e){return Date.now()>this.validoHasta&&this.enVuelo===null&&this.refrescar(),this.features.has(e)}refrescar(){return this.enVuelo?this.
132
152
  enVuelo:(this.enVuelo=this.pedir().finally(()=>{this.enVuelo=null;}),this.enVuelo)}async pedir(){try{let e=await this.fetchImpl(this.url,{method:"GET",headers:{authorization:`Bearer ${this.clave}`},signal:AbortSignal.
133
153
  timeout(1e4)});if(!e.ok){this.cerrar(`entitlements HTTP ${e.status}`);return}let n=await e.json();if(!Array.isArray(n.features)||!n.features.every(r=>typeof r=="string")){this.cerrar("entitlements con\
134
154
  forma inesperada");return}this.features=new Set(n.features);let o=typeof n.refreshAfterSeconds=="number"&&n.refreshAfterSeconds>0?Math.min(n.refreshAfterSeconds*1e3,this.ttlMs):this.ttlMs;this.validoHasta=
135
155
  Date.now()+o,this.avisado=!1;}catch(e){this.cerrar(String(e));}}cerrar(e){this.features=new Set,this.validoHasta=Date.now()+Math.min(6e4,this.ttlMs),this.avisado||(this.avisado=true,this.log(`[gateway] en\
136
- titlements no disponibles (${e}) \u2014 palanca apagada (fail-closed)`));}};var Jn=.3,Wn=4096,Gn=(t,e)=>t==="cache_control"?void 0:e;function Be(t){return t===void 0?"":JSON.stringify(t,Gn)??""}function Ue(t){return createHash("sha1").update(t).digest("base64url").slice(0,16)}function Fe(t,e){
137
- if(e!==void 0&&e!==""&&e!=="identity")return null;try{let n=JSON.parse(t.toString("utf8"));if(n===null||typeof n!="object"||Array.isArray(n))return null;let o=n;return typeof o.model!="string"||!Array.
138
- isArray(o.messages)?null:o}catch{return null}}function Ot(t){let e=Be(t.system),n=Be(t.tools),o=Array.isArray(t.messages)?t.messages.slice(0,Wn):[],r=[],s=[];for(let i of o){let a=Be(i);r.push(Ue(a)),
139
- s.push(Buffer.byteLength(a,"utf8"));}return {system:Ue(e),tools:Ue(n),mensajes:r,bytes:s,bytesFijos:Buffer.byteLength(e,"utf8")+Buffer.byteLength(n,"utf8")}}function Dt(t,e){if(t===void 0||t.system!==e.
140
- system||t.tools!==e.tools)return 1;let n=e.bytesFijos;for(let s of e.bytes)n+=s;if(n<=0)return 1;let o=0;for(;o<t.mensajes.length&&o<e.mensajes.length&&t.mensajes[o]===e.mensajes[o];)o++;let r=0;for(let s=o;s<
141
- e.bytes.length;s++)r+=e.bytes[s]??0;return r/n}function Mt(t){let{fraccionNueva:e,umbral:n=Jn}=t;return e>=n}function Ve(t,e){if(t===null||typeof t!="object")return;if(Array.isArray(t)){for(let r of t)
142
- Ve(r,e);return}let n=t,o=n.cache_control;if(o!==null&&typeof o=="object"&&!Array.isArray(o)){let r=o;r.ttl==="1h"?(r.ttl="5m",e.rebajadas++):(r.ttl==="5m"||r.ttl===void 0)&&e.yaEran5m++;}for(let[r,s]of Object.
143
- entries(n))r!=="cache_control"&&s!==null&&typeof s=="object"&&Ve(s,e);}function Lt(t,e){let n=Buffer.isBuffer(t)?Fe(t,e):t;if(n===null)return null;try{let o={rebajadas:0,yaEran5m:0};for(let r of ["syste\
144
- m","messages","tools"])Ve(n[r],o);return o.rebajadas===0?null:{cuerpo:Buffer.from(JSON.stringify(n),"utf8"),rebajadas:o.rebajadas,yaEran5m:o.yaEran5m}}catch{return null}}var ke=class{constructor(e=512,n=3600*1e3){this.maxEntradas=e;this.maxEdadMs=n;}maxEntradas;maxEdadMs;visto=new Map;ultima(e,n){let o=this.visto.get(e);if(o!==void 0){if(n-o.vistoMs>this.maxEdadMs){this.
145
- visto.delete(e);return}return o.huella}}anotar(e,n,o){for(this.visto.delete(e),this.visto.set(e,{huella:n,vistoMs:o});this.visto.size>this.maxEntradas;){let r=this.visto.keys().next();if(r.done===true)break;
146
- this.visto.delete(r.value);}}get tamano(){return this.visto.size}};var qe=5*1024*1024,Qn=["authorization","x-api-key","anthropic-version","anthropic-beta"];function jt(t,e,n,o=""){return createHash("sha256").update(t).update(`
156
+ titlements no disponibles (${e}) \u2014 palanca apagada (fail-closed)`));}};var Ke=5*1024*1024,mo=["authorization","x-api-key","anthropic-version","anthropic-beta"];function qt(t,e,n,o=""){return createHash("sha256").update(t).update(`
147
157
  `).update(e).update(`
148
158
  `).update(o).update(`
149
- `).update(n).digest("hex")}function $t(t){return Qn.map(e=>`${e}=${t(e)??""}`).join(`
150
- `)}var xe=class{enVuelo=new Map;primarias=0;gemelas=0;registrar(e){if(this.enVuelo.has(e))return null;this.primarias+=1;let n,o=new Promise(a=>n=a);this.enVuelo.set(e,{promesa:o,resolver:n});let r=[],
151
- s=0,i=false;return {capturar:a=>{if(!i){if(s+=a.length,s>qe){i=true,r.length=0;return}r.push(a);}},terminar:(a,c)=>{let p=!i&&a>=200&&a<300;this.enVuelo.get(e)?.resolver(p?{status:a,headers:c,chunks:r}:null),
159
+ `).update(n).digest("hex")}function Kt(t){return mo.map(e=>`${e}=${t(e)??""}`).join(`
160
+ `)}var Te=class{enVuelo=new Map;primarias=0;gemelas=0;registrar(e){if(this.enVuelo.has(e))return null;this.primarias+=1;let n,o=new Promise(a=>n=a);this.enVuelo.set(e,{promesa:o,resolver:n});let r=[],
161
+ s=0,i=false;return {capturar:a=>{if(!i){if(s+=a.length,s>Ke){i=true,r.length=0;return}r.push(a);}},terminar:(a,c)=>{let m=!i&&a>=200&&a<300;this.enVuelo.get(e)?.resolver(m?{status:a,headers:c,chunks:r}:null),
152
162
  this.enVuelo.delete(e);},abortar:()=>{this.enVuelo.get(e)?.resolver(null),this.enVuelo.delete(e);}}}async esperar(e){let n=this.enVuelo.get(e);if(!n)return null;let o=await n.promesa;return o&&(this.gemelas+=
153
- 1),o}tieneEnVuelo(e){return this.enVuelo.has(e)}};var eo=["content-encoding","content-length","transfer-encoding"];async function Nt(t={}){let e=(t.upstream??"https://api.anthropic.com").replace(/\/+$/,""),n=t.fetchImpl??fetch,o=t.log??(u=>console.log(
154
- u)),r;if(t.serviceAccountKey){r=new J({url:t.meteringUrl??"https://savings.bivelio.com/api/metering/usage",serviceAccountKey:t.serviceAccountKey,surface:"gateway",...t.fetchImpl?{fetchImpl:t.fetchImpl}:
155
- {},onAuthError:m=>O("gateway-ingest-auth",`[bvsala gateway] la ingesta de uso rechaza la credencial (${m}). El tr\xE1fico sigue fluyendo (avisar, nunca romper), pero este uso no est\xE1 llegando al panel. R\
156
- evisa BIVELIO_SERVICE_KEY y el estado de la suscripci\xF3n en savings.bivelio.com.`)});let u=me();t.seatId?r.setSeat(t.seatId,u):fe(t.serviceAccountKey).then(m=>r?.setSeat(m,u)).catch(()=>{}),r.start();}else
157
- O("gateway-sin-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.");
158
- let s=t.coalescer?new xe:null,i=t.sombra&&r?new ve:null,a=new ke,c=t.elision!==false&&t.serviceAccountKey?new ye({url:new URL("/api/org/entitlements",t.meteringUrl??"https://savings.bivelio.com/api/meter\
159
- ing/usage").toString(),serviceAccountKey:t.serviceAccountKey,...t.fetchImpl?{fetchImpl:t.fetchImpl}:{},log:o}):null,p=u=>u==="/v1/messages"?new U:u.endsWith("/responses")?new ge:null,f=(u,m,v,E,R,A,g,d,x,S)=>{
160
- if(!r||!v)return;let D=r,I=v,_=yt(m,A);if(!_){O(`gateway-sin-modelo:${R}`,`[bvsala gateway] no se pudo leer el modelo del cuerpo de ${R} (content-encoding: ${A??"ninguno"}); su uso se reenv\xEDa pero no \
161
- se mide.`);return}let C=vt(_,v);if(C){let X=E?St(u,_,C,g):xt(u,_,C,g,d,x);r.record(X);let q=X.cost.eliminatedInputFloorCost;o(`[gateway] POST ${R} ${E?"\xB7 COALESCIDA (llamada evitada)":""} \xB7 ${_}\
162
- \xB7 $${C.costeUsd.toFixed(6)} (in ${C.tokens.entrada}, cache\u2191${C.tokens.cacheEscrita}${C.tokens.cacheEscrita1h?` (1h ${C.tokens.cacheEscrita1h})`:""} cache\u2193${C.tokens.cacheLeida}, out ${C.
163
- tokens.salida})`+(d?` \xB7 elisi\xF3n: ${d.borrados} borrado(s), ${d.tokensLimpiados} tok limpiados por el proveedor`+(q!==void 0?` \xB7 suelo $${q.toFixed(6)} (lectura de cach\xE9)`:d.tokensLimpiadosToolUses>
164
- 0?d.atribuible?" \xB7 sin precio de lectura en el cat\xE1logo: sin suelo":" \xB7 diales del cliente: se cuenta, no se acredita":d.tokensLimpiados>0?" \xB7 solo thinking (config del cliente): se cuenta, n\
165
- o se acredita":""):""));let Z=d?.atribuible===true&&d.tokensLimpiadosToolUses>0;i&&!E&&R==="/v1/messages"&&setImmediate(()=>{try{let L=je(m,A);if(!L||typeof L!="object")return;let w=i.observar({cuerpo:L,
166
- uso:I,model:_,at:S??Date.now(),...g?.sessionId!==void 0?{sessionId:g.sessionId}:{},...g?.agentId!==void 0?{agentId:g.agentId}:{}});if(!w)return;if(Z){o(`[gateway] sombra \xB7 ${_} \xB7 el proveedor ya bo\
167
- rr\xF3 por nuestros diales: la cadena avanza, no se emite`);return}D.record(wt(`${u}:shadow`,_,w.baselineUsd,w.politicaUsd,g)),o(`[gateway] sombra \xB7 ${_} \xB7 baseline $${w.baselineUsd.toFixed(6)} \
168
- \u2192 v0 $${w.politicaUsd.toFixed(6)}`);}catch{}});}else O(`gateway-sin-precio:${_}`,`[bvsala gateway] el modelo "${_}" no est\xE1 en el cat\xE1logo de precios; su uso se reenv\xEDa pero no se mide.`);},
169
- l=createServer(async(u,m)=>{let v=randomUUID(),E=Date.now(),R=new AbortController;m.on("close",()=>{m.writableEnded||R.abort();});let A=null,g=new URL(u.url??"/",e),d=null,x=Buffer.alloc(0),S=false,D=null,I=(w,k)=>{if(w===
170
- null||D===null||!D.nuestros)return w;let z=k?.cache_creation,Ae=k?.cache_creation_input_tokens??(z?.ephemeral_5m_input_tokens??0)+(z?.ephemeral_1h_input_tokens??0),ee=(k?.input_tokens??0)+(k?.cache_read_input_tokens??
171
- 0)+Ae+w.tokensLimpiados,H=D.triggerDelCliente!==null&&ee>=D.triggerDelCliente;return {...w,atribuible:!H}},_=u.headers["content-encoding"],C=Array.isArray(_)?_[0]:_,X=w=>{let k=Array.isArray(w)?w[0]:w;
172
- return k!==void 0&&/^[A-Za-z0-9._:/-]{1,128}$/.test(k)?k:void 0},q=X(u.headers["x-claude-code-session-id"]),Z=X(u.headers["x-claude-code-agent-id"]),L=q!==void 0||Z!==void 0?{...q!==void 0?{sessionId:q}:
173
- {},...Z!==void 0?{agentId:Z}:{}}:void 0;try{let w=[];for await(let b of u)w.push(b);let k=Buffer.concat(w);x=k,g=new URL(u.url??"/",e);let z=s!==null&&u.method==="POST"&&k.length>0,Ae=$t(b=>{let y=u.headers[b];
174
- return Array.isArray(y)?y.join(", "):y}),ee=z?jt("POST",g.pathname+g.search,k,Ae):"";if(z)if(s.tieneEnVuelo(ee)){let b=await s.esperar(ee);if(b){m.writeHead(b.status,b.headers);let y=p(g.pathname)??new U;
175
- for(let re of b.chunks)m.write(re),y.observar(re);m.end();let oe=y.usage()??(g.pathname==="/v1/messages"?$e(Buffer.concat(b.chunks)):null);f(v,k,oe,!0,g.pathname,C,L);return}}else A=s.registrar(ee);let H={};
176
- for(let[b,y]of Object.entries(u.headers))b==="host"||b==="content-length"||y===void 0||(H[b]=Array.isArray(y)?y.join(", "):y);let te=k;if(c!==null&&u.method==="POST"&&g.pathname==="/v1/messages"&&c.tiene(
177
- "context_elision"))try{let b=ut(k,C);b!==null&&(te=b.cuerpo,D={nuestros:b.nuestros,triggerDelCliente:b.triggerDelCliente},H["anthropic-beta"]=pt(H["anthropic-beta"]));}catch{}let _e=null;if(c!==null&&u.
178
- method==="POST"&&g.pathname==="/v1/messages"&&c.tiene("cache_ttl_tuning"))try{let y=Fe(te,te===k?C:"identity");if(y!==null){let oe=Ot(y),re=`${L?.sessionId??"sin-sesion"}:${oe.system}`,at=Date.now(),sn=a.
179
- ultima(re,at);if(a.anotar(re,oe,at),Mt({fraccionNueva:Dt(sn,oe)})){let ue=Lt(y);ue!==null&&(te=ue.cuerpo,_e={rebajadas:ue.rebajadas,yaEran5m:ue.yaEran5m});}}}catch{}let P;try{P=await n(g,{method:u.method,
180
- headers:H,body:["GET","HEAD"].includes(u.method??"")?void 0:te,redirect:"manual",signal:R.signal});}catch(b){A?.abortar(),m.headersSent||(m.writeHead(502,{"content-type":"application/json"}),m.end(JSON.
181
- stringify({error:"bvsala gateway: upstream unreachable",detail:String(b)}))),o(`[gateway] ${u.method} ${g.pathname} \u2192 upstream inalcanzable: ${String(b)}`);return}let Re=Object.fromEntries(P.headers.
182
- entries());for(let b of eo)delete Re[b];m.writeHead(P.status,Re);let st=P.headers.get("content-type")??"",Ie=st.includes("text/event-stream")||st===""&&P.ok&&p(g.pathname)!==null;d=Ie?p(g.pathname):null;
183
- let ne=!Ie&&P.ok&&r!==void 0&&u.method==="POST"&&g.pathname==="/v1/messages"&&(P.headers.get("content-type")??"").includes("application/json")?[]:null,it=0;if(P.body)for await(let b of P.body){let y=Buffer.
184
- from(b);m.write(y),d?.observar(y),ne&&(it+=y.length,it>qe?ne=null:ne.push(y)),A?.capturar(y);}if(m.end(),A?.terminar(P.status,Re),d&&P.ok){S=!0;let b=d.usage(),y=I(d instanceof U?d.elision():null,b);f(
185
- v,k,b,!1,g.pathname,C,L,y,_e,E);}else if(ne){let b=Buffer.concat(ne),y=$e(b);f(v,k,y,!1,g.pathname,C,L,I(bt(b),y),_e,E);}else Ie||o(`[gateway] ${u.method} ${g.pathname} \u2192 ${P.status}`);}catch(w){if(A?.
186
- abortar(),R.signal.aborted){let k=!S&&d?d.usageFinal():null;if(k){o(`[gateway] ${u.method} ${g.pathname} \u2192 el cliente cerr\xF3 tras el usage final; se mide igual`);let z=I(d instanceof U?d.elision():
187
- null,k);f(v,x,k,false,g.pathname,C,L,z,void 0,E);}else o(`[gateway] ${u.method} ${g.pathname} \u2192 el cliente abort\xF3; upstream cancelado`);}else if(o(`[gateway] ${u.method} ${g.pathname} \u2192 error sirvi\
188
- endo: ${String(w)}`),!m.headersSent){m.writeHead(502,{"content-type":"application/json"}),m.end(JSON.stringify({error:"bvsala gateway: stream interrupted",detail:String(w)}));return}m.writableEnded||m.
189
- end();}});return l.on("upgrade",(u,m)=>{o(`[gateway] ${u.method} ${new URL(u.url??"/","http://x").pathname} \u2192 426 (WebSocket no soportado; el cliente cae a HTTP)`),m.once("error",()=>{}),m.once("f\
190
- inish",()=>m.destroy()),m.end(`HTTP/1.1 426 Upgrade Required\r
163
+ 1),o}tieneEnVuelo(e){return this.enVuelo.has(e)}};var go=["content-encoding","content-length","transfer-encoding"];async function Jt(t={}){let e=(t.upstream??"https://api.anthropic.com").replace(/\/+$/,""),n=t.fetchImpl??fetch,o=t.log??(u=>console.log(
164
+ u)),r;if(t.serviceAccountKey){r=new Q({url:t.meteringUrl??"https://savings.bivelio.com/api/metering/usage",serviceAccountKey:t.serviceAccountKey,surface:"gateway",...t.fetchImpl?{fetchImpl:t.fetchImpl}:
165
+ {},onAuthError:d=>M("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. R\
166
+ evisa BIVELIO_SERVICE_KEY y el estado de la suscripci\xF3n en savings.bivelio.com.`)});let u=ke();t.seatId?r.setSeat(t.seatId,u):xe(t.serviceAccountKey).then(d=>r?.setSeat(d,u)).catch(()=>{}),r.start();}else
167
+ M("gateway-sin-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.");
168
+ let s=t.coalescer?new Te:null,i=t.sombra&&r?new we:null,a=new be,c=t.elision!==false&&t.serviceAccountKey?new Ee({url:new URL("/api/org/entitlements",t.meteringUrl??"https://savings.bivelio.com/api/meter\
169
+ ing/usage").toString(),serviceAccountKey:t.serviceAccountKey,...t.fetchImpl?{fetchImpl:t.fetchImpl}:{},log:o}):null,m=u=>u==="/v1/messages"?new q:u.endsWith("/responses")?new Se:null,h=(u,d,k,E,I,A,g,p,x,S,P)=>{
170
+ if(!r||!k)return;let C=r,te=k,_=Ot(d,A);if(!_){M(`gateway-sin-modelo:${I}`,`[bvsala gateway] no se pudo leer el modelo del cuerpo de ${I} (content-encoding: ${A??"ninguno"}); su uso se reenv\xEDa pero no\
171
+ se mide.`);return}let D=!E&&P?P.servido:_,O=Pt(D,k);if(O){let W=E?Lt(u,_,O,g):Mt(u,D,O,g,p,x,P);r.record(W);let G=W.cost.eliminatedInputFloorCost;o(`[gateway] POST ${I} ${E?"\xB7 COALESCIDA (llamada evi\
172
+ tada)":""} \xB7 ${D!==_?`${_}\u2192${D} (modelo hermano)`:_} \xB7 $${O.costeUsd.toFixed(6)} (in ${O.tokens.entrada}, cache\u2191${O.tokens.cacheEscrita}${O.tokens.cacheEscrita1h?` (1h ${O.tokens.cacheEscrita1h}\
173
+ )`:""} cache\u2193${O.tokens.cacheLeida}, out ${O.tokens.salida})`+(p?` \xB7 elisi\xF3n: ${p.borrados} borrado(s), ${p.tokensLimpiados} tok limpiados por el proveedor`+(G!==void 0?` \xB7 suelo $${G.toFixed(
174
+ 6)} (lectura de cach\xE9)`:p.tokensLimpiadosToolUses>0?p.atribuible?" \xB7 sin precio de lectura en el cat\xE1logo: sin suelo":" \xB7 diales del cliente: se cuenta, no se acredita":p.tokensLimpiados>0?
175
+ " \xB7 solo thinking (config del cliente): se cuenta, no se acredita":""):""));let F=p?.atribuible===true&&p.tokensLimpiadosToolUses>0;i&&!E&&I==="/v1/messages"&&setImmediate(()=>{try{let T=Ve(d,A);if(!T||
176
+ typeof T!="object")return;let y=i.observar({cuerpo:T,uso:te,model:_,at:S??Date.now(),...g?.sessionId!==void 0?{sessionId:g.sessionId}:{},...g?.agentId!==void 0?{agentId:g.agentId}:{}});if(!y)return;if(F){
177
+ o(`[gateway] sombra \xB7 ${_} \xB7 el proveedor ya borr\xF3 por nuestros diales: la cadena avanza, no se emite`);return}C.record(jt(`${u}:shadow`,_,y.baselineUsd,y.politicaUsd,g)),o(`[gateway] sombra \
178
+ \xB7 ${_} \xB7 baseline $${y.baselineUsd.toFixed(6)} \u2192 v0 $${y.politicaUsd.toFixed(6)}`);}catch{}});}else M(`gateway-sin-precio:${_}`,`[bvsala gateway] el modelo "${_}" no est\xE1 en el cat\xE1logo de pr\
179
+ ecios; su uso se reenv\xEDa pero no se mide.`);},l=createServer(async(u,d)=>{let k=randomUUID(),E=Date.now(),I=new AbortController;d.on("close",()=>{d.writableEnded||I.abort();});let A=null,g=new URL(u.url??"/",e),p=null,
180
+ x=Buffer.alloc(0),S=false,P=null,C=null,te=(T,y)=>{if(T===null||P===null||!P.nuestros)return T;let H=y?.cache_creation,Ie=y?.cache_creation_input_tokens??(H?.ephemeral_5m_input_tokens??0)+(H?.ephemeral_1h_input_tokens??
181
+ 0),ne=(y?.input_tokens??0)+(y?.cache_read_input_tokens??0)+Ie+T.tokensLimpiados,U=P.triggerDelCliente!==null&&ne>=P.triggerDelCliente;return {...T,atribuible:!U}},_=u.headers["content-encoding"],D=Array.
182
+ isArray(_)?_[0]:_,O=T=>{let y=Array.isArray(T)?T[0]:T;return y!==void 0&&/^[A-Za-z0-9._:/-]{1,128}$/.test(y)?y:void 0},W=O(u.headers["x-claude-code-session-id"]),G=O(u.headers["x-claude-code-agent-id"]),
183
+ F=W!==void 0||G!==void 0?{...W!==void 0?{sessionId:W}:{},...G!==void 0?{agentId:G}:{}}:void 0;try{let T=[];for await(let b of u)T.push(b);let y=Buffer.concat(T);x=y,g=new URL(u.url??"/",e);let H=s!==null&&
184
+ u.method==="POST"&&y.length>0,Ie=Kt(b=>{let v=u.headers[b];return Array.isArray(v)?v.join(", "):v}),ne=H?qt("POST",g.pathname+g.search,y,Ie):"";if(H)if(s.tieneEnVuelo(ne)){let b=await s.esperar(ne);if(b){
185
+ d.writeHead(b.status,b.headers);let v=m(g.pathname)??new q;for(let se of b.chunks)d.write(se),v.observar(se);d.end();let re=v.usage()??(g.pathname==="/v1/messages"?Fe(Buffer.concat(b.chunks)):null);h(
186
+ k,y,re,!0,g.pathname,D,F);return}}else A=s.registrar(ne);let U={};for(let[b,v]of Object.entries(u.headers))b==="host"||b==="content-length"||v===void 0||(U[b]=Array.isArray(v)?v.join(", "):v);let fn={
187
+ ...U},V=y;if(c!==null&&t.dialesElision===!0&&u.method==="POST"&&g.pathname==="/v1/messages"&&c.tiene("context_elision"))try{let b=ft(y,D);b!==null&&(V=b.cuerpo,P={nuestros:b.nuestros,triggerDelCliente:b.
188
+ triggerDelCliente},U["anthropic-beta"]=gt(U["anthropic-beta"]));}catch{}let ct=c!==null&&t.modeloHermano===!0&&u.method==="POST"&&(g.pathname==="/v1/messages"||g.pathname==="/v1/messages/count_tokens");
189
+ if(ct&&!c.tiene("sibling_model_routing")&&M("gateway-hermano-sin-feature","[bvsala gateway] modelo hermano (C): la bandera est\xE1 puesta pero la licencia de la org NO trae sibling_model_routing; la peti\
190
+ ci\xF3n se reenv\xEDa intacta (fail-closed)."),ct&&c.tiene("sibling_model_routing"))try{let v=Et(V,V===y?D:"identity",{betas:U["anthropic-beta"]});v!==null&&(V=v.cuerpo,C=v.cambio);}catch{}let me=null;
191
+ if(c!==null&&u.method==="POST"&&g.pathname==="/v1/messages"&&c.tiene("cache_ttl_tuning"))try{let v=ie(V,V===y?D:"identity");if(v!==null){let re=yt(v),se=`${F?.sessionId??"sin-sesion"}:${re.system}`,dt=Date.
192
+ now(),hn=a.ultima(se,dt);if(a.anotar(se,re,dt),xt({fraccionNueva:kt(hn,re)})){let fe=St(v);fe!==null&&(V=fe.cuerpo,me={rebajadas:fe.rebajadas,yaEran5m:fe.yaEran5m});}}}catch{}let R;try{R=await n(g,{method:u.
193
+ method,headers:U,body:["GET","HEAD"].includes(u.method??"")?void 0:V,redirect:"manual",signal:I.signal});}catch(b){A?.abortar(),d.headersSent||(d.writeHead(502,{"content-type":"application/json"}),d.end(
194
+ JSON.stringify({error:"bvsala gateway: upstream unreachable",detail:String(b)}))),o(`[gateway] ${u.method} ${g.pathname} \u2192 upstream inalcanzable: ${String(b)}`);return}if(C!==null&&R.status===400&&
195
+ !I.signal.aborted){let b="";try{b=(await R.text()).slice(0,300).replace(/\s+/g," ");}catch{}o(`[gateway] modelo hermano (C): el upstream rechaz\xF3 (400) la petici\xF3n reescrita a ${C.servido}; se ree\
196
+ nv\xEDa intacta \xB7 ${b}`),C=null,me=null,P=null;try{R=await n(g,{method:u.method,headers:fn,body:y,redirect:"manual",signal:I.signal});}catch(v){A?.abortar(),d.headersSent||(d.writeHead(502,{"content\
197
+ -type":"application/json"}),d.end(JSON.stringify({error:"bvsala gateway: upstream unreachable",detail:String(v)}))),o(`[gateway] ${u.method} ${g.pathname} \u2192 upstream inalcanzable en el reintento: ${String(
198
+ v)}`);return}}let Pe=Object.fromEntries(R.headers.entries());for(let b of go)delete Pe[b];d.writeHead(R.status,Pe);let lt=R.headers.get("content-type")??"",Oe=lt.includes("text/event-stream")||lt===""&&
199
+ R.ok&&m(g.pathname)!==null;p=Oe?m(g.pathname):null;let oe=!Oe&&R.ok&&r!==void 0&&u.method==="POST"&&g.pathname==="/v1/messages"&&(R.headers.get("content-type")??"").includes("application/json")?[]:null,
200
+ ut=0;if(R.body)for await(let b of R.body){let v=Buffer.from(b);d.write(v),p?.observar(v),oe&&(ut+=v.length,ut>Ke?oe=null:oe.push(v)),A?.capturar(v);}if(d.end(),A?.terminar(R.status,Pe),p&&R.ok){S=!0;let b=p.
201
+ usage(),v=te(p instanceof q?p.elision():null,b);h(k,y,b,!1,g.pathname,D,F,v,me,E,C);}else if(oe){let b=Buffer.concat(oe),v=Fe(b);h(k,y,v,!1,g.pathname,D,F,te(Rt(b),v),me,E,C);}else Oe||o(`[gateway] ${u.
202
+ method} ${g.pathname} \u2192 ${R.status}`);}catch(T){if(A?.abortar(),I.signal.aborted){let y=!S&&p?p.usageFinal():null;if(y){o(`[gateway] ${u.method} ${g.pathname} \u2192 el cliente cerr\xF3 tras el usage fina\
203
+ l; se mide igual`);let H=te(p instanceof q?p.elision():null,y);h(k,x,y,false,g.pathname,D,F,H,void 0,E,C);}else o(`[gateway] ${u.method} ${g.pathname} \u2192 el cliente abort\xF3; upstream cancelado`);}else if(o(
204
+ `[gateway] ${u.method} ${g.pathname} \u2192 error sirviendo: ${String(T)}`),!d.headersSent){d.writeHead(502,{"content-type":"application/json"}),d.end(JSON.stringify({error:"bvsala gateway: stream int\
205
+ errupted",detail:String(T)}));return}d.writableEnded||d.end();}});return l.on("upgrade",(u,d)=>{o(`[gateway] ${u.method} ${new URL(u.url??"/","http://x").pathname} \u2192 426 (WebSocket no soportado; el cli\
206
+ ente cae a HTTP)`),d.once("error",()=>{}),d.once("finish",()=>d.destroy()),d.end(`HTTP/1.1 426 Upgrade Required\r
191
207
  connection: close\r
192
208
  content-length: 0\r
193
209
  \r
194
- `);}),await new Promise((u,m)=>{l.once("error",m),l.listen(t.puerto??8402,"127.0.0.1",()=>u());}),{puerto:l.address().port,cerrar:async()=>{await r?.stopAndDrain(),await new Promise(u=>l.close(()=>u()));}}}var He=["claude","codex","goose","qwen"];function Bt(t){return He.includes(t??"")}function Ut(t,e={}){let n=e.path??process.env.PATH??"",o=e.
210
+ `);}),await new Promise((u,d)=>{l.once("error",d),l.listen(t.puerto??8402,"127.0.0.1",()=>u());}),{puerto:l.address().port,cerrar:async()=>{await r?.stopAndDrain(),await new Promise(u=>l.close(()=>u()));}}}var Je=["claude","codex","goose","qwen"];function Gt(t){return Je.includes(t??"")}function Yt(t,e={}){let n=e.path??process.env.PATH??"",o=e.
195
211
  existe??existsSync,r=null;for(let s of n.split(";").filter(i=>i.length>0)){for(let i of [".exe",".com"]){let a=join(s,t+i);if(o(a))return {tipo:"exe",ruta:a}}if(r===null)for(let i of [".cmd",".bat"]){let a=join(s,t+
196
- i);if(o(a)){r=a;break}}}return r!==null?{tipo:"solo-shim",ruta:r}:{tipo:"no-encontrado"}}function Vt(t={}){let n=(t.env??process.env).BVSALA_CODEX_AUTH?.toLowerCase();if(n==="api-key"||n==="apikey")return "\
212
+ i);if(o(a)){r=a;break}}}return r!==null?{tipo:"solo-shim",ruta:r}:{tipo:"no-encontrado"}}function Qt(t={}){let n=(t.env??process.env).BVSALA_CODEX_AUTH?.toLowerCase();if(n==="api-key"||n==="apikey")return "\
197
213
  api-key";if(n==="chatgpt")return "chatgpt";let o=null;try{o=t.leerAuth?t.leerAuth():null;}catch{o=null;}if(o===null)return "api-key";try{let r=JSON.parse(o);return typeof r.auth_mode=="string"?r.auth_mode.
198
- toLowerCase().replace(/[^a-z]/g,"")==="apikey"?"api-key":"chatgpt":r.tokens!==void 0&&r.tokens!==null?"chatgpt":"api-key"}catch{return "api-key"}}var no={"api-key":{upstream:"https://api.openai.com",prefijo:"\
199
- /v1"},chatgpt:{upstream:"https://chatgpt.com",prefijo:"/backend-api/codex"}};function Ke(t,e,n,o={}){let r=`http://127.0.0.1:${e}`;switch(t){case "claude":return {bin:"claude",args:n,env:{ANTHROPIC_BASE_URL:r}};case "\
200
- goose":return {bin:"goose",args:n,env:{ANTHROPIC_HOST:r}};case "qwen":return {bin:"qwen",args:n,env:{ANTHROPIC_BASE_URL:r},nota:'Qwen Code solo enruta por aqu\xED con `security.auth.selectedType: "anthropic\
201
- "` en ~/.qwen/settings.json (ver `bvsala doctor`).'};case "codex":{let s=o.modoCodex??"api-key",i=no[s];return {bin:"codex",args:["-c",`openai_base_url="${r}${i.prefijo}"`,...n],env:{},upstream:i.upstream,
202
- 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\
203
- tokens.":"Auth por API key: el gateway enruta a api.openai.com/v1."}}}}function oo(t){let e=Number.parseInt(t.slice(8,10),10);return Number.isFinite(e)&&e%2===0?"palanca":"control"}function Ft(t){let e;try{e=JSON.parse(t());}catch{return null}if(typeof e!="object"||e===null)
204
- return null;let n=e,o=n.espia;return typeof o!="number"||!Number.isInteger(o)||o<1||o>65535?null:{activo:n.activo!==false,espia:o}}function qt(t){let{enrolamiento:e,espiaVivo:n,upstreamEnv:o,elisionEnv:r,
214
+ toLowerCase().replace(/[^a-z]/g,"")==="apikey"?"api-key":"chatgpt":r.tokens!==void 0&&r.tokens!==null?"chatgpt":"api-key"}catch{return "api-key"}}var vo={"api-key":{upstream:"https://api.openai.com",prefijo:"\
215
+ /v1"},chatgpt:{upstream:"https://chatgpt.com",prefijo:"/backend-api/codex"}};function We(t,e,n,o={},r=process.env){let s=`http://127.0.0.1:${e}`;switch(t){case "claude":return {bin:"claude",args:n,env:{
216
+ ANTHROPIC_BASE_URL:s,ENABLE_TOOL_SEARCH:r.ENABLE_TOOL_SEARCH??"true"}};case "goose":return {bin:"goose",args:n,env:{ANTHROPIC_HOST:s}};case "qwen":return {bin:"qwen",args:n,env:{ANTHROPIC_BASE_URL:s},nota:'\
217
+ Qwen Code solo enruta por aqu\xED con `security.auth.selectedType: "anthropic"` en ~/.qwen/settings.json (ver `bvsala doctor`).'};case "codex":{let i=o.modoCodex??"api-key",a=vo[i];return {bin:"codex",args:[
218
+ "-c",`openai_base_url="${s}${a.prefijo}"`,...n],env:{},upstream:a.upstream,nota:i==="chatgpt"?"Auth ChatGPT detectada: el gateway enruta a chatgpt.com/backend-api/codex. El tr\xE1fico de suscripci\xF3n se m\
219
+ ide (equivalente a precio de lista) pero no se monetiza: no hay factura por tokens.":"Auth por API key: el gateway enruta a api.openai.com/v1."}}}}function yo(t){let e=Number.parseInt(t.slice(8,10),10);return Number.isFinite(e)&&e%2===0?"palanca":"control"}function Xt(t){let e;try{e=JSON.parse(t());}catch{return null}if(typeof e!="object"||e===null)
220
+ return null;let n=e,o=n.espia;return typeof o!="number"||!Number.isInteger(o)||o<1||o>65535?null:{activo:n.activo!==false,espia:o}}function Zt(t){let{enrolamiento:e,espiaVivo:n,upstreamEnv:o,elisionEnv:r,
205
221
  hoyUtcIso:s}=t;if(!e)return {linea:"",aviso:false};if(!e.activo)return {linea:"anillo 2: enrolamiento en pausa (activo:false)",aviso:false};if(!n)return {linea:`anillo 2: enrolado pero el esp\xEDa NO escucha en :${e.
206
- espia} \u2014 NO encadeno (el tr\xE1fico de hoy no entra en el corpus). Arr\xE1ncalo con \`pnpm anillo2:espia\`.`,aviso:true};let i=oo(s),a=`http://127.0.0.1:${e.espia}`,c=o!==void 0&&o!=="",p=r!==void 0&&
207
- r!=="",f=[];return f.push(`anillo 2: ${s} UTC \u2192 brazo ${i.toUpperCase()}`),f.push(c?`upstream respetado del entorno (${o})`:`encadenado a :${e.espia}`),p&&f.push(`elisi\xF3n respetada del entorno (=${r}\
208
- )`),{...c?{}:{upstream:a},...p?{}:{elision:i==="palanca"?"1":"0"},brazo:i,linea:f.join(", "),aviso:false}}var ao="comprobar: en el log del gateway debe aparecer `[gateway] POST /v1/messages \u2026`; si ve\
209
- s `/v1/v1/messages`, sobra un /v1; si ves `POST /messages` a secas, falta uno.",co=[{id:"claude",nombre:"Claude Code",binario:"claude",configs:[],detectable:true,receta:({base:t})=>["usa `bvsala claude`\
222
+ espia} \u2014 NO encadeno (el tr\xE1fico de hoy no entra en el corpus). Arr\xE1ncalo con \`pnpm anillo2:espia\`.`,aviso:true};let i=yo(s),a=`http://127.0.0.1:${e.espia}`,c=o!==void 0&&o!=="",m=r!==void 0&&
223
+ r!=="",h=[];return h.push(`anillo 2: ${s} UTC \u2192 brazo ${i.toUpperCase()}`),h.push(c?`upstream respetado del entorno (${o})`:`encadenado a :${e.espia}`),m&&h.push(`elisi\xF3n respetada del entorno (=${r}\
224
+ )`),h.push("diales de elisi\xF3n APAGADOS (2026-09-09): el brazo ya no los arma"),{...c?{}:{upstream:a},brazo:i,linea:h.join(", "),aviso:false}}var wo="comprobar: en el log del gateway debe aparecer `[gateway] POST /v1/messages \u2026`; si ve\
225
+ s `/v1/v1/messages`, sobra un /v1; si ves `POST /messages` a secas, falta uno.",Eo=[{id:"claude",nombre:"Claude Code",binario:"claude",configs:[],detectable:true,receta:({base:t})=>["usa `bvsala claude`\
210
226
  \u2014 arranca el gateway en un puerto ef\xEDmero, lanza `claude` apunt\xE1ndole y lo apaga al salir.",`a mano: ANTHROPIC_BASE_URL=${t} claude (sin /v1: el cliente a\xF1ade /v1/messages)`]},{id:"co\
211
227
  dex",nombre:"Codex CLI",binario:"codex",configs:[join(".codex","config.toml"),join(".codex","auth.json")],detectable:true,receta:({base:t,rutas:e})=>["usa `bvsala codex` \u2014 el prefijo del base URL depende del \
212
228
  modo de auth y lo resuelve el envoltorio:",` API key \u2192 openai_base_url=${t}/v1`,` suscripci\xF3n ChatGPT \u2192 openai_base_url=${t}/backend-api/codex (tiene que terminar exactament\
@@ -222,41 +238,41 @@ Droid (Factory)",binario:"droid",configs:[join(".factory","settings.json")],dete
222
238
  idar en mano contra el log del gateway].`,"{",' "customModels": ['," {",' "model": "<id de modelo Anthropic>",',' "displayName": "<nombre visible>",',' "provider": "anthropic",',` \
223
239
  "baseUrl": "${t}",`,' "apiKey": "<tu API key de Anthropic>"'," }"," ]","}"]},{id:"cline",nombre:"Cline",configs:[],detectable:false,receta:({baseV1:t})=>["mecanismo: UI \u2192 proveedor Anthropic\
224
240
  \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: ${t}`]},{id:"kilo",nombre:"Kilo Code",configs:[],detectable:false,
225
- receta:({baseV1:t})=>["mecanismo: UI \u2192 proveedor custom, Provider API \xABAnthropic Messages\xBB. Probar CON /v1 primero (linaje Cline) [inferido: validar en mano].",`Base URL: ${t}`]}];function lo(t,e){
226
- let n=t.split(delimiter).filter(r=>r.length>0),o=process.platform==="win32"?["",".exe",".cmd",".bat"]:[""];return r=>n.some(s=>o.some(i=>e(join(s,r+i))))}async function Ht(t,e={}){if(!Number.isInteger(t)||t<1||
227
- t>65535)throw new RangeError(`[bvsala doctor] puerto inv\xE1lido: ${String(t)}`);let n=e.home??homedir(),o=e.existe??existsSync,r=e.enPath??lo(e.path??process.env.PATH??"",o),s=`http://127.0.0.1:${t}`,i=`${s}/v1`,
241
+ receta:({baseV1:t})=>["mecanismo: UI \u2192 proveedor custom, Provider API \xABAnthropic Messages\xBB. Probar CON /v1 primero (linaje Cline) [inferido: validar en mano].",`Base URL: ${t}`]}];function To(t,e){
242
+ let n=t.split(delimiter).filter(r=>r.length>0),o=process.platform==="win32"?["",".exe",".cmd",".bat"]:[""];return r=>n.some(s=>o.some(i=>e(join(s,r+i))))}async function en(t,e={}){if(!Number.isInteger(t)||t<1||
243
+ t>65535)throw new RangeError(`[bvsala doctor] puerto inv\xE1lido: ${String(t)}`);let n=e.home??homedir(),o=e.existe??existsSync,r=e.enPath??To(e.path??process.env.PATH??"",o),s=`http://127.0.0.1:${t}`,i=`${s}/v1`,
228
244
  a=[],c=[`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 \
229
- se lee el contenido de ning\xFAn archivo.",""];for(let p of co){let f=p.configs.map(v=>join(n,v)),l=p.binario!==void 0&&r(p.binario),h=f.filter(v=>o(v)),u=l||h.length>0;u&&a.push(p.id);let m;p.detectable?
230
- u?m=`detectado \u2014 ${[...l?[`binario \`${p.binario}\` en PATH`]:[],...h.map(E=>`config presente: ${E}`)].join("; ")}`:m="no detectado":m="sin detecci\xF3n autom\xE1tica (extensi\xF3n de editor)",c.
231
- push(`\xBB ${p.id}: ${m}`),c.push(` ${p.nombre}`);for(let v of p.receta({base:s,baseV1:i,rutas:f}))c.push(` ${v}`);c.push(` ${ao}`),c.push("");}return c.push("Regla BYOK: las recetas del anillo Anth\
245
+ se lee el contenido de ning\xFAn archivo.",""];for(let m of Eo){let h=m.configs.map(k=>join(n,k)),l=m.binario!==void 0&&r(m.binario),f=h.filter(k=>o(k)),u=l||f.length>0;u&&a.push(m.id);let d;m.detectable?
246
+ u?d=`detectado \u2014 ${[...l?[`binario \`${m.binario}\` en PATH`]:[],...f.map(E=>`config presente: ${E}`)].join("; ")}`:d="no detectado":d="sin detecci\xF3n autom\xE1tica (extensi\xF3n de editor)",c.
247
+ push(`\xBB ${m.id}: ${d}`),c.push(` ${m.nombre}`);for(let k of m.receta({base:s,baseV1:i,rutas:h}))c.push(` ${k}`);c.push(` ${wo}`),c.push("");}return c.push("Regla BYOK: las recetas del anillo Anth\
232
248
  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 \
233
249
  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:c.join(`
234
- `),detectados:a}}var Kt="savings-mode";function Jt(t,e){for(let n of t){let o=join(n,"skills",Kt,"SKILL.md");if(e.existe(o))return o}return null}var Wt="<!-- bvsala:savings-mode:inicio -->",Se="\
235
- <!-- bvsala:savings-mode:fin -->";function uo(t){let e=t.replace(/^---\n[\s\S]*?\n---\n*/,"").trim();return `${Wt}
250
+ `),detectados:a}}var tn="savings-mode";function nn(t,e){for(let n of t){let o=join(n,"skills",tn,"SKILL.md");if(e.existe(o))return o}return null}var on="<!-- bvsala:savings-mode:inicio -->",Ae="\
251
+ <!-- bvsala:savings-mode:fin -->";function Ao(t){let e=t.replace(/^---\n[\s\S]*?\n---\n*/,"").trim();return `${on}
236
252
  ${e}
237
253
 
238
254
  _Always on (AGENTS.md has no activation step). Delete this block to turn it off; \`bvsala skill --codex --forzar\` restores it._
239
- ${Se}`}function Gt(t){let e=Jt(t.origenes,t.fs);if(!e)return {ok:false,destino:"",mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${t.origenes.join(", ")})`};let n=uo(t.fs.
255
+ ${Ae}`}function rn(t){let e=nn(t.origenes,t.fs);if(!e)return {ok:false,destino:"",mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${t.origenes.join(", ")})`};let n=Ao(t.fs.
240
256
  leer(e)),o=t.proyecto?t.cwd:join(t.home,".codex"),r=join(o,"AGENTS.md");if(!t.fs.existe(r))return t.fs.crearDir(o),t.fs.escribir(r,n+`
241
- `),{ok:true,destino:r,mensaje:Je(r,"instalado")};let s=t.fs.leer(r),i=s.indexOf(Wt),a=s.indexOf(Se);return i===-1||a===-1||a<i?(t.fs.escribir(r,s.trimEnd()+`
257
+ `),{ok:true,destino:r,mensaje:Ge(r,"instalado")};let s=t.fs.leer(r),i=s.indexOf(on),a=s.indexOf(Ae);return i===-1||a===-1||a<i?(t.fs.escribir(r,s.trimEnd()+`
242
258
 
243
259
  `+n+`
244
- `),{ok:true,destino:r,mensaje:Je(r,"a\xF1adido al AGENTS.md existente")}):s.slice(i,a+Se.length)===n?{ok:true,destino:r,mensaje:`[bvsala skill] ya instalado y al d\xEDa: ${r}`}:t.forzar?(t.fs.escribir(r,s.
245
- slice(0,i)+n+s.slice(a+Se.length)),{ok:true,destino:r,mensaje:Je(r,"bloque actualizado")}):{ok:false,destino:r,mensaje:`[bvsala skill] el bloque savings-mode de ${r} tiene contenido DISTINTO \u2014 no lo piso; \
246
- usa --forzar para actualizarlo`}}function Je(t,e){return `[bvsala skill] ${e}: ${t}
260
+ `),{ok:true,destino:r,mensaje:Ge(r,"a\xF1adido al AGENTS.md existente")}):s.slice(i,a+Ae.length)===n?{ok:true,destino:r,mensaje:`[bvsala skill] ya instalado y al d\xEDa: ${r}`}:t.forzar?(t.fs.escribir(r,s.
261
+ slice(0,i)+n+s.slice(a+Ae.length)),{ok:true,destino:r,mensaje:Ge(r,"bloque actualizado")}):{ok:false,destino:r,mensaje:`[bvsala skill] el bloque savings-mode de ${r} tiene contenido DISTINTO \u2014 no lo piso; \
262
+ usa --forzar para actualizarlo`}}function Ge(t,e){return `[bvsala skill] ${e}: ${t}
247
263
  [bvsala skill] AGENTS.md va SIEMPRE activo en Codex (no hay paso de activaci\xF3n); borra el bloque para apagarlo.
248
- [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 Yt(t){let e=Jt(t.origenes,t.fs);if(!e)return {ok:false,destino:"",
249
- mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${t.origenes.join(", ")})`};let n=t.proyecto?join(t.cwd,".claude","skills"):join(t.home,".claude","skills"),o=join(n,Kt),r=join(o,
264
+ [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 sn(t){let e=nn(t.origenes,t.fs);if(!e)return {ok:false,destino:"",
265
+ mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${t.origenes.join(", ")})`};let n=t.proyecto?join(t.cwd,".claude","skills"):join(t.home,".claude","skills"),o=join(n,tn),r=join(o,
250
266
  "SKILL.md"),s=t.fs.leer(e);if(t.fs.existe(r)&&!t.forzar){let i=t.fs.leer(r)===s;return {ok:i,destino:r,mensaje:i?`[bvsala skill] ya instalado y al d\xEDa: ${r}`:`[bvsala skill] ya existe ${r} con conte\
251
267
  nido DISTINTO \u2014 no lo piso; usa --forzar para sobrescribir`}}return t.fs.crearDir(o),t.fs.escribir(r,s),{ok:true,destino:r,mensaje:`[bvsala skill] instalado: ${r}
252
268
  [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.
253
- [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 We=class{id;exact=false;constructor(e="heuristic"){this.id=e;}count(e){if(e.length===0)return 0;let n=e.match(/[A-Za-z]+|\d+|\s+|[^\sA-Za-z\d]/g)??[],o=0;for(let r of n){let s=r[0];if(/\s/.test(s)){let i=(r.
269
+ [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 Ye=class{id;exact=false;constructor(e="heuristic"){this.id=e;}count(e){if(e.length===0)return 0;let n=e.match(/[A-Za-z]+|\d+|\s+|[^\sA-Za-z\d]/g)??[],o=0;for(let r of n){let s=r[0];if(/\s/.test(s)){let i=(r.
254
270
  match(/\n/g)??[]).length;o+=i+Math.floor(Math.max(0,r.length-1)/2);}else /[A-Za-z]/.test(s)?o+=Math.max(1,Math.ceil(r.length/4)):/\d/.test(s)?o+=Math.max(1,Math.ceil(r.length/2)):o+=1;}return Math.max(o,
255
- Math.ceil(e.length/4))}},Ge=new We;var Ye=class{estimators=new Map;modelToTokenizer=new Map;fallbackId;constructor(e=Ge){this.fallbackId=e.id,this.estimators.set(e.id,e);}register(e){return this.estimators.set(e.id,e),this}mapModel(e,n){
271
+ Math.ceil(e.length/4))}},Qe=new Ye;var Xe=class{estimators=new Map;modelToTokenizer=new Map;fallbackId;constructor(e=Qe){this.fallbackId=e.id,this.estimators.set(e.id,e);}register(e){return this.estimators.set(e.id,e),this}mapModel(e,n){
256
272
  return this.modelToTokenizer.set(e,n),this}resolve(e){let n=e.tokenizer?this.estimators.get(e.tokenizer):void 0;if(n)return n;if(e.model){let o=this.modelToTokenizer.get(e.model);if(o){let r=this.estimators.
257
- get(o);if(r)return r}}return this.estimators.get(this.fallbackId)}count(e,n){return this.resolve(n).count(e)}};new Ye;new TextEncoder;new TextDecoder;new TextDecoder;var Ao={"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}};
258
- De(Ao);function Lo(t,e=300){return new Promise(n=>{let o=connect({port:t,host:"127.0.0.1"}),r=s=>{o.destroy(),n(s);};o.setTimeout(e,()=>r(false)),o.once("connect",()=>r(true)),o.once("error",()=>r(false));})}var[,,T,...N]=process.
259
- argv;function jo(){console.log(`bvsala ${K} \u2014 BiVelio Savings Layer
273
+ get(o);if(r)return r}}return this.estimators.get(this.fallbackId)}count(e,n){return this.resolve(n).count(e)}};new Xe;new TextEncoder;new TextDecoder;new TextDecoder;var Vo={"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}};
274
+ je(Vo);function Yo(t,e=300){return new Promise(n=>{let o=connect({port:t,host:"127.0.0.1"}),r=s=>{o.destroy(),n(s);};o.setTimeout(e,()=>r(false)),o.once("connect",()=>r(true)),o.once("error",()=>r(false));})}var[,,w,...B]=process.
275
+ argv;function Qo(){console.log(`bvsala ${Y} \u2014 BiVelio Savings Layer
260
276
 
261
277
  Comandos:
262
278
  gateway [--puerto N] Proxy local medidor (por defecto 8402) para terminales que
@@ -298,30 +314,43 @@ Entorno:
298
314
  Ante cualquier duda, la petici\xF3n viaja intacta. (Hasta 0.4.13
299
315
  la bandera era al rev\xE9s: \xAB=1 arma\xBB; en un A/B p\xE1sala SIEMPRE
300
316
  expl\xEDcita, =1 o =0, y no depender\xE1s de la versi\xF3n instalada.)
317
+ BVSALA_GATEWAY_MODELO_HERMANO
318
+ =1 sirve claude-fable-5 con claude-fable-5-1 (palanca C): misma
319
+ tarifa de entrada, salida y escritura de cach\xE9; la LECTURA de
320
+ cach\xE9 baja de 0,001 a 0,00025 por 1K tokens (cat\xE1logo). El
321
+ ahorro es una resta de dos precios sobre el mismo usage:
322
+ se mide sin A/B y entra en el titular medido del panel.
323
+ Solo si la licencia trae sibling_model_routing (fail-closed).
324
+ CAMBIA el model que ves en la respuesta (/cost, /status), y
325
+ encenderlo a mitad de un hilo paga UNA escritura fr\xEDa del
326
+ prefijo (cada modelo tiene su cach\xE9): arr\xE1ncalo con el terminal.
327
+ Apagar = quitar la variable o =0.
301
328
  BVSALA_CODEX_AUTH api-key | chatgpt \u2014 fuerza el modo de auth de Codex.
302
329
  BVSALA_GATEWAY_LOG =1 ense\xF1a el log por petici\xF3n tambi\xE9n dentro de los envoltorios
303
330
  (por defecto va silenciado para no pisar el TUI; mira el panel).
304
331
  CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 (Claude Code, solo API key) tus modelos en /model.
305
332
 
306
333
  El gateway nunca corta el tr\xE1fico: sin clave o con la ingesta ca\xEDda, reenv\xEDa y avisa.
307
- Tus prompts jam\xE1s salen de tu m\xE1quina \u2014 solo cuentas y coste. M\xE1s: savings.bivelio.com`);}var le=Bt(T);T!=="gateway"&&T!=="doctor"&&T!=="skill"&&!le&&(jo(),process.exit(T===void 0||T==="h\
308
- elp"||T==="--help"?0:1));if(T==="skill"){let t=dirname(fileURLToPath(import.meta.url)),e={origenes:[join(t,"..",".."),join(t,"..")],home:homedir(),cwd:process.cwd(),proyecto:N.includes("--proyecto"),forzar:N.includes("--forza\
309
- r"),fs:{existe:existsSync,leer:o=>readFileSync(o,"utf8"),escribir:(o,r)=>writeFileSync(o,r),crearDir:o=>mkdirSync(o,{recursive:true})}},n=N.includes("--codex")?Gt(e):Yt(e);console.log(n.mensaje),process.exit(n.ok?0:1);}var tt=N.indexOf("--\
310
- puerto"),Q=le?0:tt>=0?Number(N[tt+1]):8402;(!Number.isInteger(Q)||(T==="doctor"?Q<1:Q<0)||Q>65535)&&(console.error(`[bvsala ${T}] puerto inv\xE1lido: ${N[tt+1]}`),process.exit(1));if(T==="doctor"){N.includes(
311
- "--write")&&(console.error("[bvsala doctor] --write todav\xEDa no existe: el doctor solo imprime; copia el bloque a mano."),process.exit(1));let t=await Ht(Q);console.log(t.texto),process.exit(0);}var M=le?
312
- Ke(T,0,N,{modoCodex:T==="codex"?Vt({leerAuth:()=>readFileSync(join(homedir(),".codex","auth.json"),"utf8")}):void 0}):null,Ce=process.env.BIVELIO_SERVICE_KEY,$o=le&&process.env.BVSALA_GATEWAY_LOG!=="1",et=M?.upstream?
313
- null:Ft(()=>readFileSync(process.env.BVSALA_ANILLO2_FICHERO??join(homedir(),".bvsala","anillo2.json"),"utf8")),ce=qt({enrolamiento:et,espiaVivo:et!==null&&await Lo(et.espia),upstreamEnv:process.env.BVSALA_GATEWAY_UPSTREAM,
314
- elisionEnv:process.env.BVSALA_GATEWAY_ELISION,hoyUtcIso:new Date().toISOString().slice(0,10)}),nt=process.env.BVSALA_GATEWAY_UPSTREAM??ce.upstream,on=process.env.BVSALA_GATEWAY_ELISION??ce.elision,F=await Nt(
315
- {puerto:Q,...$o?{log:()=>{}}:{},...Ce?{serviceAccountKey:Ce}:{},...process.env.BVSALA_SEAT_ID?{seatId:process.env.BVSALA_SEAT_ID}:{},...nt?{upstream:nt}:M?.upstream?{upstream:M.upstream}:{},...process.
316
- env.BVSALA_GATEWAY_COALESCE==="1"?{coalescer:true}:{},...process.env.BVSALA_GATEWAY_SHADOW==="1"?{sombra:true}:{},elision:on!=="0",...process.env.BVSALA_METERING_URL?{meteringUrl:process.env.BVSALA_METERING_URL}:
317
- {}}),No=nt??M?.upstream??"https://api.anthropic.com";console.log(`[bvsala gateway] v${K} escuchando en http://127.0.0.1:${F.puerto} \u2192 ${No}`);console.log(`[bvsala gateway] medici\xF3n: ${Ce?"ACTI\
318
- VA (clave de servicio presente)":"APAGADA (falta BIVELIO_SERVICE_KEY)"}`);{let t=dt(on,Ce!==void 0);(t.aviso?console.error:console.log)(`[bvsala gateway] ${t.linea}`),ce.linea&&(ce.aviso?console.error:
319
- console.log)(`[bvsala gateway] ${ce.linea}`);}process.env.BVSALA_GATEWAY_UPSTREAM&&M?.upstream&&process.env.BVSALA_GATEWAY_UPSTREAM!==M.upstream&&console.error(`[bvsala ${T}] AVISO: BVSALA_GATEWAY_UPST\
320
- REAM=${process.env.BVSALA_GATEWAY_UPSTREAM} pisa el upstream de este terminal (${M.upstream}). Si no es lo que quieres, quita la variable.`);T==="codex"&&!kt()&&console.error(`[bvsala codex] AVISO: es\
321
- te 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(M&&le){let t=Ke(T,F.puerto,N,{...M.upstream?{modoCodex:M.
322
- upstream.includes("chatgpt.com")?"chatgpt":"api-key"}:{}});t.nota&&console.log(`[bvsala ${T}] ${t.nota}`);let e=t.bin;if(process.platform==="win32"){let o=Ut(t.bin);o.tipo==="exe"?e=o.ruta:o.tipo==="s\
323
- olo-shim"&&(console.error(`[bvsala ${T}] \`${t.bin}\` est\xE1 instalado como shim de npm (${o.ruta}) y Windows no puede lanzarlo de forma segura con argumentos (CVE-2024-27980). Inst\xE1lalo con su insta\
324
- lador nativo (deja un ${t.bin}.exe en el PATH) o usa la receta manual de docs/terminales/.`),await F.cerrar(),process.exit(127));}let n=spawn(e,t.args,{stdio:"inherit",env:{...process.env,...t.env}});n.on(
325
- "error",o=>{console.error(`[bvsala ${T}] no se pudo lanzar \`${t.bin}\`: ${String(o)}. \xBFEst\xE1 instalado y en el PATH?`),F.cerrar().then(()=>process.exit(127));}),n.on("exit",(o,r)=>{F.cerrar().then(
326
- ()=>process.exit(o??(r?1:0)));});}else console.log(`[bvsala gateway] apunta tu terminal (o usa \`bvsala ${He.join("|")}\`): ANTHROPIC_BASE_URL=http://127.0.0.1:${F.puerto} claude \xB7 bvsala doctor pa\
327
- ra el resto`);var rn=async()=>{await F.cerrar(),process.exit(0);};process.on("SIGINT",()=>{rn();});process.on("SIGTERM",()=>{rn();});
334
+ Tus prompts jam\xE1s salen de tu m\xE1quina \u2014 solo cuentas y coste. M\xE1s: savings.bivelio.com`);}var pe=Gt(w);w!=="gateway"&&w!=="doctor"&&w!=="skill"&&!pe&&(Qo(),process.exit(w===void 0||w==="h\
335
+ elp"||w==="--help"?0:1));if(w==="skill"){let t=dirname(fileURLToPath(import.meta.url)),e={origenes:[join(t,"..",".."),join(t,"..")],home:homedir(),cwd:process.cwd(),proyecto:B.includes("--proyecto"),forzar:B.includes("--forza\
336
+ r"),fs:{existe:existsSync,leer:o=>readFileSync(o,"utf8"),escribir:(o,r)=>writeFileSync(o,r),crearDir:o=>mkdirSync(o,{recursive:true})}},n=B.includes("--codex")?rn(e):sn(e);console.log(n.mensaje),process.exit(n.ok?0:1);}var ot=B.indexOf("--\
337
+ puerto"),ee=pe?0:ot>=0?Number(B[ot+1]):8402;(!Number.isInteger(ee)||(w==="doctor"?ee<1:ee<0)||ee>65535)&&(console.error(`[bvsala ${w}] puerto inv\xE1lido: ${B[ot+1]}`),process.exit(1));if(w==="doctor"){
338
+ B.includes("--write")&&(console.error("[bvsala doctor] --write todav\xEDa no existe: el doctor solo imprime; copia el bloque a mano."),process.exit(1));let t=await en(ee);console.log(t.texto),process.
339
+ exit(0);}var j=pe?We(w,0,B,{modoCodex:w==="codex"?Qt({leerAuth:()=>readFileSync(join(homedir(),".codex","auth.json"),"utf8")}):void 0}):null,de=process.env.BIVELIO_SERVICE_KEY,Xo=pe&&process.env.BVSALA_GATEWAY_LOG!=="1",
340
+ nt=j?.upstream?null:Xt(()=>readFileSync(process.env.BVSALA_ANILLO2_FICHERO??join(homedir(),".bvsala","anillo2.json"),"utf8")),ue=Zt({enrolamiento:nt,espiaVivo:nt!==null&&await Yo(nt.espia),upstreamEnv:process.env.BVSALA_GATEWAY_UPSTREAM,
341
+ elisionEnv:process.env.BVSALA_GATEWAY_ELISION,hoyUtcIso:new Date().toISOString().slice(0,10)}),rt=process.env.BVSALA_GATEWAY_UPSTREAM??ue.upstream,st=process.env.BVSALA_GATEWAY_ELISION??ue.elision,J=await Jt(
342
+ {puerto:ee,...Xo?{log:()=>{}}:{},...de?{serviceAccountKey:de}:{},...process.env.BVSALA_SEAT_ID?{seatId:process.env.BVSALA_SEAT_ID}:{},...rt?{upstream:rt}:j?.upstream?{upstream:j.upstream}:{},...process.
343
+ env.BVSALA_GATEWAY_COALESCE==="1"?{coalescer:true}:{},...process.env.BVSALA_GATEWAY_SHADOW==="1"?{sombra:true}:{},elision:st!=="0",...process.env.BVSALA_GATEWAY_DIALES_ELISION==="1"?{dialesElision:true}:{},
344
+ ...process.env.BVSALA_GATEWAY_MODELO_HERMANO==="1"?{modeloHermano:true}:{},...process.env.BVSALA_METERING_URL?{meteringUrl:process.env.BVSALA_METERING_URL}:{}}),Zo=rt??j?.upstream??"https://api.anthropi\
345
+ c.com";console.log(`[bvsala gateway] v${Y} escuchando en http://127.0.0.1:${J.puerto} \u2192 ${Zo}`);console.log(`[bvsala gateway] medici\xF3n: ${de?"ACTIVA (clave de servicio presente)":"APAGADA (fal\
346
+ ta BIVELIO_SERVICE_KEY)"}`);{let t=ht(st,de!==void 0,process.env.BVSALA_GATEWAY_DIALES_ELISION==="1");(t.aviso?console.error:console.log)(`[bvsala gateway] ${t.linea}`);let e=Tt(process.env.BVSALA_GATEWAY_MODELO_HERMANO,
347
+ de!==void 0,st!=="0");(e.aviso?console.error:console.log)(`[bvsala gateway] ${e.linea}`),ue.linea&&(ue.aviso?console.error:console.log)(`[bvsala gateway] ${ue.linea}`);}process.env.BVSALA_GATEWAY_UPSTREAM&&
348
+ j?.upstream&&process.env.BVSALA_GATEWAY_UPSTREAM!==j.upstream&&console.error(`[bvsala ${w}] AVISO: BVSALA_GATEWAY_UPSTREAM=${process.env.BVSALA_GATEWAY_UPSTREAM} pisa el upstream de este terminal (${j.
349
+ upstream}). Si no es lo que quieres, quita la variable.`);w==="codex"&&!Dt()&&console.error(`[bvsala codex] AVISO: este Node (${process.version}) no descomprime zstd y Codex manda el cuerpo en zstd: e\
350
+ l tr\xE1fico pasa pero NO se mide. Usa Node \u2265 22.15.`);if(j&&pe){let t=We(w,J.puerto,B,{...j.upstream?{modoCodex:j.upstream.includes("chatgpt.com")?"chatgpt":"api-key"}:{}});t.nota&&console.log(`\
351
+ [bvsala ${w}] ${t.nota}`);let e=t.bin;if(process.platform==="win32"){let o=Yt(t.bin);o.tipo==="exe"?e=o.ruta:o.tipo==="solo-shim"&&(console.error(`[bvsala ${w}] \`${t.bin}\` est\xE1 instalado como shim de\
352
+ npm (${o.ruta}) y Windows no puede lanzarlo de forma segura con argumentos (CVE-2024-27980). Inst\xE1lalo con su instalador nativo (deja un ${t.bin}.exe en el PATH) o usa la receta manual de docs/ter\
353
+ minales/.`),await J.cerrar(),process.exit(127));}let n=spawn(e,t.args,{stdio:"inherit",env:{...process.env,...t.env}});n.on("error",o=>{console.error(`[bvsala ${w}] no se pudo lanzar \`${t.bin}\`: ${String(
354
+ o)}. \xBFEst\xE1 instalado y en el PATH?`),J.cerrar().then(()=>process.exit(127));}),n.on("exit",(o,r)=>{J.cerrar().then(()=>process.exit(o??(r?1:0)));});}else console.log(`[bvsala gateway] apunta tu ter\
355
+ minal (o usa \`bvsala ${Je.join("|")}\`): ANTHROPIC_BASE_URL=http://127.0.0.1:${J.puerto} claude \xB7 bvsala doctor para el resto`);var mn=async()=>{await J.cerrar(),process.exit(0);};process.on("\
356
+ SIGINT",()=>{mn();});process.on("SIGTERM",()=>{mn();});
package/dist/index.d.ts CHANGED
@@ -205,7 +205,7 @@ declare function precioDeLista(model: string): CostModel | undefined;
205
205
  * on the customer's machine. `test/version-declarada.test.ts` ties this
206
206
  * constant to package.json so the two can never drift.
207
207
  */
208
- declare const BV_SALA_VERSION = "0.4.17";
208
+ declare const BV_SALA_VERSION = "0.4.19";
209
209
 
210
210
  /**
211
211
  * Environment-agnostic UUID generation.
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ cachedInputPer1k:75e-6},"gemini-3.5-flash":{inputPer1k:.0015,outputPer1k:.009,ca
18
18
  preview":{inputPer1k:.002,outputPer1k:.012,cachedInputPer1k:2e-4},"gemini-2.5-pro":{inputPer1k:.00125,outputPer1k:.01,cachedInputPer1k:125e-6},"gemini-2.5-flash":{inputPer1k:3e-4,outputPer1k:.0025,cachedInputPer1k:3e-5}};
19
19
  function dn(t,e,n){if(!n)return;let o=t[n];if(o)return o;let r=n.lastIndexOf("/"),s=r>=0?n.slice(r+1):n,i=t[s];if(i)return i;for(let a of e){if(!s.startsWith(a))continue;let c=s.charAt(a.length);if(c!==
20
20
  ""&&c!=="-"&&c!=="."&&c!=="_")continue;let l=s.slice(a.length+1);if(!(/^\d/.test(l)&&!/^\d{4}/.test(l)))return t[a]}}function pn(t){return Object.keys(t).sort((e,n)=>n.length-e.length)}var Qs=pn(bt);function xt(t){
21
- return dn(bt,Qs,t)}Object.fromEntries(Object.keys(bt).map(t=>[t,t]));var fn="0.4.17",Bo="x-bvsala-version";var ei=0;function mn(){let t=globalThis.crypto;if(t?.randomUUID)return t.randomUUID();let e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else {let o=++ei,r=Date.now?Date.now():0;for(let s=0;s<
21
+ return dn(bt,Qs,t)}Object.fromEntries(Object.keys(bt).map(t=>[t,t]));var fn="0.4.19",Bo="x-bvsala-version";var ei=0;function mn(){let t=globalThis.crypto;if(t?.randomUUID)return t.randomUUID();let e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else {let o=++ei,r=Date.now?Date.now():0;for(let s=0;s<
22
22
  16;s++)e[s]=(s<6?o>>>s*8:r>>>(s-6)*8)&255;}e[6]=e[6]&15|64,e[8]=e[8]&63|128;let n=[];for(let o=0;o<16;o++)n.push(e[o].toString(16).padStart(2,"0"));return `${n[0]}${n[1]}${n[2]}${n[3]}-${n[4]}${n[5]}-${n[6]}${n[7]}\
23
23
  -${n[8]}${n[9]}-${n[10]}${n[11]}${n[12]}${n[13]}${n[14]}${n[15]}`}var Gc=["exact","task_equivalent","not_verified","bounded_degradation","rejected"];function Zc(t){return {v:1,task:t.task,goal:t.goal,rules:t.rules??[],facts:t.facts??[],refs:t.refs??[],...t.delta?{delta:t.delta}:{},outputContract:t.outputContract}}var hn=class{id;exact=false;constructor(e="heuristic"){this.id=e;}count(e){if(e.length===0)return 0;let n=e.match(/[A-Za-z]+|\d+|\s+|[^\sA-Za-z\d]/g)??[],o=0;for(let r of n){let s=r[0];if(/\s/.test(s)){let i=(r.
24
24
  match(/\n/g)??[]).length;o+=i+Math.floor(Math.max(0,r.length-1)/2);}else /[A-Za-z]/.test(s)?o+=Math.max(1,Math.ceil(r.length/4)):/\d/.test(s)?o+=Math.max(1,Math.ceil(r.length/2)):o+=1;}return Math.max(o,
@@ -35,11 +35,21 @@ terminales a la vez):
35
35
 
36
36
  ```bash
37
37
  bvsala gateway # ventana 1: http://127.0.0.1:8402
38
- ANTHROPIC_BASE_URL=http://127.0.0.1:8402 claude # ventana 2 — SIN /v1
38
+ ENABLE_TOOL_SEARCH=true ANTHROPIC_BASE_URL=http://127.0.0.1:8402 claude # ventana 2 — SIN /v1
39
39
  ```
40
40
 
41
41
  Claude Code añade `/v1/messages` por su cuenta. Sin barra final.
42
42
 
43
+ **`ENABLE_TOOL_SEARCH=true` no es opcional.** Al ver un `ANTHROPIC_BASE_URL`
44
+ que no es el oficial, Claude Code apaga por defecto la búsqueda de herramientas
45
+ y mete TODAS las definiciones (las de tus servidores MCP incluidas) en el
46
+ prefijo cacheado de cada petición. Medido el 2026-09-09 en un montaje con 226
47
+ herramientas MCP: 450 KB por petición, el 66 % de los bytes y el 25 % de la
48
+ factura del día. El gateway reenvía la beta y los bloques `tool_reference`
49
+ intactos, así que la búsqueda funciona a través de él. `bvsala claude` la
50
+ activa solo; si ya tienes la variable fijada (`false`, `auto`, `auto:N`), se
51
+ respeta tu valor.
52
+
43
53
  ## Comprobar que funciona
44
54
 
45
55
  **Con `bvsala claude` (el envoltorio), la comprobación es tu dashboard**: el
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bivelio/savings-layer",
3
- "version": "0.4.17",
3
+ "version": "0.4.19",
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",