@bivelio/savings-layer 0.4.17 → 0.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -9
- package/dist/gateway/bin.js +296 -244
- package/dist/index.d.ts +45 -3
- package/dist/index.js +466 -459
- package/docs/terminales/README.md +4 -1
- package/docs/terminales/claude-code.md +11 -1
- package/package.json +7 -7
package/dist/gateway/bin.js
CHANGED
|
@@ -1,44 +1,36 @@
|
|
|
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 {
|
|
3
|
-
n.messages))return null;let o=
|
|
4
|
-
return null}}function
|
|
5
|
-
n)!==
|
|
6
|
-
|
|
7
|
-
s.value>0?s.value:1e5;
|
|
8
|
-
clear_tool_uses_20250919",
|
|
9
|
-
null&&typeof
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 B from'zlib';import {connect}from'net';var ge="context-management-2025-06-27";function Le(){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 bt(e,t){if(t!==void 0&&t!==""&&t!=="identity")return null;try{let n=JSON.parse(e.toString("utf8"));if(n===null||typeof n!="object"||Array.isArray(n)||typeof n.model!="string"||!Array.isArray(
|
|
3
|
+
n.messages))return null;let o=An(n.context_management),r=_n(n.context_management);return n.context_management=Cn(n.context_management),{cuerpo:Buffer.from(JSON.stringify(n),"utf8"),nuestros:o,triggerDelCliente:r}}catch{
|
|
4
|
+
return null}}function An(e){let t=e!==null&&typeof e=="object"&&!Array.isArray(e)?e.edits:void 0,n=(Array.isArray(t)?t:[]).filter(o=>o!==null&&typeof o=="object"&&!Array.isArray(o)&&o.type===je);return ht(
|
|
5
|
+
n)!==ht([Le().edits[0]])}function _n(e){let t=e!==null&&typeof e=="object"&&!Array.isArray(e)?e.edits:void 0,n=(Array.isArray(t)?t:[]).filter(r=>r!==null&&typeof r=="object"&&!Array.isArray(r)&&r.type===
|
|
6
|
+
je);if(n.length===0)return null;let o=Number.POSITIVE_INFINITY;for(let r of n){let s=r.trigger,a=s!==null&&typeof s=="object"&&s.type==="input_tokens"&&typeof s.value=="number"&&Number.isFinite(s.value)&&
|
|
7
|
+
s.value>0?s.value:1e5;a<o&&(o=a);}return o}function ht(e){return JSON.stringify(e,(t,n)=>n!==null&&typeof n=="object"&&!Array.isArray(n)?Object.fromEntries(Object.keys(n).sort().map(o=>[o,n[o]])):n)}var je="\
|
|
8
|
+
clear_tool_uses_20250919",gt="clear_thinking_20251015";function Cn(e){let t=Le().edits[0],n=e!==null&&typeof e=="object"&&!Array.isArray(e)?{...e}:{},o=(Array.isArray(n.edits)?n.edits:[]).filter(a=>a!==
|
|
9
|
+
null&&typeof a=="object"&&!Array.isArray(a)&&a.type!==je),r=o.filter(a=>a.type===gt),s=o.filter(a=>a.type!==gt);return {...n,edits:[...r,...s,t]}}function vt(e,t,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 e==="0"?{linea:"canal S4a: CERRADO (BVSALA_GATEWAY_ELISION=0) \u2014 sin rebaja de TTL y sin diales",aviso:false}:t?{linea:(e==="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"+(e==="1"?". Abre un termi\
|
|
13
|
+
nal nuevo o exporta la clave y relanza":""),aviso:e==="1"}}function yt(e){return e===void 0||e.trim()===""?ge:e.split(",").map(n=>n.trim()).filter(n=>n.length>0).includes(ge)?e:`${e},${ge}`}function z(e){let t=e.toLowerCase();return t.startsWith("gpt-")||t.startsWith("o1")||t.startsWith("o3")||t.startsWith("o4")?/^gpt-5\.6/.test(t)?1.25:1:t.startsWith("gemini")?1:1.25}function $e(e){let t=e.
|
|
14
|
+
toLowerCase();return t.startsWith("claude")||t.startsWith("anthropic/")?2:z(e)}var In=.3,Pn=4096,On=(e,t)=>e==="cache_control"?void 0:t;function Ne(e){return e===void 0?"":JSON.stringify(e,On)??""}function Dn(e){return Array.isArray(e)?e.filter(t=>!(t!==null&&typeof t=="object"&&
|
|
15
|
+
t.defer_loading===true)):e}function ze(e){return createHash("sha1").update(e).digest("base64url").slice(0,16)}function q(e,t){if(t!==void 0&&t!==""&&t!=="identity")return null;try{let n=JSON.parse(e.toString("u\
|
|
16
|
+
tf8"));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 kt(e){let t=Ne(e.system),n=Ne(
|
|
17
|
+
Dn(e.tools)),o=Array.isArray(e.messages)?e.messages.slice(0,Pn):[],r=[],s=[];for(let a of o){let i=Ne(a);r.push(ze(i)),s.push(Buffer.byteLength(i,"utf8"));}return {system:ze(t),tools:ze(n),mensajes:r,bytes:s,
|
|
18
|
+
bytesFijos:Buffer.byteLength(t,"utf8")+Buffer.byteLength(n,"utf8")}}function xt(e,t){if(e===void 0||e.system!==t.system||e.tools!==t.tools)return 1;let n=t.bytesFijos;for(let s of t.bytes)n+=s;if(n<=0)
|
|
19
|
+
return 1;let o=0;for(;o<e.mensajes.length&&o<t.mensajes.length&&e.mensajes[o]===t.mensajes[o];)o++;let r=0;for(let s=o;s<t.bytes.length;s++)r+=t.bytes[s]??0;return r/n}function St(e){let{fraccionNueva:t,
|
|
20
|
+
umbral:n=In}=e;return t>=n}function Be(e,t){if(e===null||typeof e!="object")return;if(Array.isArray(e)){for(let r of e)Be(r,t);return}let n=e,o=n.cache_control;if(o!==null&&typeof o=="object"&&!Array.
|
|
21
|
+
isArray(o)){let r=o;r.ttl==="1h"?(r.ttl="5m",t.rebajadas++):(r.ttl==="5m"||r.ttl===void 0)&&t.yaEran5m++;}for(let[r,s]of Object.entries(n))r!=="cache_control"&&s!==null&&typeof s=="object"&&Be(s,t);}function Et(e,t){
|
|
22
|
+
let n=Buffer.isBuffer(e)?q(e,t):e;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.stringify(
|
|
23
|
+
n),"utf8"),rebajadas:o.rebajadas,yaEran5m:o.yaEran5m}}catch{return null}}var be=class{constructor(t=512,n=3600*1e3){this.maxEntradas=t;this.maxEdadMs=n;}maxEntradas;maxEdadMs;visto=new Map;ultima(t,n){let o=this.visto.get(t);if(o!==void 0){if(n-o.vistoMs>this.maxEdadMs){this.
|
|
24
|
+
visto.delete(t);return}return o.huella}}anotar(t,n,o){for(this.visto.delete(t),this.visto.set(t,{huella:n,vistoMs:o});this.visto.size>this.maxEntradas;){let r=this.visto.keys().next();if(r.done===true)break;
|
|
25
|
+
this.visto.delete(r.value);}}get tamano(){return this.visto.size}};var wt="mid-conversation-output-config-2026-07-01",Ve=["low","medium","high","xhigh","max"],Mn=new Set(["claude-fable-5-1","claude-mythos-5-1","claude-opus-5"]);function Ln(e){return Mn.has(e)}function Fe(e){
|
|
26
|
+
return e!==void 0&&Ve.includes(e)}function jn(e){return {role:"system",content:[],output_config:{effort:e}}}function $n(e){if(e.output_config!==void 0&&e.output_config!==null)return true;let t=e.messages;
|
|
27
|
+
return Array.isArray(t)?t.some(n=>typeof n=="object"&&n!==null&&n.output_config!==void 0):false}function Tt(e,t,n){let o=q(e,n);if(o===null||typeof o.model!="string"||!Ln(o.model)||$n(o))return null;let r=o.
|
|
28
|
+
messages;return Array.isArray(r)?(o.messages=[...r,jn(t)],{cuerpo:Buffer.from(JSON.stringify(o),"utf8"),nivel:t}):null}function At(e){let t=(e??"").split(",").map(n=>n.trim()).filter(Boolean);return t.
|
|
29
|
+
includes(wt)||t.push(wt),t.join(",")}function _t(e,t,n){return e===void 0||e===""?{linea:`esfuerzo por turno (D): APAGADO (BVSALA_GATEWAY_ESFUERZO=${Ve.join("|")} lo arma)`,aviso:false}:Fe(e)?t?n?{linea:`\
|
|
30
|
+
esfuerzo por turno (D): ARMADO a "${e}" (activo si la licencia trae per_turn_effort; fail-closed). Solo fable-5-1, mythos-5-1 y opus-5; el resto pasa intacto. NO reinicia la cach\xE9 de prefijo: el dial \
|
|
31
|
+
se a\xF1ade al final, no reescribe nada anterior`,aviso:false}:{linea:"esfuerzo por turno (D): NO SE ARMA \u2014 el canal S4a est\xE1 CERRADO (BVSALA_GATEWAY_ELISION=0 apaga las palancas)",aviso:true}:{linea:"\
|
|
32
|
+
esfuerzo por turno (D): 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",aviso:true}:{linea:`esfuerzo por turno (D):\
|
|
33
|
+
NO SE ARMA \u2014 "${e}" no es un nivel. Usa uno de: ${Ve.join(", ")}`,aviso:true}}var ye={"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
34
|
"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
35
|
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
36
|
"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,208 +47,245 @@ able-5":{inputPer1k:.01,outputPer1k:.05,cachedInputPer1k:.001},"claude-fable-5-1
|
|
|
55
47
|
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
48
|
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
49
|
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
|
|
59
|
-
if(!n)return;let o=
|
|
60
|
-
"."&&c!=="_")continue;let
|
|
61
|
-
|
|
62
|
-
|
|
50
|
+
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 He(e,t,n){
|
|
51
|
+
if(!n)return;let o=e[n];if(o)return o;let r=n.lastIndexOf("/"),s=r>=0?n.slice(r+1):n,a=e[s];if(a)return a;for(let i of t){if(!s.startsWith(i))continue;let c=s.charAt(i.length);if(c!==""&&c!=="-"&&c!==
|
|
52
|
+
"."&&c!=="_")continue;let m=s.slice(i.length+1);if(!(/^\d/.test(m)&&!/^\d{4}/.test(m)))return e[i]}}function qe(e){return Object.keys(e).sort((t,n)=>n.length-t.length)}var Ct=qe(ye);function j(e){return He(
|
|
53
|
+
ye,Ct,e)}var Nn=Object.fromEntries(Object.keys(ye).map(e=>[e,e]));function Rt(e){return He(Nn,Ct,e)}var It={"claude-fable-5":"claude-fable-5-1"};function zn(e,t){let n=j(e),o=j(t);if(n===void 0||o===void 0||n.inputPer1k!==o.inputPer1k||n.outputPer1k!==o.outputPer1k||z(e)!==z(t))return false;let r=n.cachedInputPer1k??
|
|
54
|
+
n.inputPer1k;return (o.cachedInputPer1k??o.inputPer1k)<r}function Bn(e){let t=Rt(e);if(t===void 0||t!==e)return null;let n=It[t];return n===void 0||n===t||!zn(t,n)?null:{solicitado:e,servido:n}}var Un=/(^|,)\s*context-1m/i;
|
|
55
|
+
function Vn(e){let t=e.tool_choice;if(t===null||typeof t!="object")return false;let n=t.type;return n==="any"||n==="tool"}function Pt(e,t,n={}){if(n.betas!==void 0&&Un.test(n.betas))return null;let o=q(e,
|
|
56
|
+
t);if(o===null||Vn(o))return null;let r=Bn(o.model);return r===null?null:(o.model=r.servido,{cuerpo:Buffer.from(JSON.stringify(o),"utf8"),cambio:r})}function Ot(e,t,n){let o=Object.entries(It).map(([r,
|
|
57
|
+
s])=>`${r}\u2192${s}`).join(", ");return e!=="1"?{linea:"modelo hermano (C): APAGADO (BVSALA_GATEWAY_MODELO_HERMANO=1 lo arma)",aviso:false}:t?n?{linea:`modelo hermano (C): ARMADO (${o}; activo si la lic\
|
|
58
|
+
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\
|
|
59
|
+
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\
|
|
60
|
+
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",
|
|
61
|
+
aviso:true}}var Dt=new Set;function M(e,t){Dt.has(e)||(Dt.add(e),console.warn(t));}var Q="0.4.20",Mt="x-bvsala-version";var X=class{options;now;flushIntervalMs;maxBatch;maxBuffer;buffer=[];seatId;ci;timer;inflight=null;fallosSeguidos=0;constructor(t){this.options=t,this.now=t.now??(()=>Date.now()),this.flushIntervalMs=
|
|
62
|
+
t.flushIntervalMs??15e3,this.maxBatch=t.maxBatch??50,this.maxBuffer=t.maxBuffer??1e3,this.ci=t.ci??false;}setSeat(t,n){t&&(this.seatId=t),this.ci=n;}record(t){this.buffer.push({report:t,at:this.now()}),this.
|
|
63
|
+
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.
|
|
64
|
+
flushIntervalMs),this.timer.unref?.());}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0),this.flush();}async stopAndDrain(t){this.timer&&(clearInterval(this.timer),this.timer=void 0);let n=t??
|
|
65
|
+
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.
|
|
66
|
+
inflight)return this.inflight;if(this.buffer.length!==0){this.inflight=this.hacerFlush();try{await this.inflight;}finally{this.inflight=null;}}}async hacerFlush(){let t=this.options.fetchImpl??globalThis.
|
|
67
|
+
fetch;if(!t)return;let n=this.buffer.splice(0,this.maxBatch);try{let o=n.map(s=>this.toWire(s)),r=await t(this.options.url,{method:"POST",headers:{"content-type":"application/json",authorization:`Bear\
|
|
68
|
+
er ${this.options.serviceAccountKey}`,[Mt]:`${this.options.surface??"sdk"}/${Q}`},body:JSON.stringify(o)});r.ok?this.fallosSeguidos=0:r.status>=500?(this.fallosSeguidos++,this.requeue(n),this.avisarDeFallo(
|
|
69
|
+
`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}\
|
|
70
|
+
. 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.`),
|
|
71
|
+
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\
|
|
72
|
+
HTTP ${r.status}`));}catch(o){this.fallosSeguidos++,this.requeue(n),this.avisarDeFallo(o instanceof Error?o.message:"error de red");}}avisarDeFallo(t){if(this.options.silenceWarnings)return;let n=this.
|
|
73
|
+
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} (${t}). Las peticiones SIGUEN funcionando, pero el uso no \
|
|
74
|
+
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(t){
|
|
75
|
+
this.buffer=[...t,...this.buffer],this.buffer.length>this.maxBuffer&&(this.buffer.length=this.maxBuffer);}toWire(t){let n=t.report;return {orgId:this.options.orgId??"self",...this.seatId?{seatId:this.seatId}:
|
|
76
|
+
{},...this.ci?{ci:true}:{},requestId:n.requestId,model:n.model,at:t.at,avoidedLlm:n.calls.avoidedLlm,actualLlm:n.calls.actualLlm,baselineInputTokens:n.tokens.baselineInput,actualInputTokens:n.tokens.actualInput,
|
|
77
|
+
eliminatedInputTokens:n.tokens.eliminatedInput,compressedInputTokens:n.tokens.compressedInput,baselineOutputTokens:n.tokens.baselineOutput,actualOutputTokens:n.tokens.actualOutput,providerCachedInputTokens:n.
|
|
78
|
+
tokens.providerCachedInput??0,cacheResult:n.cache.result,...n.cost.eliminatedInputFloorCost!==void 0&&Number.isFinite(n.cost.eliminatedInputFloorCost)&&n.cost.eliminatedInputFloorCost>0&&n.tokens.eliminatedInput>
|
|
79
|
+
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.
|
|
80
|
+
attribution?.sessionId?{sessionId:n.attribution.sessionId}:{},...n.attribution?.agentId?{agentId:n.attribution.agentId}:{}}}};function ke(){return globalThis.process}function Fn(e){if(/^[0-9a-f]{12}$/.test(e)||/^\d{1,3}(\.\d{1,3}){3}$/.test(e)||/^ip-\d{1,3}(-\d{1,3}){3}$/i.test(e))return true;let t="[bcdfghjklmnpqrstvwxz2456789\
|
|
81
|
+
]";return new RegExp(`-${t}{8,10}-${t}{5}$`).test(e)}function Hn(e){return !!(e.AWS_LAMBDA_FUNCTION_NAME??e.LAMBDA_TASK_ROOT??e.VERCEL??e.VERCEL_ENV??e.K_SERVICE??e.FUNCTION_TARGET??e.FUNCTIONS_WORKER_RUNTIME??
|
|
82
|
+
e.NETLIFY)}async function qn(){if(ke()?.execPath)try{let t=await import(["node","os"].join(":")),n=typeof t.hostname=="function"?t.hostname():"";return n.length>0?n:void 0}catch{return}}async function Kn(e,t=qn){
|
|
83
|
+
if(e.KUBERNETES_SERVICE_HOST||Hn(e))return;let n=e.HOSTNAME??e.COMPUTERNAME??await t();if(!(!n||Fn(n)))return n}async function Jn(){let e=ke();if(!e||!e.env)return;let t=e.env,n=await Kn(t),o=[e.platform,
|
|
84
|
+
e.arch,e.execPath,n,t.USER??t.USERNAME??t.LOGNAME,t.HOME??t.USERPROFILE].filter(r=>typeof r=="string"&&r.length>0);return o.length?o.join("|"):void 0}var Gn=["CI","CONTINUOUS_INTEGRATION","GITHUB_ACTI\
|
|
85
|
+
ONS","GITLAB_CI","CIRCLECI","TRAVIS","JENKINS_URL","BUILDKITE","TF_BUILD","TEAMCITY_VERSION","BITBUCKET_BUILD_NUMBER","CODEBUILD_BUILD_ID","HEROKU_TEST_RUN_ID","DRONE"];function xe(){let e=ke()?.env;if(!e)
|
|
86
|
+
return false;for(let t of Gn){let n=e[t];if(n&&n!=="false"&&n!=="0")return true}return false}async function Wn(e,t){let n=globalThis.crypto,o=new TextEncoder;if(n?.subtle)try{let a=await n.subtle.importKey("raw",
|
|
87
|
+
o.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),i=await n.subtle.sign("HMAC",a,o.encode(t));return [...new Uint8Array(i)].map(c=>c.toString(16).padStart(2,"0")).join("")}catch{}let r=2166136261,s=`${e}\
|
|
88
|
+
|${t}`;for(let a=0;a<s.length;a++)r^=s.charCodeAt(a),r=Math.imul(r,16777619);return (r>>>0).toString(16).padStart(8,"0")}async function Se(e){let n=ke()?.env?.BVSALA_SEAT_ID;if(n&&Yn.test(n))return n;let o=await Jn();
|
|
89
|
+
if(!o)return;let r=await Wn(e,o);if(r)return `m-${r.slice(0,32)}`}var Yn=/^[A-Za-z0-9._:/-]{1,128}$/;var K=class{resto="";uso=null;elisionObservada=null;eventos={};observar(t){this.resto+=typeof t=="string"?t:t.toString("utf8");let n;for(;(n=this.resto.indexOf(`
|
|
63
90
|
|
|
64
91
|
`))>=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
|
|
66
|
-
{...this.uso?.cache_creation,...c.cache_creation}:void 0;this.uso={...this.uso,...c,...
|
|
67
|
-
uso:null}elision(){return this.elisionObservada}};function
|
|
68
|
-
n)||n<=0?0:
|
|
69
|
-
cleared_input_tokens;typeof s=="number"&&Number.isFinite(s)&&s>0&&(n+=s,r.type==="clear_tool_uses_20250919"&&(o+=s));}return {borrados:
|
|
70
|
-
try{let
|
|
71
|
-
|
|
92
|
+
let s=/^data: (.+)$/m.exec(o)?.[1];if(s)try{let a=JSON.parse(s),i=Lt(a.context_management);i&&(this.elisionObservada=i);let c=a.usage??a.message?.usage;if(c){let m=c.cache_creation||this.uso?.cache_creation?
|
|
93
|
+
{...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.
|
|
94
|
+
uso:null}elision(){return this.elisionObservada}};function Qn(e,t){if(!t||t.atribuible!==true||!(t.tokensLimpiadosToolUses>0))return 0;let n=e.cachedInputPer1k;return typeof n!="number"||!Number.isFinite(
|
|
95
|
+
n)||n<=0?0:t.tokensLimpiadosToolUses/1e3*n}function Lt(e){if(e===null||typeof e!="object")return null;let t=e.applied_edits;if(!Array.isArray(t)||t.length===0)return null;let n=0,o=0;for(let r of t){let s=r.
|
|
96
|
+
cleared_input_tokens;typeof s=="number"&&Number.isFinite(s)&&s>0&&(n+=s,r.type==="clear_tool_uses_20250919"&&(o+=s));}return {borrados:t.length,tokensLimpiados:n,tokensLimpiadosToolUses:o}}function jt(e){
|
|
97
|
+
try{let t=JSON.parse(typeof e=="string"?e:e.toString("utf8"));return Lt(t.context_management)}catch{return null}}var Ee=class{resto="";uso=null;eventos={};observar(t){this.resto+=typeof t=="string"?t:
|
|
98
|
+
t.toString("utf8");let n;for(;(n=this.resto.indexOf(`
|
|
72
99
|
|
|
73
|
-
`))>=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
|
|
74
|
-
parse(s);if((r??
|
|
75
|
-
0),n=Math.min(Math.max(0,
|
|
76
|
-
0),cache_read_input_tokens:n,cache_creation_input_tokens:o}}function
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
t,e)?.model;return typeof o=="string"?o:""}function
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
function
|
|
83
|
-
avoidedLlm:0,actualLlm:0},tokens:{baselineInput:0,actualInput:0,eliminatedInput:0,compressedInput:0,
|
|
84
|
-
actual:o,netSavings:n>0?Math.max(-100,Math.min(1,(n-o)/n)):0,basis:"shadow"}}}function
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
e.
|
|
91
|
-
|
|
92
|
-
`)
|
|
93
|
-
|
|
100
|
+
`))>=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 a=JSON.
|
|
101
|
+
parse(s);if((r??a.type)!=="response.completed")continue;let i=a.response?.usage;i&&(this.uso=Xn(i));}catch{}}}usage(){return this.uso}usageFinal(){return this.uso}};function Xn(e){let t=Math.max(0,e.input_tokens??
|
|
102
|
+
0),n=Math.min(Math.max(0,e.input_tokens_details?.cached_tokens??0),t),o=Math.min(Math.max(0,e.input_tokens_details?.cache_write_tokens??0),t-n);return {input_tokens:t-n-o,output_tokens:Math.max(0,e.output_tokens??
|
|
103
|
+
0),cache_read_input_tokens:n,cache_creation_input_tokens:o}}function $t(e,t,n){let o=e.cachedInputPer1k??e.inputPer1k;return t.entrada/1e3*e.inputPer1k+t.cacheLeida/1e3*o+(t.cacheEscrita-t.cacheEscrita1h)/
|
|
104
|
+
1e3*e.inputPer1k*z(n)+t.cacheEscrita1h/1e3*e.inputPer1k*2+t.salida/1e3*e.outputPer1k}function Nt(e,t){let n=j(e);if(!n)return null;let o=t.input_tokens??0,r=t.output_tokens??0,s=t.cache_read_input_tokens??
|
|
105
|
+
0,a=t.cache_creation,i=t.cache_creation_input_tokens??(a?.ephemeral_5m_input_tokens??0)+(a?.ephemeral_1h_input_tokens??0),c=Math.min(a?.ephemeral_1h_input_tokens??0,i),m={entrada:o,salida:r,cacheLeida:s,
|
|
106
|
+
cacheEscrita:i,cacheEscrita1h:c};return {costeUsd:$t(n,m,e),precio:n,tokens:m}}function zt(e,t){let o=Ke(e,t)?.model;return typeof o=="string"?o:""}function Ke(e,t){try{let n=e,o={maxOutputLength:Zn};switch((t??
|
|
107
|
+
"").trim().toLowerCase()){case "gzip":case "x-gzip":n=B.gunzipSync(e,o);break;case "deflate":n=B.inflateSync(e,o);break;case "br":n=B.brotliDecompressSync(e,o);break;case "zstd":{let r=B.zstdDecompressSync;
|
|
108
|
+
if(typeof r!="function")return null;n=r(e,o);break}default:break}return JSON.parse(n.toString("utf8"))}catch{return null}}var Zn=5*1024*1024;function Bt(){return typeof B.zstdDecompressSync=="function"}
|
|
109
|
+
function Je(e){try{return JSON.parse(typeof e=="string"?e:e.toString("utf8")).usage??null}catch{return null}}function Ut(e,t,n,o,r,s,a){return Ht(e,t,n,false,o,r,s,a)}function Vt(e,t,n,o){return Ht(e,t,n,
|
|
110
|
+
true,o)}function Ft(e,t,n,o,r){return {requestId:e,model:t,...r&&(r.sessionId||r.agentId)?{attribution:r}:{},calls:{avoidedLlm:0,actualLlm:0},tokens:{baselineInput:0,actualInput:0,eliminatedInput:0,compressedInput:0,
|
|
111
|
+
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 eo(e,t){let n=j(
|
|
112
|
+
e.solicitado);return n===void 0?0:Math.max(0,$t(n,t.tokens,e.solicitado)-t.costeUsd)}function Ht(e,t,n,o,r,s,a,i){let c=n.tokens.entrada+n.tokens.cacheLeida+n.tokens.cacheEscrita,m=n.tokens.cacheEscrita-
|
|
113
|
+
n.tokens.cacheEscrita1h,f=!o&&a&&a.rebajadas>0&&a.yaEran5m===0&&m>0?m/1e3*n.precio.inputPer1k*(2-1.25):0,l=!o&&i?eo(i,n):0,h=n.costeUsd+f+l,u=f+l,d=o?0:Qn(n.precio,s);return {requestId:e,model:t,...r&&
|
|
114
|
+
(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,
|
|
115
|
+
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,
|
|
116
|
+
basis:"estimated"}:{baselineEstimate:h,actual:n.costeUsd,netSavings:h>0?Math.max(-100,Math.min(1,u/h)):0,basis:"measured",...d>0?{eliminatedInputFloorCost:d}:{}}}}var to=1024,ce=120,no=8,oo=256*1024,ro=/error|exception|traceback|warn|fatal|fail|panic|assert|denied|refused|timeout|\bat\s+\S+:\d+/i,Jt=/^\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)/;
|
|
117
|
+
function so(e){return Buffer.byteLength(typeof e=="string"?e:JSON.stringify(e??""))}function ao(e){return typeof e=="string"?e:Array.isArray(e)?e.map(t=>t&&typeof t=="object"&&typeof t.text=="string"?
|
|
118
|
+
t.text:"").join(`
|
|
119
|
+
`):""}var io=/^\s*\d+[\t→]/;function Gt(e){return e.replace(io,"")}function co(e){if(!e)return "otro";let t=e.split(`
|
|
120
|
+
`),n=Math.max(1,t.length),o=0,r=0,s=0;for(let a of t){let i=Gt(a);(/^[+-](?![+-])/.test(i)||i.startsWith("@@")||i.startsWith("diff --git"))&&(o+=1),Jt.test(i)&&(r+=1),(/^\s*(\d{4}-\d{2}-\d{2}|\[\d|\d{2}:\d{2}:\d{2})/.
|
|
121
|
+
test(i)||/\b(INFO|DEBUG|TRACE|WARN|ERROR)\b/.test(i))&&(s+=1);}return o/n>.25?"diff":s/n>.3?"log":r/n>.08?"codigo":"otro"}function lo(e,t){if(t==="diff"||t==="otro")return Buffer.byteLength(e);let n=e.
|
|
94
122
|
split(`
|
|
95
|
-
`),o=new Set;for(let s=0;s<n.length;s++){let
|
|
96
|
-
n[s])+1;return Math.min(r,Buffer.byteLength(
|
|
97
|
-
n:${JSON.stringify(
|
|
98
|
-
function
|
|
99
|
-
|
|
100
|
-
let
|
|
101
|
-
n("tools",o);if(Array.isArray(
|
|
102
|
-
"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
|
|
103
|
-
:${
|
|
104
|
-
return n}function
|
|
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>=
|
|
106
|
-
|
|
107
|
-
var
|
|
108
|
-
o:null}escribir(
|
|
109
|
-
|
|
110
|
-
value;if(n===void 0)break;this.entradas.delete(n);}}};function
|
|
111
|
-
"|").update(
|
|
112
|
-
t");
|
|
113
|
-
5m";hayPrevio=false;atPrevio=0;acumulado=
|
|
114
|
-
s,this.previoUltimoBp=-1,this.previoTtl="5m",this.hayPrevio=true,this.atPrevio=
|
|
115
|
-
x.tipo,x.bytes),0),
|
|
116
|
-
n.tokensEntrada+=f[
|
|
117
|
-
n.tokensEntrada,this.acumulado.entradaUsd+=n.entradaUsd,this.acumulado.totalUsd+=n.totalUsd,n}let
|
|
118
|
-
|
|
119
|
-
[]:this.previo.slice(
|
|
120
|
-
S/1e3*r.inputPer1k;continue}for(;u[
|
|
121
|
-
A.length&&(A[
|
|
122
|
-
atPrevio=
|
|
123
|
+
`),o=new Set;for(let s=0;s<n.length;s++){let a=Gt(n[s]);(t==="log"?ro.test(a):Jt.test(a))&&(o.add(s),t==="log"&&(s>0&&o.add(s-1),s<n.length-1&&o.add(s+1)));}let r=ce;for(let s of o)r+=Buffer.byteLength(
|
|
124
|
+
n[s])+1;return Math.min(r,Buffer.byteLength(e))}var uo=(e,t)=>e==="cache_control"?void 0:t;function po(e){if(typeof e=="string")return `text:${e}`;if(!e||typeof e!="object"||Array.isArray(e))return `jso\
|
|
125
|
+
n:${JSON.stringify(e??"")}`;let t=e;return t.type==="text"&&typeof t.text=="string"&&Object.keys(t).every(n=>n==="type"||n==="text"||n==="cache_control")?`text:${t.text}`:`json:${JSON.stringify(t,uo)}`}
|
|
126
|
+
function mo(e){return createHash("sha256").update(po(e)).digest("hex").slice(0,16)}function fo(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e.cache_control;return !t||typeof t!="object"?null:
|
|
127
|
+
t.ttl==="1h"?"1h":"5m"}function Wt(e){let t=[],n=(o,r)=>{let s=so(r),a={clave:mo(r),tipo:o,marca:fo(r),bytes:s,bytesV1:s,clase:"otro",esError:false};if(o.endsWith(":tool_result")&&r&&typeof r=="object"){
|
|
128
|
+
let i=r;a.esError=i.is_error===true;let c=ao(i.content);a.clase=co(c);let m=s-Buffer.byteLength(c);a.bytesV1=Math.min(s,Math.max(0,m)+lo(c,a.clase));}t.push(a);};if(Array.isArray(e.tools))for(let o of e.tools)
|
|
129
|
+
n("tools",o);if(Array.isArray(e.system))for(let o of e.system)n("system",o);else (e.system??void 0)!==void 0&&n("system",e.system);for(let o of Array.isArray(e.messages)?e.messages:[]){if(!o||typeof o!=
|
|
130
|
+
"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 a of r.content)n(`${s}\
|
|
131
|
+
:${a?.type??"?"}`,a);}return t}function ho(){return {nacimiento:new Map,turno:0,elididosV2m:new Set}}function go(e,t){let n=e.turno++;for(let o of t)e.nacimiento.has(o.clave)||e.nacimiento.set(o.clave,n);
|
|
132
|
+
return n}function Yt(e,t,n,o,r=oo){let s=t.reduce((l,h,u)=>h.tipo.endsWith(":tool_result")?u:l,-1),a=(l,h)=>l.tipo.endsWith(":tool_result")&&l.bytes>=to&&h!==s;return t.map((l,h)=>{if(!a(l,
|
|
133
|
+
h))return {clave:l.clave,bytes:l.bytes};let u=o-(n.nacimiento.get(l.clave)??o);return u>=2&&u*l.bytes/1024>=no?{clave:`${l.clave}:e`,bytes:ce}:{clave:l.clave,bytes:l.bytes}});}function bo(e){let t=j(e);return t?{inputPer1k:t.inputPer1k,lecturaPer1k:t.cachedInputPer1k??t.inputPer1k,escrituraPer1k:t.inputPer1k*
|
|
134
|
+
z(e),escritura1hPer1k:t.inputPer1k*$e(e)}:null}function qt(){return {lecturaUsd:0,escrituraUsd:0,entradaUsd:0,totalUsd:0,tokensLeidos:0,tokensEscritos:0,tokensEntrada:0,tokensInvalidados:0,invalidacionUsd:0}}
|
|
135
|
+
var We={"1h":36e5,"5m":3e5},vo=20,yo=6e3,ko=2e4,Z=class{constructor(t=ko){this.tope=t;}tope;entradas=new Map;get size(){return this.entradas.size}viva(t,n){let o=this.entradas.get(t);return o&&n<=o.expira?
|
|
136
|
+
o:null}escribir(t,n,o){this.entradas.delete(t),this.entradas.set(t,{expira:n+We[o],ttl:o}),this.entradas.size>this.tope&&this.podar(n);}refrescar(t,n){let o=this.entradas.get(t);o&&(this.entradas.delete(
|
|
137
|
+
t),this.entradas.set(t,{expira:n+We[o.ttl],ttl:o.ttl}));}podar(t){for(let[n,o]of this.entradas)t>o.expira&&this.entradas.delete(n);for(;this.entradas.size>this.tope;){let n=this.entradas.keys().next().
|
|
138
|
+
value;if(n===void 0)break;this.entradas.delete(n);}}};function xo(e,t){let n=new Array(t.length),o=createHash("sha256").update(`model:${e}`).digest("hex");for(let r=0;r<t.length;r++)o=createHash("sha256").update(o).update(
|
|
139
|
+
"|").update(t[r]).digest("hex").slice(0,32),n[r]=o;return n}function So(e){let t=new Array(e.length),n=-1,o="";for(let r=0;r<e.length;r++){let s=e[r],a=s.endsWith(":tool_use")||s.endsWith(":tool_resul\
|
|
140
|
+
t");a&&s===o||(n+=1),o=a?s:"",t[r]=n;}return t}function Kt(e,t){return e.endsWith(":image")?Math.min(t,yo):t}var le=class{constructor(t,n){this.transformar=t;this.cache=n??new Z;}transformar;estado=ho();cache;previo=[];previoUltimoBp=-1;previoTtl="\
|
|
141
|
+
5m";hayPrevio=false;atPrevio=0;acumulado=qt();paso(t){let n=qt(),o=go(this.estado,t.bloques),r=bo(t.model),s=this.transformar(t.bloques,this.estado,o);if(!r||t.entradaReal<=0||s.length===0)return this.previo=
|
|
142
|
+
s,this.previoUltimoBp=-1,this.previoTtl="5m",this.hayPrevio=true,this.atPrevio=t.at,n;let a=s.map((p,x)=>t.bloques[x]?.tipo??""),i=s.map((p,x)=>t.bloques[x]?.marca??null),c=t.bloques.reduce((p,x)=>p+Kt(
|
|
143
|
+
x.tipo,x.bytes),0),m=c>0?t.entradaReal/c:0,f=s.map((p,x)=>Kt(a[x],p.bytes)*m),l=xo(t.model,s.map(p=>p.clave)),h=So(a),u=i.map((p,x)=>p?x:-1).filter(p=>p>=0);if(u.length===0){for(let p=0;p<s.length;p++)
|
|
144
|
+
n.tokensEntrada+=f[p],n.entradaUsd+=f[p]/1e3*r.inputPer1k;return n.totalUsd=n.entradaUsd,this.previo=s,this.previoUltimoBp=-1,this.previoTtl="5m",this.hayPrevio=true,this.atPrevio=t.at,this.acumulado.tokensEntrada+=
|
|
145
|
+
n.tokensEntrada,this.acumulado.entradaUsd+=n.entradaUsd,this.acumulado.totalUsd+=n.totalUsd,n}let d=-1;for(let p of u){let x=h[p]-(vo-1);for(let S=p;S>=0&&h[S]>=x;S--)if(this.cache.viva(l[S],t.at)){S>
|
|
146
|
+
d&&(d=S);break}}for(let p=0;p<=d;p++)this.cache.refrescar(l[p],t.at);let k=u[u.length-1];for(let p of u)p>d&&this.cache.escribir(l[p],t.at,i[p]);let w=0,A=this.hayPrevio&&t.at-this.atPrevio>We[this.previoTtl]?
|
|
147
|
+
[]:this.previo.slice(d+1,this.previoUltimoBp+1),b=0;for(let p=0;p<s.length;p++){let x=s[p],S=f[p];if(p<=d){n.tokensLeidos+=S,n.lecturaUsd+=S/1e3*r.lecturaPer1k;continue}if(p>k){n.tokensEntrada+=S,n.entradaUsd+=
|
|
148
|
+
S/1e3*r.inputPer1k;continue}for(;u[w]<p;)w+=1;let O=i[u[w]]==="1h"?r.escritura1hPer1k:r.escrituraPer1k;n.tokensEscritos+=S,n.escrituraUsd+=S/1e3*O;let _=b;for(;_<A.length&&A[_].clave!==x.clave;)_+=1;_<
|
|
149
|
+
A.length&&(A[_].bytes===x.bytes&&(n.tokensInvalidados+=S,n.invalidacionUsd+=S/1e3*(O-r.lecturaPer1k)),b=_+1);}return this.previo=s,this.previoUltimoBp=k,this.previoTtl=i[k]??"5m",this.hayPrevio=true,this.
|
|
150
|
+
atPrevio=t.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
151
|
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
|
|
125
|
-
0),o=(
|
|
126
|
-
0)>0};if(r.bloques.length===0)return null;let s=this.cadenaPara(this.clave(
|
|
127
|
-
if(
|
|
128
|
-
"hex").slice(0,16)}\xB7${
|
|
129
|
-
cachesDe(n);if(o={base:new
|
|
130
|
-
|
|
131
|
-
fetchImpl??fetch,this.log=
|
|
132
|
-
enVuelo:(this.enVuelo=this.pedir().finally(()=>{this.enVuelo=null;}),this.enVuelo)}async pedir(){try{let
|
|
133
|
-
timeout(1e4)});if(!
|
|
152
|
+
this.acumulado.invalidacionUsd+=n.invalidacionUsd,n}};function Qt(e){return e.map(t=>({clave:t.clave,bytes:t.bytes}))}var wo=64,we=class{cadenas=new Map;cachesPorModelo=new Map;observar(t){let n=t.uso.cache_creation_input_tokens??(t.uso.cache_creation?.ephemeral_5m_input_tokens??0)+(t.uso.cache_creation?.ephemeral_1h_input_tokens??
|
|
153
|
+
0),o=(t.uso.input_tokens??0)+(t.uso.cache_read_input_tokens??0)+n;if(o<=0)return null;let r={bloques:Wt(t.cuerpo),at:t.at,model:t.model,entradaReal:o,escritura1h:(t.uso.cache_creation?.ephemeral_1h_input_tokens??
|
|
154
|
+
0)>0};if(r.bloques.length===0)return null;let s=this.cadenaPara(this.clave(t),t.model),a=s.base.paso(r),i=s.v0.paso(r);return a.totalUsd<=0&&i.totalUsd<=0?null:{baselineUsd:a.totalUsd,politicaUsd:i.totalUsd}}clave(t){
|
|
155
|
+
if(t.sessionId)return `s:${t.sessionId}\xB7a:${t.agentId??""}\xB7${t.model}`;let n=Array.isArray(t.cuerpo.messages)?t.cuerpo.messages[0]:void 0;return `m:${createHash("sha256").update(JSON.stringify(n??null)).digest(
|
|
156
|
+
"hex").slice(0,16)}\xB7${t.model}`}cachesDe(t){let n=this.cachesPorModelo.get(t);return n||(n={base:new Z,v0:new Z},this.cachesPorModelo.set(t,n)),n}cadenaPara(t,n){let o=this.cadenas.get(t);if(!o){let r=this.
|
|
157
|
+
cachesDe(n);if(o={base:new le(s=>Qt(s),r.base),v0:new le((s,a,i)=>Yt("v0",s,a,i),r.v0),ultimoUso:0},this.cadenas.set(t,o),this.cadenas.size>wo){let s=null,a=1/0;for(let[i,c]of this.cadenas)c.ultimoUso<
|
|
158
|
+
a&&(a=c.ultimoUso,s=i);s!==null&&this.cadenas.delete(s);}}return o.ultimoUso=Date.now(),o}};var Te=class{url;clave;ttlMs;fetchImpl;log;features=new Set;validoHasta=0;enVuelo=null;avisado=false;constructor(t){this.url=t.url,this.clave=t.serviceAccountKey,this.ttlMs=t.ttlMs??3e5,this.fetchImpl=t.
|
|
159
|
+
fetchImpl??fetch,this.log=t.log??(()=>{}),this.refrescar();}tiene(t){return Date.now()>this.validoHasta&&this.enVuelo===null&&this.refrescar(),this.features.has(t)}refrescar(){return this.enVuelo?this.
|
|
160
|
+
enVuelo:(this.enVuelo=this.pedir().finally(()=>{this.enVuelo=null;}),this.enVuelo)}async pedir(){try{let t=await this.fetchImpl(this.url,{method:"GET",headers:{authorization:`Bearer ${this.clave}`},signal:AbortSignal.
|
|
161
|
+
timeout(1e4)});if(!t.ok){this.cerrar(`entitlements HTTP ${t.status}`);return}let n=await t.json();if(!Array.isArray(n.features)||!n.features.every(r=>typeof r=="string")){this.cerrar("entitlements con\
|
|
134
162
|
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
|
-
Date.now()+o,this.avisado=!1;}catch(
|
|
136
|
-
titlements no disponibles (${
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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(`
|
|
147
|
-
`).update(e).update(`
|
|
163
|
+
Date.now()+o,this.avisado=!1;}catch(t){this.cerrar(String(t));}}cerrar(t){this.features=new Set,this.validoHasta=Date.now()+Math.min(6e4,this.ttlMs),this.avisado||(this.avisado=true,this.log(`[gateway] en\
|
|
164
|
+
titlements no disponibles (${t}) \u2014 palanca apagada (fail-closed)`));}};function Xt(e){let t=0,n=0;for(;;){let r=e.indexOf('"input_schema"',n);if(r<0)break;t+=1,n=r+14;}let o=0;for(n=0;;){let r=e.indexOf('"tool_reference"',n);if(r<0)break;o+=1,n=r+16;}return {definiciones:t,
|
|
165
|
+
referencias:o}}var To=40;function Zt(e){return e.referencias>0||e.definiciones<To?null:`[bvsala gateway] tu cliente manda ${e.definiciones} definiciones de herramientas ENTERAS en cada petici\xF3n y no u\
|
|
166
|
+
sa la b\xFAsqueda de herramientas. Con un proxy delante, Claude Code la apaga por defecto: \`bvsala claude\` la reactiva, pero solo en una VENTANA NUEVA. Si lanzaste el terminal a mano, exporta ENABLE_TOOL\
|
|
167
|
+
_SEARCH=true. En el corpus de la casa ese bloque era el 24,5 % del dinero de entrada.`}var Ye=5*1024*1024,_o=["authorization","x-api-key","anthropic-version","anthropic-beta"];function en(e,t,n,o=""){return createHash("sha256").update(e).update(`
|
|
168
|
+
`).update(t).update(`
|
|
148
169
|
`).update(o).update(`
|
|
149
|
-
`).update(n).digest("hex")}function
|
|
150
|
-
`)}var
|
|
151
|
-
s=0,
|
|
152
|
-
this.enVuelo.delete(
|
|
153
|
-
1),o}tieneEnVuelo(
|
|
154
|
-
u)),r;if(
|
|
155
|
-
{},onAuthError:
|
|
156
|
-
evisa BIVELIO_SERVICE_KEY y el estado de la suscripci\xF3n en savings.bivelio.com.`)});let u=
|
|
157
|
-
|
|
158
|
-
let s=
|
|
159
|
-
ing/usage").toString(),serviceAccountKey:
|
|
160
|
-
if(!r||!
|
|
161
|
-
se mide.`);return}let C=
|
|
162
|
-
\xB7 $${
|
|
163
|
-
tokens.salida})`+(
|
|
164
|
-
0?
|
|
165
|
-
|
|
166
|
-
uso:
|
|
167
|
-
|
|
168
|
-
\u2192 v0 $${
|
|
169
|
-
l=createServer(async(u,
|
|
170
|
-
null||
|
|
171
|
-
0)+
|
|
172
|
-
return
|
|
173
|
-
{},...
|
|
174
|
-
return Array.isArray(
|
|
175
|
-
for(let
|
|
176
|
-
for(let[
|
|
177
|
-
"context_elision"))try{let
|
|
178
|
-
method==="POST"&&
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
170
|
+
`).update(n).digest("hex")}function tn(e){return _o.map(t=>`${t}=${e(t)??""}`).join(`
|
|
171
|
+
`)}var Ae=class{enVuelo=new Map;primarias=0;gemelas=0;registrar(t){if(this.enVuelo.has(t))return null;this.primarias+=1;let n,o=new Promise(i=>n=i);this.enVuelo.set(t,{promesa:o,resolver:n});let r=[],
|
|
172
|
+
s=0,a=false;return {capturar:i=>{if(!a){if(s+=i.length,s>Ye){a=true,r.length=0;return}r.push(i);}},terminar:(i,c)=>{let m=!a&&i>=200&&i<300;this.enVuelo.get(t)?.resolver(m?{status:i,headers:c,chunks:r}:null),
|
|
173
|
+
this.enVuelo.delete(t);},abortar:()=>{this.enVuelo.get(t)?.resolver(null),this.enVuelo.delete(t);}}}async esperar(t){let n=this.enVuelo.get(t);if(!n)return null;let o=await n.promesa;return o&&(this.gemelas+=
|
|
174
|
+
1),o}tieneEnVuelo(t){return this.enVuelo.has(t)}};var Io=["content-encoding","content-length","transfer-encoding"];async function nn(e={}){let t=(e.upstream??"https://api.anthropic.com").replace(/\/+$/,""),n=e.fetchImpl??fetch,o=e.log??(u=>console.log(
|
|
175
|
+
u)),r;if(e.serviceAccountKey){r=new X({url:e.meteringUrl??"https://savings.bivelio.com/api/metering/usage",serviceAccountKey:e.serviceAccountKey,surface:"gateway",...e.fetchImpl?{fetchImpl:e.fetchImpl}:
|
|
176
|
+
{},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\
|
|
177
|
+
evisa BIVELIO_SERVICE_KEY y el estado de la suscripci\xF3n en savings.bivelio.com.`)});let u=xe();e.seatId?r.setSeat(e.seatId,u):Se(e.serviceAccountKey).then(d=>r?.setSeat(d,u)).catch(()=>{}),r.start();}else
|
|
178
|
+
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.");
|
|
179
|
+
let s=e.coalescer?new Ae:null,a=e.sombra&&r?new we:null,i=new be,c=e.elision!==false&&e.serviceAccountKey?new Te({url:new URL("/api/org/entitlements",e.meteringUrl??"https://savings.bivelio.com/api/meter\
|
|
180
|
+
ing/usage").toString(),serviceAccountKey:e.serviceAccountKey,...e.fetchImpl?{fetchImpl:e.fetchImpl}:{},log:o}):null,m=u=>u==="/v1/messages"?new K:u.endsWith("/responses")?new Ee:null,f=(u,d,k,w,I,A,b,p,x,S,O)=>{
|
|
181
|
+
if(!r||!k)return;let _=r,oe=k,C=zt(d,A);if(!C){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\
|
|
182
|
+
se mide.`);return}let P=!w&&O?O.servido:C,D=Nt(P,k);if(D){let W=w?Vt(u,C,D,b):Ut(u,P,D,b,p,x,O);r.record(W);let Y=W.cost.eliminatedInputFloorCost;o(`[gateway] POST ${I} ${w?"\xB7 COALESCIDA (llamada evi\
|
|
183
|
+
tada)":""} \xB7 ${P!==C?`${C}\u2192${P} (modelo hermano)`:C} \xB7 $${D.costeUsd.toFixed(6)} (in ${D.tokens.entrada}, cache\u2191${D.tokens.cacheEscrita}${D.tokens.cacheEscrita1h?` (1h ${D.tokens.cacheEscrita1h}\
|
|
184
|
+
)`:""} cache\u2193${D.tokens.cacheLeida}, out ${D.tokens.salida})`+(p?` \xB7 elisi\xF3n: ${p.borrados} borrado(s), ${p.tokensLimpiados} tok limpiados por el proveedor`+(Y!==void 0?` \xB7 suelo $${Y.toFixed(
|
|
185
|
+
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?
|
|
186
|
+
" \xB7 solo thinking (config del cliente): se cuenta, no se acredita":""):""));let F=p?.atribuible===true&&p.tokensLimpiadosToolUses>0;a&&!w&&I==="/v1/messages"&&setImmediate(()=>{try{let T=Ke(d,A);if(!T||
|
|
187
|
+
typeof T!="object")return;let y=a.observar({cuerpo:T,uso:oe,model:C,at:S??Date.now(),...b?.sessionId!==void 0?{sessionId:b.sessionId}:{},...b?.agentId!==void 0?{agentId:b.agentId}:{}});if(!y)return;if(F){
|
|
188
|
+
o(`[gateway] sombra \xB7 ${C} \xB7 el proveedor ya borr\xF3 por nuestros diales: la cadena avanza, no se emite`);return}_.record(Ft(`${u}:shadow`,C,y.baselineUsd,y.politicaUsd,b)),o(`[gateway] sombra \
|
|
189
|
+
\xB7 ${C} \xB7 baseline $${y.baselineUsd.toFixed(6)} \u2192 v0 $${y.politicaUsd.toFixed(6)}`);}catch{}});}else M(`gateway-sin-precio:${C}`,`[bvsala gateway] el modelo "${C}" no est\xE1 en el cat\xE1logo de pr\
|
|
190
|
+
ecios; su uso se reenv\xEDa pero no se mide.`);},l=createServer(async(u,d)=>{let k=randomUUID(),w=Date.now(),I=new AbortController;d.on("close",()=>{d.writableEnded||I.abort();});let A=null,b=new URL(u.url??"/",t),p=null,
|
|
191
|
+
x=Buffer.alloc(0),S=false,O=null,_=null,oe=(T,y)=>{if(T===null||O===null||!O.nuestros)return T;let H=y?.cache_creation,Oe=y?.cache_creation_input_tokens??(H?.ephemeral_5m_input_tokens??0)+(H?.ephemeral_1h_input_tokens??
|
|
192
|
+
0),re=(y?.input_tokens??0)+(y?.cache_read_input_tokens??0)+Oe+T.tokensLimpiados,$=O.triggerDelCliente!==null&&re>=O.triggerDelCliente;return {...T,atribuible:!$}},C=u.headers["content-encoding"],P=Array.
|
|
193
|
+
isArray(C)?C[0]:C,D=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=D(u.headers["x-claude-code-session-id"]),Y=D(u.headers["x-claude-code-agent-id"]),
|
|
194
|
+
F=W!==void 0||Y!==void 0?{...W!==void 0?{sessionId:W}:{},...Y!==void 0?{agentId:Y}:{}}:void 0;try{let T=[];for await(let g of u)T.push(g);let y=Buffer.concat(T);x=y,b=new URL(u.url??"/",t);let H=s!==null&&
|
|
195
|
+
u.method==="POST"&&y.length>0,Oe=tn(g=>{let v=u.headers[g];return Array.isArray(v)?v.join(", "):v}),re=H?en("POST",b.pathname+b.search,y,Oe):"";if(H)if(s.tieneEnVuelo(re)){let g=await s.esperar(re);if(g){
|
|
196
|
+
d.writeHead(g.status,g.headers);let v=m(b.pathname)??new K;for(let ie of g.chunks)d.write(ie),v.observar(ie);d.end();let ae=v.usage()??(b.pathname==="/v1/messages"?Je(Buffer.concat(g.chunks)):null);f(
|
|
197
|
+
k,y,ae,!0,b.pathname,P,F);return}}else A=s.registrar(re);let $={};for(let[g,v]of Object.entries(u.headers))g==="host"||g==="content-length"||v===void 0||($[g]=Array.isArray(v)?v.join(", "):v);let En={
|
|
198
|
+
...$},L=y;if(c!==null&&e.dialesElision===!0&&u.method==="POST"&&b.pathname==="/v1/messages"&&c.tiene("context_elision"))try{let g=bt(y,P);g!==null&&(L=g.cuerpo,O={nuestros:g.nuestros,triggerDelCliente:g.
|
|
199
|
+
triggerDelCliente},$["anthropic-beta"]=yt($["anthropic-beta"]));}catch{}if(u.method==="POST"&&b.pathname==="/v1/messages"&&(P??"")==="")try{let g=Zt(Xt(y.toString("utf8")));g&&M("gateway-busqueda-herra\
|
|
200
|
+
mientas",g);}catch{}let dt=c!==null&&e.modeloHermano===!0&&u.method==="POST"&&(b.pathname==="/v1/messages"||b.pathname==="/v1/messages/count_tokens");if(dt&&!c.tiene("sibling_model_routing")&&M("gatewa\
|
|
201
|
+
y-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 petici\xF3n se reenv\xEDa intacta (fail-closed)."),dt&&
|
|
202
|
+
c.tiene("sibling_model_routing"))try{let v=Pt(L,L===y?P:"identity",{betas:$["anthropic-beta"]});v!==null&&(L=v.cuerpo,_=v.cambio);}catch{}let me=!1;if(c!==null&&Fe(e.esfuerzo)&&u.method==="POST"&&b.pathname===
|
|
203
|
+
"/v1/messages"&&c.tiene("per_turn_effort"))try{let g=L===y?P:"identity",v=Tt(L,e.esfuerzo,g);v!==null&&(L=v.cuerpo,$["anthropic-beta"]=At($["anthropic-beta"]),me=!0);}catch{}let fe=null;if(c!==null&&u.
|
|
204
|
+
method==="POST"&&b.pathname==="/v1/messages"&&c.tiene("cache_ttl_tuning"))try{let v=q(L,L===y?P:"identity");if(v!==null){let ae=kt(v),ie=`${F?.sessionId??"sin-sesion"}:${ae.system}`,ft=Date.now(),wn=i.
|
|
205
|
+
ultima(ie,ft);if(i.anotar(ie,ae,ft),St({fraccionNueva:xt(wn,ae)})){let he=Et(v);he!==null&&(L=he.cuerpo,fe={rebajadas:he.rebajadas,yaEran5m:he.yaEran5m});}}}catch{}let R;try{R=await n(b,{method:u.method,
|
|
206
|
+
headers:$,body:["GET","HEAD"].includes(u.method??"")?void 0:L,redirect:"manual",signal:I.signal});}catch(g){A?.abortar(),d.headersSent||(d.writeHead(502,{"content-type":"application/json"}),d.end(JSON.
|
|
207
|
+
stringify({error:"bvsala gateway: upstream unreachable",detail:String(g)}))),o(`[gateway] ${u.method} ${b.pathname} \u2192 upstream inalcanzable: ${String(g)}`);return}if((_!==null||me)&&R.status===400&&
|
|
208
|
+
!I.signal.aborted){let g="";try{g=(await R.text()).slice(0,300).replace(/\s+/g," ");}catch{}o(`[gateway] el upstream rechaz\xF3 (400) la petici\xF3n reescrita${_?` a ${_.servido}`:""}${me?" (esfuerzo p\
|
|
209
|
+
or turno)":""}; se reenv\xEDa intacta \xB7 ${g}`),_=null,me=!1,fe=null,O=null;try{R=await n(b,{method:u.method,headers:En,body:y,redirect:"manual",signal:I.signal});}catch(v){A?.abortar(),d.headersSent||
|
|
210
|
+
(d.writeHead(502,{"content-type":"application/json"}),d.end(JSON.stringify({error:"bvsala gateway: upstream unreachable",detail:String(v)}))),o(`[gateway] ${u.method} ${b.pathname} \u2192 upstream inalcanz\
|
|
211
|
+
able en el reintento: ${String(v)}`);return}}let De=Object.fromEntries(R.headers.entries());for(let g of Io)delete De[g];d.writeHead(R.status,De);let pt=R.headers.get("content-type")??"",Me=pt.includes(
|
|
212
|
+
"text/event-stream")||pt===""&&R.ok&&m(b.pathname)!==null;p=Me?m(b.pathname):null;let se=!Me&&R.ok&&r!==void 0&&u.method==="POST"&&b.pathname==="/v1/messages"&&(R.headers.get("content-type")??"").includes(
|
|
213
|
+
"application/json")?[]:null,mt=0;if(R.body)for await(let g of R.body){let v=Buffer.from(g);d.write(v),p?.observar(v),se&&(mt+=v.length,mt>Ye?se=null:se.push(v)),A?.capturar(v);}if(d.end(),A?.terminar(R.
|
|
214
|
+
status,De),p&&R.ok){S=!0;let g=p.usage(),v=oe(p instanceof K?p.elision():null,g);f(k,y,g,!1,b.pathname,P,F,v,fe,w,_);}else if(se){let g=Buffer.concat(se),v=Je(g);f(k,y,v,!1,b.pathname,P,F,oe(jt(g),v),fe,
|
|
215
|
+
w,_);}else Me||o(`[gateway] ${u.method} ${b.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} ${b.pathname} \u2192 el c\
|
|
216
|
+
liente cerr\xF3 tras el usage final; se mide igual`);let H=oe(p instanceof K?p.elision():null,y);f(k,x,y,false,b.pathname,P,F,H,void 0,w,_);}else o(`[gateway] ${u.method} ${b.pathname} \u2192 el cliente abort\xF3\
|
|
217
|
+
; upstream cancelado`);}else if(o(`[gateway] ${u.method} ${b.pathname} \u2192 error sirviendo: ${String(T)}`),!d.headersSent){d.writeHead(502,{"content-type":"application/json"}),d.end(JSON.stringify({
|
|
218
|
+
error:"bvsala gateway: stream interrupted",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 42\
|
|
219
|
+
6 (WebSocket no soportado; el cliente cae a HTTP)`),d.once("error",()=>{}),d.once("finish",()=>d.destroy()),d.end(`HTTP/1.1 426 Upgrade Required\r
|
|
191
220
|
connection: close\r
|
|
192
221
|
content-length: 0\r
|
|
193
222
|
\r
|
|
194
|
-
`);}),await new Promise((u,
|
|
195
|
-
existe??existsSync,r=null;for(let s of n.split(";").filter(
|
|
196
|
-
|
|
197
|
-
api-key";if(n==="chatgpt")return "chatgpt";let o=null;try{o=
|
|
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
|
|
199
|
-
/v1"},chatgpt:{upstream:"https://chatgpt.com",prefijo:"/backend-api/codex"}};function
|
|
200
|
-
goose":return {bin:"goose",args:n,env:{ANTHROPIC_HOST:
|
|
201
|
-
"` en ~/.qwen/settings.json (ver `bvsala doctor`).'};case "codex":{let
|
|
202
|
-
nota:
|
|
203
|
-
tokens.":"Auth por API key: el gateway enruta a api.openai.com/v1."}}}}function
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
)
|
|
209
|
-
s `/v1/v1/messages`, sobra un /v1; si ves `POST /messages` a secas, falta uno.",
|
|
210
|
-
\u2014 arranca el gateway en un puerto ef\xEDmero, lanza `claude` apunt\xE1ndole y lo apaga al salir.",`a mano: ANTHROPIC_BASE_URL=${
|
|
211
|
-
dex",nombre:"Codex CLI",binario:"codex",configs:[join(".codex","config.toml"),join(".codex","auth.json")],detectable:true,receta:({base:
|
|
212
|
-
modo de auth y lo resuelve el envoltorio:",` API key \u2192 openai_base_url=${
|
|
213
|
-
e ah\xED)`,`${
|
|
214
|
-
rutas:
|
|
215
|
-
URL": "${
|
|
216
|
-
configs:[join(".config","goose","config.yaml")],detectable:true,receta:({base:
|
|
217
|
-
goose`]},{id:"crush",nombre:"Crush",binario:"crush",configs:[join(".config","crush","crushrc")],detectable:true,receta:({baseV1:
|
|
218
|
-
y SIN barra final (el SDK Go resuelve relativo: /v1/ \u2192 /v1/v1/messages).`,`provider add bvsala --type anthropic --base-url ${
|
|
219
|
-
qwen",configs:[join(".qwen","settings.json")],detectable:true,receta:({base:
|
|
220
|
-
al a\xF1ade /v1/messages).`,`ANTHROPIC_BASE_URL=${
|
|
221
|
-
Droid (Factory)",binario:"droid",configs:[join(".factory","settings.json")],detectable:true,receta:({base:
|
|
223
|
+
`);}),await new Promise((u,d)=>{l.once("error",d),l.listen(e.puerto??8402,"127.0.0.1",()=>u());}),{puerto:l.address().port,cerrar:async()=>{await r?.stopAndDrain(),await new Promise(u=>l.close(()=>u()));}}}var Qe=["claude","codex","goose","qwen"];function rn(e){return Qe.includes(e??"")}function sn(e,t={}){let n=t.path??process.env.PATH??"",o=t.
|
|
224
|
+
existe??existsSync,r=null;for(let s of n.split(";").filter(a=>a.length>0)){for(let a of [".exe",".com"]){let i=join(s,e+a);if(o(i))return {tipo:"exe",ruta:i}}if(r===null)for(let a of [".cmd",".bat"]){let i=join(s,e+
|
|
225
|
+
a);if(o(i)){r=i;break}}}return r!==null?{tipo:"solo-shim",ruta:r}:{tipo:"no-encontrado"}}function an(e={}){let n=(e.env??process.env).BVSALA_CODEX_AUTH?.toLowerCase();if(n==="api-key"||n==="apikey")return "\
|
|
226
|
+
api-key";if(n==="chatgpt")return "chatgpt";let o=null;try{o=e.leerAuth?e.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.
|
|
227
|
+
toLowerCase().replace(/[^a-z]/g,"")==="apikey"?"api-key":"chatgpt":r.tokens!==void 0&&r.tokens!==null?"chatgpt":"api-key"}catch{return "api-key"}}var Oo={"api-key":{upstream:"https://api.openai.com",prefijo:"\
|
|
228
|
+
/v1"},chatgpt:{upstream:"https://chatgpt.com",prefijo:"/backend-api/codex"}};function Xe(e,t,n,o={},r=process.env){let s=`http://127.0.0.1:${t}`;switch(e){case "claude":return {bin:"claude",args:n,env:{
|
|
229
|
+
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:'\
|
|
230
|
+
Qwen Code solo enruta por aqu\xED con `security.auth.selectedType: "anthropic"` en ~/.qwen/settings.json (ver `bvsala doctor`).'};case "codex":{let a=o.modoCodex??"api-key",i=Oo[a];return {bin:"codex",args:[
|
|
231
|
+
"-c",`openai_base_url="${s}${i.prefijo}"`,...n],env:{},upstream:i.upstream,nota:a==="chatgpt"?"Auth ChatGPT detectada: el gateway enruta a chatgpt.com/backend-api/codex. El tr\xE1fico de suscripci\xF3n se m\
|
|
232
|
+
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 Do(e){let t=Number.parseInt(e.slice(8,10),10);return Number.isFinite(t)&&t%2===0?"palanca":"control"}function cn(e){let t;try{t=JSON.parse(e());}catch{return null}if(typeof t!="object"||t===null)return null;let n=t,o=n.espia;return typeof o!="number"||!Number.isInteger(o)||o<1||o>65535?null:{activo:n.
|
|
233
|
+
activo!==false,espia:o}}function ln(e){let{enrolamiento:t,espiaVivo:n,upstreamEnv:o,elisionEnv:r,hoyUtcIso:s}=e;if(!t)return {linea:"",aviso:false};if(!t.activo)return {linea:"anillo 2: enrolamiento en pausa \
|
|
234
|
+
(activo:false)",aviso:false};if(!n)return {linea:`anillo 2: enrolado pero el esp\xEDa NO escucha en :${t.espia} \u2014 NO encadeno (el tr\xE1fico de hoy no entra en el corpus). Arr\xE1ncalo con \`pnpm anillo2:espia\`.`,
|
|
235
|
+
aviso:true};let a=Do(s),i=`http://127.0.0.1:${t.espia}`,c=o!==void 0&&o!=="",m=r!==void 0&&r!=="",f=[];return f.push(`anillo 2: ${s} UTC \u2192 brazo ${a.toUpperCase()}`),f.push(c?`upstream respetado de\
|
|
236
|
+
l entorno (${o})`:`encadenado a :${t.espia}`),m&&f.push(`elisi\xF3n respetada del entorno (=${r})`),f.push("diales de elisi\xF3n APAGADOS (2026-09-09): el brazo ya no los arma"),f.push("asignaci\xF3n POR\
|
|
237
|
+
SESI\xD3N desde el 2026-09-10 (brazoDeSesion), no por paridad del d\xEDa"),{...c?{}:{upstream:i},brazo:a,linea:f.join(", "),aviso:false}}var $o="comprobar: en el log del gateway debe aparecer `[gateway] POST /v1/messages \u2026`; si ve\
|
|
238
|
+
s `/v1/v1/messages`, sobra un /v1; si ves `POST /messages` a secas, falta uno.",No=[{id:"claude",nombre:"Claude Code",binario:"claude",configs:[],detectable:true,receta:({base:e})=>["usa `bvsala claude`\
|
|
239
|
+
\u2014 arranca el gateway en un puerto ef\xEDmero, lanza `claude` apunt\xE1ndole y lo apaga al salir.",`a mano: ANTHROPIC_BASE_URL=${e} claude (sin /v1: el cliente a\xF1ade /v1/messages)`]},{id:"co\
|
|
240
|
+
dex",nombre:"Codex CLI",binario:"codex",configs:[join(".codex","config.toml"),join(".codex","auth.json")],detectable:true,receta:({base:e,rutas:t})=>["usa `bvsala codex` \u2014 el prefijo del base URL depende del \
|
|
241
|
+
modo de auth y lo resuelve el envoltorio:",` API key \u2192 openai_base_url=${e}/v1`,` suscripci\xF3n ChatGPT \u2192 openai_base_url=${e}/backend-api/codex (tiene que terminar exactament\
|
|
242
|
+
e ah\xED)`,`${t[1]}: solo se comprueba que exista; nunca se lee.`]},{id:"opencode",nombre:"opencode",binario:"opencode",configs:[join(".config","opencode","opencode.json")],detectable:true,receta:({baseV1:e,
|
|
243
|
+
rutas:t})=>[`mecanismo: ${t[0]} \u2192 provider.anthropic.options.baseURL (el opencode.json del proyecto pisa al global). CON /v1.`,"{",' "provider": {',' "anthropic": {',` "options": { "base\
|
|
244
|
+
URL": "${e}" }`," }"," }","}",'alternativa: "baseURL": "{env:BVSALA_BASE_URL}" y exportar la variable; trampa: sin la variable, baseURL queda vac\xEDo.']},{id:"goose",nombre:"Goose",binario:"goose",
|
|
245
|
+
configs:[join(".config","goose","config.yaml")],detectable:true,receta:({base:e,rutas:t})=>[`mecanismo: variable de entorno ANTHROPIC_HOST (pisa ${t[0]}). SIN /v1.`,`ANTHROPIC_HOST=${e} ANTHROPIC_API_KEY=\u2026\
|
|
246
|
+
goose`]},{id:"crush",nombre:"Crush",binario:"crush",configs:[join(".config","crush","crushrc")],detectable:true,receta:({baseV1:e,rutas:t})=>[`mecanismo: ${t[0]} (Bash); crush.json est\xE1 deprecado. CON /v1\
|
|
247
|
+
y SIN barra final (el SDK Go resuelve relativo: /v1/ \u2192 /v1/v1/messages).`,`provider add bvsala --type anthropic --base-url ${e} --api-key "$ANTHROPIC_API_KEY"`]},{id:"qwen",nombre:"Qwen Code",binario:"\
|
|
248
|
+
qwen",configs:[join(".qwen","settings.json")],detectable:true,receta:({base:e,rutas:t})=>[`mecanismo: variable de entorno ANTHROPIC_BASE_URL + ${t[0]} con selectedType = anthropic. SIN /v1 (el SDK TS ofici\
|
|
249
|
+
al a\xF1ade /v1/messages).`,`ANTHROPIC_BASE_URL=${e} ANTHROPIC_API_KEY=\u2026 qwen`,`comprueba a mano que ${t[0]} lleve selectedType: anthropic \u2014 el doctor no lee el archivo.`]},{id:"droid",nombre:"\
|
|
250
|
+
Droid (Factory)",binario:"droid",configs:[join(".factory","settings.json")],detectable:true,receta:({base:e,rutas:t})=>[`mecanismo: ${t[0]} \u2192 customModels[] con provider "anthropic". SIN /v1 [inferido: val\
|
|
222
251
|
idar en mano contra el log del gateway].`,"{",' "customModels": ['," {",' "model": "<id de modelo Anthropic>",',' "displayName": "<nombre visible>",',' "provider": "anthropic",',` \
|
|
223
|
-
"baseUrl": "${
|
|
224
|
-
\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: ${
|
|
225
|
-
receta:({baseV1:
|
|
226
|
-
let n=
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
se lee el contenido de ning\xFAn archivo.",""];for(let
|
|
230
|
-
u?
|
|
231
|
-
push(`\xBB ${
|
|
252
|
+
"baseUrl": "${e}",`,' "apiKey": "<tu API key de Anthropic>"'," }"," ]","}"]},{id:"cline",nombre:"Cline",configs:[],detectable:false,receta:({baseV1:e})=>["mecanismo: UI \u2192 proveedor Anthropic\
|
|
253
|
+
\u2192 marca \xABUse custom base URL\xBB. CON /v1 (Cline fija https://api.anthropic.com/v1 y solo normaliza la URL oficial exacta).",`Base URL: ${e}`]},{id:"kilo",nombre:"Kilo Code",configs:[],detectable:false,
|
|
254
|
+
receta:({baseV1:e})=>["mecanismo: UI \u2192 proveedor custom, Provider API \xABAnthropic Messages\xBB. Probar CON /v1 primero (linaje Cline) [inferido: validar en mano].",`Base URL: ${e}`]}];function zo(e,t){
|
|
255
|
+
let n=e.split(delimiter).filter(r=>r.length>0),o=process.platform==="win32"?["",".exe",".cmd",".bat"]:[""];return r=>n.some(s=>o.some(a=>t(join(s,r+a))))}async function un(e,t={}){if(!Number.isInteger(e)||e<1||
|
|
256
|
+
e>65535)throw new RangeError(`[bvsala doctor] puerto inv\xE1lido: ${String(e)}`);let n=t.home??homedir(),o=t.existe??existsSync,r=t.enPath??zo(t.path??process.env.PATH??"",o),s=`http://127.0.0.1:${e}`,a=`${s}/v1`,
|
|
257
|
+
i=[],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 \
|
|
258
|
+
se lee el contenido de ning\xFAn archivo.",""];for(let m of No){let f=m.configs.map(k=>join(n,k)),l=m.binario!==void 0&&r(m.binario),h=f.filter(k=>o(k)),u=l||h.length>0;u&&i.push(m.id);let d;m.detectable?
|
|
259
|
+
u?d=`detectado \u2014 ${[...l?[`binario \`${m.binario}\` en PATH`]:[],...h.map(w=>`config presente: ${w}`)].join("; ")}`:d="no detectado":d="sin detecci\xF3n autom\xE1tica (extensi\xF3n de editor)",c.
|
|
260
|
+
push(`\xBB ${m.id}: ${d}`),c.push(` ${m.nombre}`);for(let k of m.receta({base:s,baseV1:a,rutas:f}))c.push(` ${k}`);c.push(` ${$o}`),c.push("");}return c.push("Regla BYOK: las recetas del anillo Anth\
|
|
232
261
|
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
262
|
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:
|
|
235
|
-
<!-- bvsala:savings-mode:fin -->";function
|
|
236
|
-
${
|
|
263
|
+
`),detectados:i}}var dn="savings-mode";function pn(e,t){for(let n of e){let o=join(n,"skills",dn,"SKILL.md");if(t.existe(o))return o}return null}var mn="<!-- bvsala:savings-mode:inicio -->",_e="\
|
|
264
|
+
<!-- bvsala:savings-mode:fin -->";function Bo(e){let t=e.replace(/^---\n[\s\S]*?\n---\n*/,"").trim();return `${mn}
|
|
265
|
+
${t}
|
|
237
266
|
|
|
238
267
|
_Always on (AGENTS.md has no activation step). Delete this block to turn it off; \`bvsala skill --codex --forzar\` restores it._
|
|
239
|
-
${
|
|
240
|
-
leer(
|
|
241
|
-
`),{ok:true,destino:r,mensaje:
|
|
268
|
+
${_e}`}function fn(e){let t=pn(e.origenes,e.fs);if(!t)return {ok:false,destino:"",mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${e.origenes.join(", ")})`};let n=Bo(e.fs.
|
|
269
|
+
leer(t)),o=e.proyecto?e.cwd:join(e.home,".codex"),r=join(o,"AGENTS.md");if(!e.fs.existe(r))return e.fs.crearDir(o),e.fs.escribir(r,n+`
|
|
270
|
+
`),{ok:true,destino:r,mensaje:Ze(r,"instalado")};let s=e.fs.leer(r),a=s.indexOf(mn),i=s.indexOf(_e);return a===-1||i===-1||i<a?(e.fs.escribir(r,s.trimEnd()+`
|
|
242
271
|
|
|
243
272
|
`+n+`
|
|
244
|
-
`),{ok:true,destino:r,mensaje:
|
|
245
|
-
slice(0,
|
|
246
|
-
usa --forzar para actualizarlo`}}function
|
|
273
|
+
`),{ok:true,destino:r,mensaje:Ze(r,"a\xF1adido al AGENTS.md existente")}):s.slice(a,i+_e.length)===n?{ok:true,destino:r,mensaje:`[bvsala skill] ya instalado y al d\xEDa: ${r}`}:e.forzar?(e.fs.escribir(r,s.
|
|
274
|
+
slice(0,a)+n+s.slice(i+_e.length)),{ok:true,destino:r,mensaje:Ze(r,"bloque actualizado")}):{ok:false,destino:r,mensaje:`[bvsala skill] el bloque savings-mode de ${r} tiene contenido DISTINTO \u2014 no lo piso; \
|
|
275
|
+
usa --forzar para actualizarlo`}}function Ze(e,t){return `[bvsala skill] ${t}: ${e}
|
|
247
276
|
[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
|
|
249
|
-
mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${
|
|
250
|
-
"SKILL.md"),s=
|
|
251
|
-
nido DISTINTO \u2014 no lo piso; usa --forzar para sobrescribir`}}return
|
|
277
|
+
[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 hn(e){let t=pn(e.origenes,e.fs);if(!t)return {ok:false,destino:"",
|
|
278
|
+
mensaje:`[bvsala skill] no encuentro el SKILL.md empaquetado (ra\xEDces probadas: ${e.origenes.join(", ")})`};let n=e.proyecto?join(e.cwd,".claude","skills"):join(e.home,".claude","skills"),o=join(n,dn),r=join(o,
|
|
279
|
+
"SKILL.md"),s=e.fs.leer(t);if(e.fs.existe(r)&&!e.forzar){let a=e.fs.leer(r)===s;return {ok:a,destino:r,mensaje:a?`[bvsala skill] ya instalado y al d\xEDa: ${r}`:`[bvsala skill] ya existe ${r} con conte\
|
|
280
|
+
nido DISTINTO \u2014 no lo piso; usa --forzar para sobrescribir`}}return e.fs.crearDir(o),e.fs.escribir(r,s),{ok:true,destino:r,mensaje:`[bvsala skill] instalado: ${r}
|
|
252
281
|
[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
|
|
254
|
-
match(/\n/g)??[]).length;o+=
|
|
255
|
-
Math.ceil(
|
|
256
|
-
return this.modelToTokenizer.set(
|
|
257
|
-
get(o);if(r)return r}}return this.estimators.get(this.fallbackId)}count(
|
|
258
|
-
|
|
259
|
-
argv;function
|
|
282
|
+
[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 et=class{id;exact=false;constructor(t="heuristic"){this.id=t;}count(t){if(t.length===0)return 0;let n=t.match(/[A-Za-z]+|\d+|\s+|[^\sA-Za-z\d]/g)??[],o=0;for(let r of n){let s=r[0];if(/\s/.test(s)){let a=(r.
|
|
283
|
+
match(/\n/g)??[]).length;o+=a+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,
|
|
284
|
+
Math.ceil(t.length/4))}},tt=new et;var nt=class{estimators=new Map;modelToTokenizer=new Map;fallbackId;constructor(t=tt){this.fallbackId=t.id,this.estimators.set(t.id,t);}register(t){return this.estimators.set(t.id,t),this}mapModel(t,n){
|
|
285
|
+
return this.modelToTokenizer.set(t,n),this}resolve(t){let n=t.tokenizer?this.estimators.get(t.tokenizer):void 0;if(n)return n;if(t.model){let o=this.modelToTokenizer.get(t.model);if(o){let r=this.estimators.
|
|
286
|
+
get(o);if(r)return r}}return this.estimators.get(this.fallbackId)}count(t,n){return this.resolve(n).count(t)}};new nt;new TextEncoder;new TextDecoder;new TextDecoder;var nr={"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}};
|
|
287
|
+
qe(nr);function ur(e,t=300){return new Promise(n=>{let o=connect({port:e,host:"127.0.0.1"}),r=s=>{o.destroy(),n(s);};o.setTimeout(t,()=>r(false)),o.once("connect",()=>r(true)),o.once("error",()=>r(false));})}var[,,E,...V]=process.
|
|
288
|
+
argv;function dr(){console.log(`bvsala ${Q} \u2014 BiVelio Savings Layer
|
|
260
289
|
|
|
261
290
|
Comandos:
|
|
262
291
|
gateway [--puerto N] Proxy local medidor (por defecto 8402) para terminales que
|
|
@@ -298,30 +327,53 @@ Entorno:
|
|
|
298
327
|
Ante cualquier duda, la petici\xF3n viaja intacta. (Hasta 0.4.13
|
|
299
328
|
la bandera era al rev\xE9s: \xAB=1 arma\xBB; en un A/B p\xE1sala SIEMPRE
|
|
300
329
|
expl\xEDcita, =1 o =0, y no depender\xE1s de la versi\xF3n instalada.)
|
|
330
|
+
BVSALA_GATEWAY_MODELO_HERMANO
|
|
331
|
+
=1 sirve claude-fable-5 con claude-fable-5-1 (palanca C): misma
|
|
332
|
+
tarifa de entrada, salida y escritura de cach\xE9; la LECTURA de
|
|
333
|
+
cach\xE9 baja de 0,001 a 0,00025 por 1K tokens (cat\xE1logo). El
|
|
334
|
+
ahorro es una resta de dos precios sobre el mismo usage:
|
|
335
|
+
se mide sin A/B y entra en el titular medido del panel.
|
|
336
|
+
Solo si la licencia trae sibling_model_routing (fail-closed).
|
|
337
|
+
CAMBIA el model que ves en la respuesta (/cost, /status), y
|
|
338
|
+
encenderlo a mitad de un hilo paga UNA escritura fr\xEDa del
|
|
339
|
+
prefijo (cada modelo tiene su cach\xE9): arr\xE1ncalo con el terminal.
|
|
340
|
+
Apagar = quitar la variable o =0.
|
|
341
|
+
BVSALA_GATEWAY_ESFUERZO
|
|
342
|
+
=low|medium|high|xhigh|max arma el esfuerzo por turno (palanca D):
|
|
343
|
+
a\xF1ade al final de cada /v1/messages un mensaje con
|
|
344
|
+
output_config.effort, sin tocar la ra\xEDz (no reinicia la cach\xE9 de
|
|
345
|
+
prefijo). Solo si la licencia trae per_turn_effort (fail-closed)
|
|
346
|
+
y solo con claude-fable-5-1, claude-mythos-5-1 y claude-opus-5;
|
|
347
|
+
con otro modelo la petici\xF3n viaja intacta. Es la \xFAnica palanca
|
|
348
|
+
que puede tocar la calidad de la respuesta: va APAGADA por
|
|
349
|
+
defecto y a\xFAn no est\xE1 medida contra la verja de calidad.
|
|
301
350
|
BVSALA_CODEX_AUTH api-key | chatgpt \u2014 fuerza el modo de auth de Codex.
|
|
302
351
|
BVSALA_GATEWAY_LOG =1 ense\xF1a el log por petici\xF3n tambi\xE9n dentro de los envoltorios
|
|
303
352
|
(por defecto va silenciado para no pisar el TUI; mira el panel).
|
|
304
353
|
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 (Claude Code, solo API key) tus modelos en /model.
|
|
305
354
|
|
|
306
355
|
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
|
|
308
|
-
elp"||
|
|
309
|
-
r"),fs:{existe:existsSync,leer:o=>readFileSync(o,"utf8"),escribir:(o,r)=>writeFileSync(o,r),crearDir:o=>mkdirSync(o,{recursive:true})}},n=
|
|
310
|
-
puerto"),
|
|
311
|
-
"--write")&&(console.error("[bvsala doctor] --write todav\xEDa no existe: el doctor solo imprime; copia el bloque a mano."),process.exit(1));let
|
|
312
|
-
|
|
313
|
-
null:
|
|
314
|
-
elisionEnv:process.env.BVSALA_GATEWAY_ELISION,hoyUtcIso:new Date().toISOString().slice(0,10)}),
|
|
315
|
-
{puerto:
|
|
316
|
-
env.BVSALA_GATEWAY_COALESCE==="1"?{coalescer:true}:{},...process.env.BVSALA_GATEWAY_SHADOW==="1"?{sombra:true}:{},elision:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
upstream.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
"
|
|
326
|
-
(
|
|
327
|
-
|
|
356
|
+
Tus prompts jam\xE1s salen de tu m\xE1quina \u2014 solo cuentas y coste. M\xE1s: savings.bivelio.com`);}var pe=rn(E);E!=="gateway"&&E!=="doctor"&&E!=="skill"&&!pe&&(dr(),process.exit(E===void 0||E==="h\
|
|
357
|
+
elp"||E==="--help"?0:1));if(E==="skill"){let e=dirname(fileURLToPath(import.meta.url)),t={origenes:[join(e,"..",".."),join(e,"..")],home:homedir(),cwd:process.cwd(),proyecto:V.includes("--proyecto"),forzar:V.includes("--forza\
|
|
358
|
+
r"),fs:{existe:existsSync,leer:o=>readFileSync(o,"utf8"),escribir:(o,r)=>writeFileSync(o,r),crearDir:o=>mkdirSync(o,{recursive:true})}},n=V.includes("--codex")?fn(t):hn(t);console.log(n.mensaje),process.exit(n.ok?0:1);}var it=V.indexOf("--\
|
|
359
|
+
puerto"),te=pe?0:it>=0?Number(V[it+1]):8402;(!Number.isInteger(te)||(E==="doctor"?te<1:te<0)||te>65535)&&(console.error(`[bvsala ${E}] puerto inv\xE1lido: ${V[it+1]}`),process.exit(1));if(E==="doctor"){
|
|
360
|
+
V.includes("--write")&&(console.error("[bvsala doctor] --write todav\xEDa no existe: el doctor solo imprime; copia el bloque a mano."),process.exit(1));let e=await un(te);console.log(e.texto),process.
|
|
361
|
+
exit(0);}var N=pe?Xe(E,0,V,{modoCodex:E==="codex"?an({leerAuth:()=>readFileSync(join(homedir(),".codex","auth.json"),"utf8")}):void 0}):null,ne=process.env.BIVELIO_SERVICE_KEY,pr=pe&&process.env.BVSALA_GATEWAY_LOG!=="1",
|
|
362
|
+
at=N?.upstream?null:cn(()=>readFileSync(process.env.BVSALA_ANILLO2_FICHERO??join(homedir(),".bvsala","anillo2.json"),"utf8")),de=ln({enrolamiento:at,espiaVivo:at!==null&&await ur(at.espia),upstreamEnv:process.env.BVSALA_GATEWAY_UPSTREAM,
|
|
363
|
+
elisionEnv:process.env.BVSALA_GATEWAY_ELISION,hoyUtcIso:new Date().toISOString().slice(0,10)}),ct=process.env.BVSALA_GATEWAY_UPSTREAM??de.upstream,Ie=process.env.BVSALA_GATEWAY_ELISION??de.elision,G=await nn(
|
|
364
|
+
{puerto:te,...pr?{log:()=>{}}:{},...ne?{serviceAccountKey:ne}:{},...process.env.BVSALA_SEAT_ID?{seatId:process.env.BVSALA_SEAT_ID}:{},...ct?{upstream:ct}:N?.upstream?{upstream:N.upstream}:{},...process.
|
|
365
|
+
env.BVSALA_GATEWAY_COALESCE==="1"?{coalescer:true}:{},...process.env.BVSALA_GATEWAY_SHADOW==="1"?{sombra:true}:{},elision:Ie!=="0",...process.env.BVSALA_GATEWAY_DIALES_ELISION==="1"?{dialesElision:true}:{},
|
|
366
|
+
...process.env.BVSALA_GATEWAY_MODELO_HERMANO==="1"?{modeloHermano:true}:{},...process.env.BVSALA_GATEWAY_ESFUERZO?{esfuerzo:process.env.BVSALA_GATEWAY_ESFUERZO}:{},...process.env.BVSALA_METERING_URL?{meteringUrl:process.
|
|
367
|
+
env.BVSALA_METERING_URL}:{}}),mr=ct??N?.upstream??"https://api.anthropic.com";console.log(`[bvsala gateway] v${Q} escuchando en http://127.0.0.1:${G.puerto} \u2192 ${mr}`);console.log(`[bvsala gateway\
|
|
368
|
+
] medici\xF3n: ${ne?"ACTIVA (clave de servicio presente)":"APAGADA (falta BIVELIO_SERVICE_KEY)"}`);{let e=vt(Ie,ne!==void 0,process.env.BVSALA_GATEWAY_DIALES_ELISION==="1");(e.aviso?console.error:console.
|
|
369
|
+
log)(`[bvsala gateway] ${e.linea}`);let t=Ot(process.env.BVSALA_GATEWAY_MODELO_HERMANO,ne!==void 0,Ie!=="0");(t.aviso?console.error:console.log)(`[bvsala gateway] ${t.linea}`);let n=_t(process.env.BVSALA_GATEWAY_ESFUERZO,
|
|
370
|
+
ne!==void 0,Ie!=="0");(n.aviso?console.error:console.log)(`[bvsala gateway] ${n.linea}`),de.linea&&(de.aviso?console.error:console.log)(`[bvsala gateway] ${de.linea}`);}process.env.BVSALA_GATEWAY_UPSTREAM&&
|
|
371
|
+
N?.upstream&&process.env.BVSALA_GATEWAY_UPSTREAM!==N.upstream&&console.error(`[bvsala ${E}] AVISO: BVSALA_GATEWAY_UPSTREAM=${process.env.BVSALA_GATEWAY_UPSTREAM} pisa el upstream de este terminal (${N.
|
|
372
|
+
upstream}). Si no es lo que quieres, quita la variable.`);E==="codex"&&!Bt()&&console.error(`[bvsala codex] AVISO: este Node (${process.version}) no descomprime zstd y Codex manda el cuerpo en zstd: e\
|
|
373
|
+
l tr\xE1fico pasa pero NO se mide. Usa Node \u2265 22.15.`);if(N&&pe){let e=Xe(E,G.puerto,V,{...N.upstream?{modoCodex:N.upstream.includes("chatgpt.com")?"chatgpt":"api-key"}:{}});e.nota&&console.log(`\
|
|
374
|
+
[bvsala ${E}] ${e.nota}`);let t=e.bin;if(process.platform==="win32"){let o=sn(e.bin);o.tipo==="exe"?t=o.ruta:o.tipo==="solo-shim"&&(console.error(`[bvsala ${E}] \`${e.bin}\` est\xE1 instalado como shim de\
|
|
375
|
+
npm (${o.ruta}) y Windows no puede lanzarlo de forma segura con argumentos (CVE-2024-27980). Inst\xE1lalo con su instalador nativo (deja un ${e.bin}.exe en el PATH) o usa la receta manual de docs/ter\
|
|
376
|
+
minales/.`),await G.cerrar(),process.exit(127));}let n=spawn(t,e.args,{stdio:"inherit",env:{...process.env,...e.env}});n.on("error",o=>{console.error(`[bvsala ${E}] no se pudo lanzar \`${e.bin}\`: ${String(
|
|
377
|
+
o)}. \xBFEst\xE1 instalado y en el PATH?`),G.cerrar().then(()=>process.exit(127));}),n.on("exit",(o,r)=>{G.cerrar().then(()=>process.exit(o??(r?1:0)));});}else console.log(`[bvsala gateway] apunta tu ter\
|
|
378
|
+
minal (o usa \`bvsala ${Qe.join("|")}\`): ANTHROPIC_BASE_URL=http://127.0.0.1:${G.puerto} claude \xB7 bvsala doctor para el resto`);var Sn=async()=>{await G.cerrar(),process.exit(0);};process.on("\
|
|
379
|
+
SIGINT",()=>{Sn();});process.on("SIGTERM",()=>{Sn();});
|