inference-relay 1.5.0 → 1.5.2

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/dist/cli/main.js CHANGED
@@ -8,7 +8,7 @@ kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
8
8
  7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
9
9
  Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
10
10
  UQIDAQAB
11
- -----END PUBLIC KEY-----`,Le={version:"1.0.0",cliVersion:"2.1.87",eventTypes:{system:"system",streamEvent:"stream_event",assistant:"assistant",result:"result"},fieldMappings:{sessionId:"session_id",model:"model",cliVersion:"claude_code_version",content:"content",usage:"usage",inputTokens:"input_tokens",outputTokens:"output_tokens",stopReason:"stop_reason",isError:"is_error",totalCostUsd:"total_cost_usd",durationMs:"duration_ms",error:"error",event:"event"},syntheticModel:"<synthetic>"},V=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(ge,"RS256"),{payload:a}=await t(e,s),i=JSON.parse(new TextDecoder().decode(a));return this.verificationFailures=0,this.cachedManifest=i,this.currentSecurityState="SEC_NOMINAL",{manifest:i,securityState:"SEC_NOMINAL"}}catch{if(this.verificationFailures++,this.verificationFailures>=3){this.currentSecurityState="SEC_DEGRADED";let t=2e3+Math.random()*3e3;return await new Promise(r=>setTimeout(r,t)),console.warn("[inference-relay] Logic synchronization mismatch. Routing via local recovery."),{manifest:Le,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:Le,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},Ct=new V;});function Ee(n){return join(homedir(),".inference-relay","gateway",n)}function Ue(n){return join(Ee(n),"bundle.js")}function Ne(n){return join(Ee(n),"meta.json")}var wt,_,W,z,be=C(()=>{fe();wt=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";_=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},W=new Map,z=class{static async load(e,t,r=wt){let s=`${t}:${e.slice(-8)}`;if(W.has(s))return W.get(s);try{let d=await this.tryLoadFromDisk(t);if(d)return W.set(s,d),d}catch{}let{bytes:a,sha256:i,signature:l,libraryVersion:o}=await this.fetchFromAuthority(e,t,r);if(createHash("sha256").update(a).digest("hex")!==i)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,o,i);try{let d=Ee(t);mkdirSync(d,{recursive:!0}),writeFileSync(Ue(t),a),writeFileSync(Ne(t),JSON.stringify({sha256:i,signature:l,libraryVersion:o}));}catch{}let c=this.loadIntoVm(a.toString("utf-8"));return W.set(s,c),c}static async loadFromDisk(e){if(!existsSync(e))throw new _(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Ue(e),r=Ne(e);if(!existsSync(t)||!existsSync(r))return null;let s=readFileSync(t),a=JSON.parse(readFileSync(r,"utf-8"));return createHash("sha256").update(s).digest("hex")!==a.sha256?null:(await this.verifySignature(a.signature,a.libraryVersion,a.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r){let s,a=[0,1e3,4e3],i;for(let c of a){c>0&&await new Promise(d=>setTimeout(d,c));try{let d=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(d.status===401||d.status===403)throw new _("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(d.status>=500&&d.status<600){i=new _(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${d.status})`,"GATEWAY_FETCH_FAILED");continue}if(!d.ok)throw new _(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${d.status})`,"GATEWAY_FETCH_FAILED");s=await d.json(),i=null;break}catch(d){if(d instanceof _&&d.code==="LICENSE_REJECTED")throw d;i=d;}}if(i||!s)throw i instanceof _?i:new _("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)","GATEWAY_FETCH_FAILED",i);let l;try{l=await fetch(s.bundleUrl);}catch(c){throw new _("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)","GATEWAY_FETCH_FAILED",c)}if(!l.ok)throw new _(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${l.status})`,"GATEWAY_FETCH_FAILED");let o=await l.arrayBuffer();return {bytes:Buffer.from(o),sha256:s.sha256,signature:s.signature,libraryVersion:s.libraryVersion,bundleVersion:s.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:a}=await import('jose'),i=await a(ge,"RS256"),{payload:l}=await s(e,i),o=JSON.parse(new TextDecoder().decode(l));if(o.purpose!=="gateway-bundle")throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(o.libraryVersion!==t)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(o.sha256!==r)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof _?s:new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=join(homedir(),".inference-relay","gateway","runtime.cjs"),r=dirname(t),s=createRequire(t),a={exports:{}};compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(a.exports,s,a,t,r);let l=a.exports;if(!l.ClaudeCLIProvider)throw new _("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return l}catch(t){throw t instanceof _?t:new _("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){W.clear();}};});var He={};xe(He,{detectCLI:()=>N});function Lt(n){let e=process.env.PATH;if(!e)return null;let t=process.platform==="win32",r=t?";":":",s=t?(process.env.PATHEXT??".COM;.EXE;.BAT;.CMD").split(";").map(a=>a.toLowerCase()):[""];for(let a of e.split(r))if(a)for(let i of s){let l=join(a,n+i);if(existsSync(l))return l}return null}async function N(){if(!Lt("claude"))return {available:false,authenticated:false};let e=null;try{let r=execSync("claude --version",{encoding:"utf-8",timeout:5e3}).trim(),s=r.match(/(\d+\.\d+\.\d+)/);e=s?s[1]:r;}catch{}let t;return e&&!xt.some(r=>e.startsWith(r.split(".").slice(0,2).join(".")))&&(t=`CLI version ${e} is not tested with this version of inference-relay. Streaming may be unstable.`),{available:true,authenticated:true,cliVersion:e||void 0,versionWarning:t}}var xt,Q=C(()=>{xt=["2.1.87"];});var Mt,Z,Be=C(()=>{$();be();Mt="1.5.0",Z=class extends w{type="claude-cli";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";licenseKey;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.licenseKey=e;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await z.load(this.licenseKey,Mt)).ClaudeCLIProvider,r=new t;return this.loadedProvider=r,r}catch(e){throw this.loadingPromise=null,this.health.status="unhealthy",this.health.errorCount++,e instanceof _?this.health.lastError=e.message:e instanceof Error&&(this.health.lastError=e.message),e}})(),this.loadingPromise)}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(Q(),He));return e()}async execute(e,t){return (await this.ensureLoaded()).execute(e,t)}async streamRaw(e,t){return (await this.ensureLoaded()).streamRaw(e,t)}estimateCost(e){if(this.loadedProvider)return this.loadedProvider.estimateCost(e);let r=JSON.stringify(e.messages).length/4+5e3,s=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(s*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};});function Ve(n){return ee[n]||n}function ve(n){return $e.find(e=>e.canonical===n)?.provider}var $e,ee,Ce=C(()=>{$e=[{canonical:"claude-haiku-4-5",apiId:"claude-haiku-4-5-20251001",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[.8,4]},{canonical:"claude-sonnet-4-6",apiId:"claude-sonnet-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[3,15]},{canonical:"claude-opus-4-6",apiId:"claude-opus-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[15,75]},{canonical:"gpt-4.1",apiId:"gpt-4.1",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[2,8]},{canonical:"gpt-4.1-mini",apiId:"gpt-4.1-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.4,1.6]},{canonical:"gpt-4.1-nano",apiId:"gpt-4.1-nano",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.1,.4]},{canonical:"gpt-4o",apiId:"gpt-4o",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[2.5,10]},{canonical:"gpt-4o-mini",apiId:"gpt-4o-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[.15,.6]},{canonical:"o4-mini",apiId:"o4-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o3",apiId:"o3",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[.4,1.6]},{canonical:"o3-mini",apiId:"o3-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o1",apiId:"o1",provider:"openai-api",capabilities:{streaming:false,tools:false,multimodal:false,contextWindow:2e5},pricing:[15,60]},{canonical:"llama3.1",apiId:"llama3.1",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"mistral",apiId:"mistral",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}},{canonical:"mistral-nemo",apiId:"mistral-nemo",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"llava",apiId:"llava",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:true,contextWindow:32e3}},{canonical:"qwen2:0.5b",apiId:"qwen2:0.5b",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}}],ee=Object.fromEntries($e.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));ee["claude-sonnet-4"]="claude-sonnet-4-20250514";ee["claude-opus-4"]="claude-opus-4-20250514";ee["claude-haiku-4"]="claude-haiku-4-5-20251001";});function We(n){if(Ae[n])return Ae[n];for(let[e,t]of Object.entries(Ae))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Dt,Ot,Ae,te,Ge=C(()=>{$();Ce();Dt="https://api.anthropic.com/v1/messages",Ot="2023-06-01",Ae={"claude-sonnet-4-5-20250514":[3,15],"claude-sonnet-4-20250514":[3,15],"claude-haiku-4-5-20250414":[.8,4],"claude-opus-4-20250514":[15,75]};te=class extends w{type="anthropic-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;dangerousDirectBrowserAccess;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||Dt,this.dangerousDirectBrowserAccess=e.dangerousDirectBrowserAccess??false;}async probe(){try{let e=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{available:!0,authenticated:!1}:e.ok||e.status===429?{available:!0,authenticated:!0,rateLimitTier:e.headers.get("anthropic-ratelimit-tier")??void 0}:e.status===529?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),a=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!a.ok)throw this.handleErrorResponse(a),new Error("unreachable");let i=await a.json(),l=Date.now()-r;this.recordSuccess();let[o,p]=We(i.model||e.model),c=((i.usage?.input_tokens||0)*o+(i.usage?.output_tokens||0)*p)/1e6,d={},h=["request-id","x-request-id","anthropic-ratelimit-requests-limit","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-reset","anthropic-ratelimit-tokens-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-reset","anthropic-ratelimit-tier"];for(let m of h){let E=a.headers.get(m);E&&(d[m]=E);}return {content:i.content||[],model:i.model||e.model,usage:{input_tokens:i.usage?.input_tokens||0,output_tokens:i.usage?.output_tokens||0},stop_reason:i.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(c*1e6)/1e6,durationMs:l,fallbackChain:["anthropic-api:success"],headers:Object.keys(d).length>0?d:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let a=s.body.getReader(),i=new TextDecoder;return (async function*(){let l="",o=false;try{for(;;){let{done:p,value:c}=await a.read();if(p)break;l+=i.decode(c,{stream:!0});let d=l.split(`
11
+ -----END PUBLIC KEY-----`,Le={version:"1.0.0",cliVersion:"2.1.87",eventTypes:{system:"system",streamEvent:"stream_event",assistant:"assistant",result:"result"},fieldMappings:{sessionId:"session_id",model:"model",cliVersion:"claude_code_version",content:"content",usage:"usage",inputTokens:"input_tokens",outputTokens:"output_tokens",stopReason:"stop_reason",isError:"is_error",totalCostUsd:"total_cost_usd",durationMs:"duration_ms",error:"error",event:"event"},syntheticModel:"<synthetic>"},V=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(ge,"RS256"),{payload:a}=await t(e,s),i=JSON.parse(new TextDecoder().decode(a));return this.verificationFailures=0,this.cachedManifest=i,this.currentSecurityState="SEC_NOMINAL",{manifest:i,securityState:"SEC_NOMINAL"}}catch{if(this.verificationFailures++,this.verificationFailures>=3){this.currentSecurityState="SEC_DEGRADED";let t=2e3+Math.random()*3e3;return await new Promise(r=>setTimeout(r,t)),console.warn("[inference-relay] Logic synchronization mismatch. Routing via local recovery."),{manifest:Le,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:Le,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},Ct=new V;});function Ee(n){return join(homedir(),".inference-relay","gateway",n)}function Ue(n){return join(Ee(n),"bundle.js")}function Ne(n){return join(Ee(n),"meta.json")}var wt,_,W,z,be=C(()=>{fe();wt=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";_=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},W=new Map,z=class{static async load(e,t,r=wt){let s=`${t}:${e.slice(-8)}`;if(W.has(s))return W.get(s);try{let d=await this.tryLoadFromDisk(t);if(d)return W.set(s,d),d}catch{}let{bytes:a,sha256:i,signature:l,libraryVersion:o}=await this.fetchFromAuthority(e,t,r);if(createHash("sha256").update(a).digest("hex")!==i)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,o,i);try{let d=Ee(t);mkdirSync(d,{recursive:!0}),writeFileSync(Ue(t),a),writeFileSync(Ne(t),JSON.stringify({sha256:i,signature:l,libraryVersion:o}));}catch{}let c=this.loadIntoVm(a.toString("utf-8"));return W.set(s,c),c}static async loadFromDisk(e){if(!existsSync(e))throw new _(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Ue(e),r=Ne(e);if(!existsSync(t)||!existsSync(r))return null;let s=readFileSync(t),a=JSON.parse(readFileSync(r,"utf-8"));return createHash("sha256").update(s).digest("hex")!==a.sha256?null:(await this.verifySignature(a.signature,a.libraryVersion,a.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r){let s,a=[0,1e3,4e3],i;for(let c of a){c>0&&await new Promise(d=>setTimeout(d,c));try{let d=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(d.status===401||d.status===403)throw new _("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(d.status>=500&&d.status<600){i=new _(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${d.status})`,"GATEWAY_FETCH_FAILED");continue}if(!d.ok)throw new _(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${d.status})`,"GATEWAY_FETCH_FAILED");s=await d.json(),i=null;break}catch(d){if(d instanceof _&&d.code==="LICENSE_REJECTED")throw d;i=d;}}if(i||!s)throw i instanceof _?i:new _("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)","GATEWAY_FETCH_FAILED",i);let l;try{l=await fetch(s.bundleUrl);}catch(c){throw new _("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)","GATEWAY_FETCH_FAILED",c)}if(!l.ok)throw new _(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${l.status})`,"GATEWAY_FETCH_FAILED");let o=await l.arrayBuffer();return {bytes:Buffer.from(o),sha256:s.sha256,signature:s.signature,libraryVersion:s.libraryVersion,bundleVersion:s.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:a}=await import('jose'),i=await a(ge,"RS256"),{payload:l}=await s(e,i),o=JSON.parse(new TextDecoder().decode(l));if(o.purpose!=="gateway-bundle")throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(o.libraryVersion!==t)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(o.sha256!==r)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof _?s:new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=join(homedir(),".inference-relay","gateway","runtime.cjs"),r=dirname(t),s=createRequire(t),a={exports:{}};compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(a.exports,s,a,t,r);let l=a.exports;if(!l.ClaudeCLIProvider)throw new _("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return l}catch(t){throw t instanceof _?t:new _("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){W.clear();}};});var He={};xe(He,{detectCLI:()=>N});function Lt(n){let e=process.env.PATH;if(!e)return null;let t=process.platform==="win32",r=t?";":":",s=t?(process.env.PATHEXT??".COM;.EXE;.BAT;.CMD").split(";").map(a=>a.toLowerCase()):[""];for(let a of e.split(r))if(a)for(let i of s){let l=join(a,n+i);if(existsSync(l))return l}return null}async function N(){if(!Lt("claude"))return {available:false,authenticated:false};let e=null;try{let r=execSync("claude --version",{encoding:"utf-8",timeout:5e3}).trim(),s=r.match(/(\d+\.\d+\.\d+)/);e=s?s[1]:r;}catch{}let t;return e&&!xt.some(r=>e.startsWith(r.split(".").slice(0,2).join(".")))&&(t=`CLI version ${e} is not tested with this version of inference-relay. Streaming may be unstable.`),{available:true,authenticated:true,cliVersion:e||void 0,versionWarning:t}}var xt,Q=C(()=>{xt=["2.1.87"];});var Mt,Z,Be=C(()=>{$();be();Mt="1.5.2",Z=class extends w{type="claude-cli";supportsStreaming=true;supportsMultimodal=true;platformRequirement="desktop";licenseKey;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.licenseKey=e;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await z.load(this.licenseKey,Mt)).ClaudeCLIProvider,r=new t;return this.loadedProvider=r,r}catch(e){throw this.loadingPromise=null,this.health.status="unhealthy",this.health.errorCount++,e instanceof _?this.health.lastError=e.message:e instanceof Error&&(this.health.lastError=e.message),e}})(),this.loadingPromise)}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(Q(),He));return e()}async execute(e,t){return (await this.ensureLoaded()).execute(e,t)}async streamRaw(e,t){return (await this.ensureLoaded()).streamRaw(e,t)}estimateCost(e){if(this.loadedProvider)return this.loadedProvider.estimateCost(e);let r=JSON.stringify(e.messages).length/4+5e3,s=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(s*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};});function Ve(n){return ee[n]||n}function ve(n){return $e.find(e=>e.canonical===n)?.provider}var $e,ee,Ce=C(()=>{$e=[{canonical:"claude-haiku-4-5",apiId:"claude-haiku-4-5-20251001",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[.8,4]},{canonical:"claude-sonnet-4-6",apiId:"claude-sonnet-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[3,15]},{canonical:"claude-opus-4-6",apiId:"claude-opus-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[15,75]},{canonical:"gpt-4.1",apiId:"gpt-4.1",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[2,8]},{canonical:"gpt-4.1-mini",apiId:"gpt-4.1-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.4,1.6]},{canonical:"gpt-4.1-nano",apiId:"gpt-4.1-nano",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.1,.4]},{canonical:"gpt-4o",apiId:"gpt-4o",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[2.5,10]},{canonical:"gpt-4o-mini",apiId:"gpt-4o-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[.15,.6]},{canonical:"o4-mini",apiId:"o4-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o3",apiId:"o3",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[.4,1.6]},{canonical:"o3-mini",apiId:"o3-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o1",apiId:"o1",provider:"openai-api",capabilities:{streaming:false,tools:false,multimodal:false,contextWindow:2e5},pricing:[15,60]},{canonical:"llama3.1",apiId:"llama3.1",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"mistral",apiId:"mistral",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}},{canonical:"mistral-nemo",apiId:"mistral-nemo",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"llava",apiId:"llava",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:true,contextWindow:32e3}},{canonical:"qwen2:0.5b",apiId:"qwen2:0.5b",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}}],ee=Object.fromEntries($e.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));ee["claude-sonnet-4"]="claude-sonnet-4-20250514";ee["claude-opus-4"]="claude-opus-4-20250514";ee["claude-haiku-4"]="claude-haiku-4-5-20251001";});function We(n){if(Ae[n])return Ae[n];for(let[e,t]of Object.entries(Ae))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Dt,Ot,Ae,te,Ge=C(()=>{$();Ce();Dt="https://api.anthropic.com/v1/messages",Ot="2023-06-01",Ae={"claude-sonnet-4-5-20250514":[3,15],"claude-sonnet-4-20250514":[3,15],"claude-haiku-4-5-20250414":[.8,4],"claude-opus-4-20250514":[15,75]};te=class extends w{type="anthropic-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;dangerousDirectBrowserAccess;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||Dt,this.dangerousDirectBrowserAccess=e.dangerousDirectBrowserAccess??false;}async probe(){try{let e=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{available:!0,authenticated:!1}:e.ok||e.status===429?{available:!0,authenticated:!0,rateLimitTier:e.headers.get("anthropic-ratelimit-tier")??void 0}:e.status===529?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),a=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!a.ok)throw this.handleErrorResponse(a),new Error("unreachable");let i=await a.json(),l=Date.now()-r;this.recordSuccess();let[o,p]=We(i.model||e.model),c=((i.usage?.input_tokens||0)*o+(i.usage?.output_tokens||0)*p)/1e6,d={},h=["request-id","x-request-id","anthropic-ratelimit-requests-limit","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-reset","anthropic-ratelimit-tokens-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-reset","anthropic-ratelimit-tier"];for(let m of h){let E=a.headers.get(m);E&&(d[m]=E);}return {content:i.content||[],model:i.model||e.model,usage:{input_tokens:i.usage?.input_tokens||0,output_tokens:i.usage?.output_tokens||0},stop_reason:i.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(c*1e6)/1e6,durationMs:l,fallbackChain:["anthropic-api:success"],headers:Object.keys(d).length>0?d:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let a=s.body.getReader(),i=new TextDecoder;return (async function*(){let l="",o=false;try{for(;;){let{done:p,value:c}=await a.read();if(p)break;l+=i.decode(c,{stream:!0});let d=l.split(`
12
12
  `);l=d.pop()||"";let h=null;for(let m of d)if(m.startsWith("event: "))h=m.slice(7).trim();else if(m.startsWith("data: ")){let E=m.slice(6);if(h&&E)try{let u=JSON.parse(E);u.type==="message_stop"&&(o=!0),yield u;}catch{console.warn("[inference-relay] Skipped malformed SSE data:",E.substring(0,100));}h=null;}else m.trim()===""&&(h=null);}o||(yield {type:"message_stop"});}finally{try{a.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[a,i]=We(e.model),l=(s*a+1e3*i)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(l*1e4)/1e4,model:e.model,provider:"anthropic-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){let e={"content-type":"application/json","x-api-key":this.apiKey,"anthropic-version":Ot};return this.dangerousDirectBrowserAccess&&(e["anthropic-dangerous-direct-browser-access"]="true"),e}buildRequestBody(e,t){let r={model:Ve(e.model),max_tokens:e.max_tokens,messages:e.messages};return t&&(r.stream=true),e.system&&(r.system=e.system),e.temperature!==void 0&&(r.temperature=e.temperature),e.tools&&e.tools.length>0&&(r.tools=e.tools),e.metadata&&(r.metadata=e.metadata),r}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let a=new Error(`ANTHROPIC_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw a.retryAfterMs=s,a}throw t===529?(this.health.status="degraded",this.health.lastError="API overloaded",this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_OVERLOADED: API is temporarily overloaded (529)")):(this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`ANTHROPIC_API_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};});function Ke(n){if(Re[n])return Re[n];for(let[e,t]of Object.entries(Re))if(n.startsWith(e))return t;return [2.5,10]}function Nt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Ft(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n){let s=Nt(r.content);if(r.role==="assistant"&&Array.isArray(r.content)){let a=r.content.filter(i=>i.type==="tool_use");if(a.length>0){t.push({role:"assistant",content:s||"",tool_calls:a.map(i=>({id:i.id||`call_${Math.random().toString(36).slice(2)}`,type:"function",function:{name:i.name,arguments:typeof i.input=="string"?i.input:JSON.stringify(i.input)}}))});continue}}t.push({role:r.role,content:s});}return t}function je(n){switch(n){case "stop":return "end_turn";case "length":return "max_tokens";case "tool_calls":case "function_call":return "tool_use";default:return "end_turn"}}var Ut,Ye,Re,ne,qe=C(()=>{$();Ut="https://api.openai.com/v1/chat/completions",Ye=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],Re={"gpt-4.1":[2,8],"gpt-4.1-mini":[.4,1.6],"gpt-4.1-nano":[.1,.4],"gpt-4o":[2.5,10],"gpt-4o-mini":[.15,.6],"o4-mini":[1.1,4.4],o3:[.4,1.6],"o3-mini":[1.1,4.4],o1:[15,60],"o1-mini":[3,12],"gpt-4-turbo":[10,30],"gpt-4":[30,60],"gpt-3.5-turbo":[.5,1.5]};ne=class extends w{type="openai-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||Ut;}async probe(){try{let e=this.baseUrl.replace(/\/chat\/completions$/,"/models"),t=await fetch(e,{method:"GET",headers:this.buildHeaders()});return t.status===401?{available:!0,authenticated:!1}:t.ok||t.status===429?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),a=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!a.ok)throw this.handleErrorResponse(a),new Error("unreachable");let i=await a.json(),l=Date.now()-r;this.recordSuccess();let o=i.choices?.[0],p=[];if(o?.message?.content&&p.push({type:"text",text:o.message.content}),o?.message?.tool_calls)for(let g of o.message.tool_calls)p.push({type:"tool_use",id:g.id,name:g.function?.name,input:g.function?.arguments?JSON.parse(g.function.arguments):{}});let c=i.usage?.prompt_tokens||0,d=i.usage?.completion_tokens||0,[h,m]=Ke(i.model||e.model),E=(c*h+d*m)/1e6,u={},y=["x-request-id","x-ratelimit-limit-requests","x-ratelimit-remaining-requests","x-ratelimit-limit-tokens","x-ratelimit-remaining-tokens","x-ratelimit-reset-requests","x-ratelimit-reset-tokens"];for(let g of y){let f=a.headers.get(g);f&&(u[g]=f);}return {content:p,model:i.model||e.model,usage:{input_tokens:c,output_tokens:d},stop_reason:je(o?.finish_reason),provider:"openai-api",costUsd:Math.round(E*1e6)/1e6,durationMs:l,fallbackChain:["openai-api:success"],headers:Object.keys(u).length>0?u:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OPENAI_API_ERROR: Response body is null \u2014 streaming unavailable");let a=s.body.getReader(),i=new TextDecoder,l=e.model;return (async function*(){let o="",p=false,c=false,d,h;yield {type:"message_start",message:{model:l,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:m,value:E}=await a.read();if(m)break;o+=i.decode(E,{stream:!0});let u=o.split(`
13
13
  `);o=u.pop()||"";for(let y of u){if(!y.startsWith("data: "))continue;let g=y.slice(6).trim();if(g==="[DONE]"){yield {type:"message_delta",delta:{stop_reason:h||"end_turn"},usage:d||{}},yield {type:"message_stop"},c=!0;return}try{let f=JSON.parse(g);f.usage&&(d={input_tokens:f.usage.prompt_tokens||0,output_tokens:f.usage.completion_tokens||0});let R=f.choices?.[0];if(!R)continue;let b=R.delta;b?.content&&!p&&(p=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),b?.content&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:b.content}}),R.finish_reason&&(p&&(yield {type:"content_block_stop",index:0}),h=je(R.finish_reason));}catch{}}}c||(yield {type:"message_delta",delta:{stop_reason:h||"end_turn"},usage:d||{}},yield {type:"message_stop"});}finally{try{a.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[a,i]=Ke(e.model),l=(s*a+1e3*i)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(l*1e4)/1e4,model:e.model,provider:"openai-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}}buildRequestBody(e,t){let r=e.model.toLowerCase();if(!Ye.some(l=>r.startsWith(l)))throw new Error(`OPENAI_MODEL_TRANSLATION_REQUIRED: The OpenAI provider received the model name '${e.model}', which does not match any known OpenAI model prefix (${Ye.join(", ")}). The relay does NOT auto-translate model names across providers in v1.3.x. Either (a) pass an OpenAI model name like 'gpt-4o-mini' when routing to this provider, or (b) route non-OpenAI models through a provider that understands them (e.g. 'anthropic-api' for Claude models).`);let a=Ft(e.messages,e.system),i={model:e.model,max_tokens:e.max_tokens,messages:a};return t&&(i.stream=true,i.stream_options={include_usage:true}),e.temperature!==void 0&&(i.temperature=e.temperature),e.tools&&e.tools.length>0&&(i.tools=e.tools),i}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("OPENAI_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let a=new Error(`OPENAI_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw a.retryAfterMs=s,a}throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`OPENAI_API_ERROR: Request failed with status ${t}`)}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};});function Bt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function $t(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:Bt(r.content)});return t}var Ht,re,Je=C(()=>{$();Ht="http://localhost:11434";re=class extends w{type="ollama";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.baseUrl=e?.baseUrl?.replace(/\/$/,"")||Ht;}async probe(){try{return (await fetch(`${this.baseUrl}/api/tags`,{method:"GET"})).ok?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),a=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),signal:t?.signal});if(!a.ok)throw this.handleErrorResponse(a),new Error("unreachable");let i=await a.json(),l=Date.now()-r;this.recordSuccess();let o=[];i.message?.content&&o.push({type:"text",text:i.message.content});let p=i.prompt_eval_count||0,c=i.eval_count||0;return {content:o,model:i.model||e.model,usage:{input_tokens:p,output_tokens:c},stop_reason:(i.done,"end_turn"),provider:"ollama",costUsd:0,durationMs:l,fallbackChain:["ollama:success"]}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OLLAMA_ERROR: Response body is null \u2014 streaming unavailable");let a=s.body.getReader(),i=new TextDecoder,l=e.model;return (async function*(){let o="",p=false,c=false;yield {type:"message_start",message:{model:l,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:d,value:h}=await a.read();if(d)break;o+=i.decode(h,{stream:!0});let m=o.split(`
14
14
  `);o=m.pop()||"";for(let E of m){let u=E.trim();if(u)try{let y=JSON.parse(u);if(y.message?.content&&(p||(p=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:y.message.content}}),y.done){p&&(yield {type:"content_block_stop",index:0}),yield {type:"message_delta",delta:{stop_reason:"end_turn"},usage:{input_tokens:y.prompt_eval_count||0,output_tokens:y.eval_count||0}},yield {type:"message_stop"},c=!0;return}}catch{}}}c||(yield {type:"message_stop"});}finally{try{a.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0;return {estimatedInputTokens:t+r,estimatedCost:0,model:e.model,provider:"ollama"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildRequestBody(e,t){if(e.tools&&e.tools.length>0)throw new Error(`OLLAMA_TOOLS_NOT_SUPPORTED: The Ollama provider received ${e.tools.length} tool definition(s) in params.tools, but this provider does not implement function calling in v1.3.x. For tool-use workflows route to 'anthropic-api' or 'openai-api' instead. Tracking issue: 1.4.0 ships an Ollama tool-use shim for models that support native function calling (llama3.1, mistral-nemo, etc.).`);let r=$t(e.messages,e.system),s={model:e.model,messages:r,stream:t};return e.temperature!==void 0&&(s.options={temperature:e.temperature}),s}handleErrorResponse(e){let t=e.status;throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),t===404?(this.health.status="unhealthy",this.health.lastError="Model not found",new Error("OLLAMA_MODEL_NOT_FOUND: Requested model is not available locally (404)")):(this.health.status="unhealthy",this.health.lastError=`Request failed with status ${t}`,new Error(`OLLAMA_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};});var se,ze=C(()=>{se=class extends EventEmitter{constructor(){super(),this.setMaxListeners(50);}emitTyped(e){return this.emit(e.kind,e)}onTyped(e,t){return this.on(e,t)}offTyped(e,t){return this.off(e,t)}};});function ie(n,e){if(e instanceof _)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,rt)||"unknown"}`}function Qe(n){return n.messages.some(e=>typeof e.content=="string"?false:Array.isArray(e.content)&&e.content.some(t=>t.type==="image"||t.type==="image_url"))}function ke(n){if(!(n instanceof Error))return "unknown";let e=n.code;if(typeof e=="string"){if(e==="LICENSE_REJECTED")return "auth_failed";if(e==="GATEWAY_FETCH_FAILED"||e==="GATEWAY_VERIFICATION_FAILED"||e==="GATEWAY_LOAD_FAILED")return "gateway_unavailable"}let t=n.message.toLowerCase(),r=n.name.toLowerCase();return t.startsWith("openai_model_translation_required:")||t.startsWith("ollama_tools_not_supported:")||t.startsWith("multimodal_cli_too_old:")?"provider_incompatible":t.includes("rate limit")||t.includes("429")||r.includes("ratelimit")?"rate_limited":t.includes("auth")||t.includes("401")||t.includes("403")||t.includes("unauthorized")||t.includes("forbidden")?"auth_failed":t.includes("timeout")||t.includes("timed out")||t.includes("aborted")||r==="aborterror"||r==="timeouterror"?"timeout":"unknown"}function Ze(n){return [...n].sort((e,t)=>e.priority-t.priority)}function et(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function Wt(n,e,t){typeof t.input_tokens=="number"&&(n.inputTokens=t.input_tokens),typeof t.output_tokens=="number"&&(e==="anthropic-api"||e==="claude-cli"?n.outputTokens+=t.output_tokens:n.outputTokens=t.output_tokens);}function tt(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function Gt(n,e){if(e.type==="content_block_start"){let t=e.content_block;t?.type==="text"?n.content.push({type:"text",text:t.text||"",open:true}):t?.type==="tool_use"&&n.content.push({type:"tool_use",id:t.id,name:t.name,input:{},_partialJson:"",open:true});}else if(e.type==="content_block_delta"){let t=n.content[n.content.length-1];if(!t)return;t.type==="text"&&e.delta?.type==="text_delta"?t.text+=e.delta.text||"":t.type==="tool_use"&&e.delta?.type==="input_json_delta"&&(t._partialJson=(t._partialJson||"")+(e.delta.partial_json||""));}else if(e.type==="content_block_stop"){for(let t=n.content.length-1;t>=0;t--)if(n.content[t].open){if(n.content[t].open=false,n.content[t].type==="tool_use"){let r=n.content[t];try{r.input=JSON.parse(r._partialJson||"{}");}catch{}delete r._partialJson;}break}}}function Yt(n,e,t,r,s){if(s&&n.type==="content_block_delta"&&n.index===s.fromIndex)return {action:"yield",event:{...n,index:s.toIndex}};if(s&&n.type==="content_block_stop"&&n.index===s.fromIndex)return {action:"suppress",coalesceMode:null,coalesceModeCleared:true};if(r&&n.type==="content_block_start"&&n.content_block?.type==="text"){let i=t.content[t.content.length-1];if(i?.type==="text"&&i.open===true)return {action:"suppress",coalesceMode:{fromIndex:n.index+e,toIndex:t.content.length-1},clearedJustFailedOver:true}}let a=r&&n.type==="content_block_start";return typeof n.index=="number"&&e>0?{action:"yield",event:{...n,index:n.index+e},clearedJustFailedOver:a}:{action:"yield",event:n,clearedJustFailedOver:a}}function Kt(n){let e=[];for(let t of n)t.type==="text"?t.text&&e.push({type:"text",text:t.text}):t.type==="tool_use"&&!t.open&&t.input&&Object.keys(t.input).length>0&&e.push({type:"tool_use",id:t.id,name:t.name,input:t.input});return e}function jt(n,e){return n?`${n}
package/dist/index.cjs CHANGED
@@ -7,7 +7,7 @@ kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
7
7
  7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
8
8
  Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
9
9
  UQIDAQAB
10
- -----END PUBLIC KEY-----`,pe={version:"1.0.0",cliVersion:"2.1.87",eventTypes:{system:"system",streamEvent:"stream_event",assistant:"assistant",result:"result"},fieldMappings:{sessionId:"session_id",model:"model",cliVersion:"claude_code_version",content:"content",usage:"usage",inputTokens:"input_tokens",outputTokens:"output_tokens",stopReason:"stop_reason",isError:"is_error",totalCostUsd:"total_cost_usd",durationMs:"duration_ms",error:"error",event:"event"},syntheticModel:"<synthetic>"},M=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(me,"RS256"),{payload:i}=await t(e,s),a=JSON.parse(new TextDecoder().decode(i));return this.verificationFailures=0,this.cachedManifest=a,this.currentSecurityState="SEC_NOMINAL",{manifest:a,securityState:"SEC_NOMINAL"}}catch{if(this.verificationFailures++,this.verificationFailures>=3){this.currentSecurityState="SEC_DEGRADED";let t=2e3+Math.random()*3e3;return await new Promise(r=>setTimeout(r,t)),console.warn("[inference-relay] Logic synchronization mismatch. Routing via local recovery."),{manifest:pe,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:pe,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},Ze=new M;function ke(){Ze.clearCache();}function et(){return pe}function tt(n,e){return e.split(".").reduce((t,r)=>{if(!(r==="__proto__"||r==="constructor"||r==="prototype"))return t&&t[r]},n)}var at=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function ge(n){return path.join(os.homedir(),".inference-relay","gateway",n)}function Te(n){return path.join(ge(n),"bundle.js")}function xe(n){return path.join(ge(n),"meta.json")}var b=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},F=new Map,B=class{static async load(e,t,r=at){let s=`${t}:${e.slice(-8)}`;if(F.has(s))return F.get(s);try{let p=await this.tryLoadFromDisk(t);if(p)return F.set(s,p),p}catch{}let{bytes:i,sha256:a,signature:o,libraryVersion:l}=await this.fetchFromAuthority(e,t,r);if(crypto$1.createHash("sha256").update(i).digest("hex")!==a)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(o,l,a);try{let p=ge(t);fs.mkdirSync(p,{recursive:!0}),fs.writeFileSync(Te(t),i),fs.writeFileSync(xe(t),JSON.stringify({sha256:a,signature:o,libraryVersion:l}));}catch{}let c=this.loadIntoVm(i.toString("utf-8"));return F.set(s,c),c}static async loadFromDisk(e){if(!fs.existsSync(e))throw new b(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=fs.readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Te(e),r=xe(e);if(!fs.existsSync(t)||!fs.existsSync(r))return null;let s=fs.readFileSync(t),i=JSON.parse(fs.readFileSync(r,"utf-8"));return crypto$1.createHash("sha256").update(s).digest("hex")!==i.sha256?null:(await this.verifySignature(i.signature,i.libraryVersion,i.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r){let s,i=[0,1e3,4e3],a;for(let c of i){c>0&&await new Promise(p=>setTimeout(p,c));try{let p=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(p.status===401||p.status===403)throw new b("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(p.status>=500&&p.status<600){a=new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");continue}if(!p.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");s=await p.json(),a=null;break}catch(p){if(p instanceof b&&p.code==="LICENSE_REJECTED")throw p;a=p;}}if(a||!s)throw a instanceof b?a:new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)","GATEWAY_FETCH_FAILED",a);let o;try{o=await fetch(s.bundleUrl);}catch(c){throw new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)","GATEWAY_FETCH_FAILED",c)}if(!o.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${o.status})`,"GATEWAY_FETCH_FAILED");let l=await o.arrayBuffer();return {bytes:Buffer.from(l),sha256:s.sha256,signature:s.signature,libraryVersion:s.libraryVersion,bundleVersion:s.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:i}=await import('jose'),a=await i(me,"RS256"),{payload:o}=await s(e,a),l=JSON.parse(new TextDecoder().decode(o));if(l.purpose!=="gateway-bundle")throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof b?s:new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=path.join(os.homedir(),".inference-relay","gateway","runtime.cjs"),r=path.dirname(t),s=module$1.createRequire(t),i={exports:{}};vm.compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(i.exports,s,i,t,r);let o=i.exports;if(!o.ClaudeCLIProvider)throw new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return o}catch(t){throw t instanceof b?t:new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){F.clear();}};var pt="1.5.0",te=class extends R{type="claude-cli";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";licenseKey;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.licenseKey=e;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await B.load(this.licenseKey,pt)).ClaudeCLIProvider,r=new t;return this.loadedProvider=r,r}catch(e){throw this.loadingPromise=null,this.health.status="unhealthy",this.health.errorCount++,e instanceof b?this.health.lastError=e.message:e instanceof Error&&(this.health.lastError=e.message),e}})(),this.loadingPromise)}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(ee(),Me));return e()}async execute(e,t){return (await this.ensureLoaded()).execute(e,t)}async streamRaw(e,t){return (await this.ensureLoaded()).streamRaw(e,t)}estimateCost(e){if(this.loadedProvider)return this.loadedProvider.estimateCost(e);let r=JSON.stringify(e.messages).length/4+5e3,s=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(s*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};var G=[{canonical:"claude-haiku-4-5",apiId:"claude-haiku-4-5-20251001",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[.8,4]},{canonical:"claude-sonnet-4-6",apiId:"claude-sonnet-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[3,15]},{canonical:"claude-opus-4-6",apiId:"claude-opus-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[15,75]},{canonical:"gpt-4.1",apiId:"gpt-4.1",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[2,8]},{canonical:"gpt-4.1-mini",apiId:"gpt-4.1-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.4,1.6]},{canonical:"gpt-4.1-nano",apiId:"gpt-4.1-nano",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.1,.4]},{canonical:"gpt-4o",apiId:"gpt-4o",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[2.5,10]},{canonical:"gpt-4o-mini",apiId:"gpt-4o-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[.15,.6]},{canonical:"o4-mini",apiId:"o4-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o3",apiId:"o3",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[.4,1.6]},{canonical:"o3-mini",apiId:"o3-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o1",apiId:"o1",provider:"openai-api",capabilities:{streaming:false,tools:false,multimodal:false,contextWindow:2e5},pricing:[15,60]},{canonical:"llama3.1",apiId:"llama3.1",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"mistral",apiId:"mistral",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}},{canonical:"mistral-nemo",apiId:"mistral-nemo",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"llava",apiId:"llava",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:true,contextWindow:32e3}},{canonical:"qwen2:0.5b",apiId:"qwen2:0.5b",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}}],K=Object.fromEntries(G.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));K["claude-sonnet-4"]="claude-sonnet-4-20250514";K["claude-opus-4"]="claude-opus-4-20250514";K["claude-haiku-4"]="claude-haiku-4-5-20251001";function fe(n){return K[n]||n}function mt(n){return G.find(e=>e.canonical===n)}function re(n){return G.find(e=>e.canonical===n)?.provider}function ht(n){return G.filter(e=>e.provider===n)}var yt="https://api.anthropic.com/v1/messages",gt="2023-06-01",be={"claude-sonnet-4-5-20250514":[3,15],"claude-sonnet-4-20250514":[3,15],"claude-haiku-4-5-20250414":[.8,4],"claude-opus-4-20250514":[15,75]};function De(n){if(be[n])return be[n];for(let[e,t]of Object.entries(be))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var V=class extends R{type="anthropic-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;dangerousDirectBrowserAccess;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||yt,this.dangerousDirectBrowserAccess=e.dangerousDirectBrowserAccess??false;}async probe(){try{let e=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{available:!0,authenticated:!1}:e.ok||e.status===429?{available:!0,authenticated:!0,rateLimitTier:e.headers.get("anthropic-ratelimit-tier")??void 0}:e.status===529?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let[l,d]=De(a.model||e.model),c=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*d)/1e6,p={},y=["request-id","x-request-id","anthropic-ratelimit-requests-limit","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-reset","anthropic-ratelimit-tokens-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-reset","anthropic-ratelimit-tier"];for(let m of y){let _=i.headers.get(m);_&&(p[m]=_);}return {content:a.content||[],model:a.model||e.model,usage:{input_tokens:a.usage?.input_tokens||0,output_tokens:a.usage?.output_tokens||0},stop_reason:a.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(c*1e6)/1e6,durationMs:o,fallbackChain:["anthropic-api:success"],headers:Object.keys(p).length>0?p:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder;return (async function*(){let o="",l=false;try{for(;;){let{done:d,value:c}=await i.read();if(d)break;o+=a.decode(c,{stream:!0});let p=o.split(`
10
+ -----END PUBLIC KEY-----`,pe={version:"1.0.0",cliVersion:"2.1.87",eventTypes:{system:"system",streamEvent:"stream_event",assistant:"assistant",result:"result"},fieldMappings:{sessionId:"session_id",model:"model",cliVersion:"claude_code_version",content:"content",usage:"usage",inputTokens:"input_tokens",outputTokens:"output_tokens",stopReason:"stop_reason",isError:"is_error",totalCostUsd:"total_cost_usd",durationMs:"duration_ms",error:"error",event:"event"},syntheticModel:"<synthetic>"},M=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(me,"RS256"),{payload:i}=await t(e,s),a=JSON.parse(new TextDecoder().decode(i));return this.verificationFailures=0,this.cachedManifest=a,this.currentSecurityState="SEC_NOMINAL",{manifest:a,securityState:"SEC_NOMINAL"}}catch{if(this.verificationFailures++,this.verificationFailures>=3){this.currentSecurityState="SEC_DEGRADED";let t=2e3+Math.random()*3e3;return await new Promise(r=>setTimeout(r,t)),console.warn("[inference-relay] Logic synchronization mismatch. Routing via local recovery."),{manifest:pe,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:pe,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},Ze=new M;function ke(){Ze.clearCache();}function et(){return pe}function tt(n,e){return e.split(".").reduce((t,r)=>{if(!(r==="__proto__"||r==="constructor"||r==="prototype"))return t&&t[r]},n)}var at=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function ge(n){return path.join(os.homedir(),".inference-relay","gateway",n)}function Te(n){return path.join(ge(n),"bundle.js")}function xe(n){return path.join(ge(n),"meta.json")}var b=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},F=new Map,B=class{static async load(e,t,r=at){let s=`${t}:${e.slice(-8)}`;if(F.has(s))return F.get(s);try{let p=await this.tryLoadFromDisk(t);if(p)return F.set(s,p),p}catch{}let{bytes:i,sha256:a,signature:o,libraryVersion:l}=await this.fetchFromAuthority(e,t,r);if(crypto$1.createHash("sha256").update(i).digest("hex")!==a)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(o,l,a);try{let p=ge(t);fs.mkdirSync(p,{recursive:!0}),fs.writeFileSync(Te(t),i),fs.writeFileSync(xe(t),JSON.stringify({sha256:a,signature:o,libraryVersion:l}));}catch{}let c=this.loadIntoVm(i.toString("utf-8"));return F.set(s,c),c}static async loadFromDisk(e){if(!fs.existsSync(e))throw new b(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=fs.readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Te(e),r=xe(e);if(!fs.existsSync(t)||!fs.existsSync(r))return null;let s=fs.readFileSync(t),i=JSON.parse(fs.readFileSync(r,"utf-8"));return crypto$1.createHash("sha256").update(s).digest("hex")!==i.sha256?null:(await this.verifySignature(i.signature,i.libraryVersion,i.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r){let s,i=[0,1e3,4e3],a;for(let c of i){c>0&&await new Promise(p=>setTimeout(p,c));try{let p=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(p.status===401||p.status===403)throw new b("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(p.status>=500&&p.status<600){a=new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");continue}if(!p.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");s=await p.json(),a=null;break}catch(p){if(p instanceof b&&p.code==="LICENSE_REJECTED")throw p;a=p;}}if(a||!s)throw a instanceof b?a:new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)","GATEWAY_FETCH_FAILED",a);let o;try{o=await fetch(s.bundleUrl);}catch(c){throw new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)","GATEWAY_FETCH_FAILED",c)}if(!o.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${o.status})`,"GATEWAY_FETCH_FAILED");let l=await o.arrayBuffer();return {bytes:Buffer.from(l),sha256:s.sha256,signature:s.signature,libraryVersion:s.libraryVersion,bundleVersion:s.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:i}=await import('jose'),a=await i(me,"RS256"),{payload:o}=await s(e,a),l=JSON.parse(new TextDecoder().decode(o));if(l.purpose!=="gateway-bundle")throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof b?s:new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=path.join(os.homedir(),".inference-relay","gateway","runtime.cjs"),r=path.dirname(t),s=module$1.createRequire(t),i={exports:{}};vm.compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(i.exports,s,i,t,r);let o=i.exports;if(!o.ClaudeCLIProvider)throw new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return o}catch(t){throw t instanceof b?t:new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){F.clear();}};var pt="1.5.2",te=class extends R{type="claude-cli";supportsStreaming=true;supportsMultimodal=true;platformRequirement="desktop";licenseKey;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.licenseKey=e;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await B.load(this.licenseKey,pt)).ClaudeCLIProvider,r=new t;return this.loadedProvider=r,r}catch(e){throw this.loadingPromise=null,this.health.status="unhealthy",this.health.errorCount++,e instanceof b?this.health.lastError=e.message:e instanceof Error&&(this.health.lastError=e.message),e}})(),this.loadingPromise)}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(ee(),Me));return e()}async execute(e,t){return (await this.ensureLoaded()).execute(e,t)}async streamRaw(e,t){return (await this.ensureLoaded()).streamRaw(e,t)}estimateCost(e){if(this.loadedProvider)return this.loadedProvider.estimateCost(e);let r=JSON.stringify(e.messages).length/4+5e3,s=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(s*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};var G=[{canonical:"claude-haiku-4-5",apiId:"claude-haiku-4-5-20251001",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[.8,4]},{canonical:"claude-sonnet-4-6",apiId:"claude-sonnet-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[3,15]},{canonical:"claude-opus-4-6",apiId:"claude-opus-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[15,75]},{canonical:"gpt-4.1",apiId:"gpt-4.1",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[2,8]},{canonical:"gpt-4.1-mini",apiId:"gpt-4.1-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.4,1.6]},{canonical:"gpt-4.1-nano",apiId:"gpt-4.1-nano",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.1,.4]},{canonical:"gpt-4o",apiId:"gpt-4o",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[2.5,10]},{canonical:"gpt-4o-mini",apiId:"gpt-4o-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[.15,.6]},{canonical:"o4-mini",apiId:"o4-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o3",apiId:"o3",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[.4,1.6]},{canonical:"o3-mini",apiId:"o3-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o1",apiId:"o1",provider:"openai-api",capabilities:{streaming:false,tools:false,multimodal:false,contextWindow:2e5},pricing:[15,60]},{canonical:"llama3.1",apiId:"llama3.1",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"mistral",apiId:"mistral",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}},{canonical:"mistral-nemo",apiId:"mistral-nemo",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"llava",apiId:"llava",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:true,contextWindow:32e3}},{canonical:"qwen2:0.5b",apiId:"qwen2:0.5b",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}}],K=Object.fromEntries(G.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));K["claude-sonnet-4"]="claude-sonnet-4-20250514";K["claude-opus-4"]="claude-opus-4-20250514";K["claude-haiku-4"]="claude-haiku-4-5-20251001";function fe(n){return K[n]||n}function mt(n){return G.find(e=>e.canonical===n)}function re(n){return G.find(e=>e.canonical===n)?.provider}function ht(n){return G.filter(e=>e.provider===n)}var yt="https://api.anthropic.com/v1/messages",gt="2023-06-01",be={"claude-sonnet-4-5-20250514":[3,15],"claude-sonnet-4-20250514":[3,15],"claude-haiku-4-5-20250414":[.8,4],"claude-opus-4-20250514":[15,75]};function De(n){if(be[n])return be[n];for(let[e,t]of Object.entries(be))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var V=class extends R{type="anthropic-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;dangerousDirectBrowserAccess;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||yt,this.dangerousDirectBrowserAccess=e.dangerousDirectBrowserAccess??false;}async probe(){try{let e=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{available:!0,authenticated:!1}:e.ok||e.status===429?{available:!0,authenticated:!0,rateLimitTier:e.headers.get("anthropic-ratelimit-tier")??void 0}:e.status===529?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let[l,d]=De(a.model||e.model),c=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*d)/1e6,p={},y=["request-id","x-request-id","anthropic-ratelimit-requests-limit","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-reset","anthropic-ratelimit-tokens-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-reset","anthropic-ratelimit-tier"];for(let m of y){let _=i.headers.get(m);_&&(p[m]=_);}return {content:a.content||[],model:a.model||e.model,usage:{input_tokens:a.usage?.input_tokens||0,output_tokens:a.usage?.output_tokens||0},stop_reason:a.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(c*1e6)/1e6,durationMs:o,fallbackChain:["anthropic-api:success"],headers:Object.keys(p).length>0?p:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder;return (async function*(){let o="",l=false;try{for(;;){let{done:d,value:c}=await i.read();if(d)break;o+=a.decode(c,{stream:!0});let p=o.split(`
11
11
  `);o=p.pop()||"";let y=null;for(let m of p)if(m.startsWith("event: "))y=m.slice(7).trim();else if(m.startsWith("data: ")){let _=m.slice(6);if(y&&_)try{let u=JSON.parse(_);u.type==="message_stop"&&(l=!0),yield u;}catch{console.warn("[inference-relay] Skipped malformed SSE data:",_.substring(0,100));}y=null;}else m.trim()===""&&(y=null);}l||(yield {type:"message_stop"});}finally{try{i.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[i,a]=De(e.model),o=(s*i+1e3*a)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(o*1e4)/1e4,model:e.model,provider:"anthropic-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){let e={"content-type":"application/json","x-api-key":this.apiKey,"anthropic-version":gt};return this.dangerousDirectBrowserAccess&&(e["anthropic-dangerous-direct-browser-access"]="true"),e}buildRequestBody(e,t){let r={model:fe(e.model),max_tokens:e.max_tokens,messages:e.messages};return t&&(r.stream=true),e.system&&(r.system=e.system),e.temperature!==void 0&&(r.temperature=e.temperature),e.tools&&e.tools.length>0&&(r.tools=e.tools),e.metadata&&(r.metadata=e.metadata),r}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let i=new Error(`ANTHROPIC_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw i.retryAfterMs=s,i}throw t===529?(this.health.status="degraded",this.health.lastError="API overloaded",this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_OVERLOADED: API is temporarily overloaded (529)")):(this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`ANTHROPIC_API_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};var ft="https://api.openai.com/v1/chat/completions",Oe=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],Ee={"gpt-4.1":[2,8],"gpt-4.1-mini":[.4,1.6],"gpt-4.1-nano":[.1,.4],"gpt-4o":[2.5,10],"gpt-4o-mini":[.15,.6],"o4-mini":[1.1,4.4],o3:[.4,1.6],"o3-mini":[1.1,4.4],o1:[15,60],"o1-mini":[3,12],"gpt-4-turbo":[10,30],"gpt-4":[30,60],"gpt-3.5-turbo":[.5,1.5]};function Ne(n){if(Ee[n])return Ee[n];for(let[e,t]of Object.entries(Ee))if(n.startsWith(e))return t;return [2.5,10]}function bt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Et(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n){let s=bt(r.content);if(r.role==="assistant"&&Array.isArray(r.content)){let i=r.content.filter(a=>a.type==="tool_use");if(i.length>0){t.push({role:"assistant",content:s||"",tool_calls:i.map(a=>({id:a.id||`call_${Math.random().toString(36).slice(2)}`,type:"function",function:{name:a.name,arguments:typeof a.input=="string"?a.input:JSON.stringify(a.input)}}))});continue}}t.push({role:r.role,content:s});}return t}function Ue(n){switch(n){case "stop":return "end_turn";case "length":return "max_tokens";case "tool_calls":case "function_call":return "tool_use";default:return "end_turn"}}var W=class extends R{type="openai-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||ft;}async probe(){try{let e=this.baseUrl.replace(/\/chat\/completions$/,"/models"),t=await fetch(e,{method:"GET",headers:this.buildHeaders()});return t.status===401?{available:!0,authenticated:!1}:t.ok||t.status===429?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let l=a.choices?.[0],d=[];if(l?.message?.content&&d.push({type:"text",text:l.message.content}),l?.message?.tool_calls)for(let h of l.message.tool_calls)d.push({type:"tool_use",id:h.id,name:h.function?.name,input:h.function?.arguments?JSON.parse(h.function.arguments):{}});let c=a.usage?.prompt_tokens||0,p=a.usage?.completion_tokens||0,[y,m]=Ne(a.model||e.model),_=(c*y+p*m)/1e6,u={},f=["x-request-id","x-ratelimit-limit-requests","x-ratelimit-remaining-requests","x-ratelimit-limit-tokens","x-ratelimit-remaining-tokens","x-ratelimit-reset-requests","x-ratelimit-reset-tokens"];for(let h of f){let g=i.headers.get(h);g&&(u[h]=g);}return {content:d,model:a.model||e.model,usage:{input_tokens:c,output_tokens:p},stop_reason:Ue(l?.finish_reason),provider:"openai-api",costUsd:Math.round(_*1e6)/1e6,durationMs:o,fallbackChain:["openai-api:success"],headers:Object.keys(u).length>0?u:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OPENAI_API_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder,o=e.model;return (async function*(){let l="",d=false,c=false,p,y;yield {type:"message_start",message:{model:o,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:m,value:_}=await i.read();if(m)break;l+=a.decode(_,{stream:!0});let u=l.split(`
12
12
  `);l=u.pop()||"";for(let f of u){if(!f.startsWith("data: "))continue;let h=f.slice(6).trim();if(h==="[DONE]"){yield {type:"message_delta",delta:{stop_reason:y||"end_turn"},usage:p||{}},yield {type:"message_stop"},c=!0;return}try{let g=JSON.parse(h);g.usage&&(p={input_tokens:g.usage.prompt_tokens||0,output_tokens:g.usage.completion_tokens||0});let C=g.choices?.[0];if(!C)continue;let E=C.delta;E?.content&&!d&&(d=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),E?.content&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:E.content}}),C.finish_reason&&(d&&(yield {type:"content_block_stop",index:0}),y=Ue(C.finish_reason));}catch{}}}c||(yield {type:"message_delta",delta:{stop_reason:y||"end_turn"},usage:p||{}},yield {type:"message_stop"});}finally{try{i.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[i,a]=Ne(e.model),o=(s*i+1e3*a)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(o*1e4)/1e4,model:e.model,provider:"openai-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}}buildRequestBody(e,t){let r=e.model.toLowerCase();if(!Oe.some(o=>r.startsWith(o)))throw new Error(`OPENAI_MODEL_TRANSLATION_REQUIRED: The OpenAI provider received the model name '${e.model}', which does not match any known OpenAI model prefix (${Oe.join(", ")}). The relay does NOT auto-translate model names across providers in v1.3.x. Either (a) pass an OpenAI model name like 'gpt-4o-mini' when routing to this provider, or (b) route non-OpenAI models through a provider that understands them (e.g. 'anthropic-api' for Claude models).`);let i=Et(e.messages,e.system),a={model:e.model,max_tokens:e.max_tokens,messages:i};return t&&(a.stream=true,a.stream_options={include_usage:true}),e.temperature!==void 0&&(a.temperature=e.temperature),e.tools&&e.tools.length>0&&(a.tools=e.tools),a}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("OPENAI_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let i=new Error(`OPENAI_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw i.retryAfterMs=s,i}throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`OPENAI_API_ERROR: Request failed with status ${t}`)}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};var _t="http://localhost:11434";function vt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Ct(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:vt(r.content)});return t}var Y=class extends R{type="ollama";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.baseUrl=e?.baseUrl?.replace(/\/$/,"")||_t;}async probe(){try{return (await fetch(`${this.baseUrl}/api/tags`,{method:"GET"})).ok?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let l=[];a.message?.content&&l.push({type:"text",text:a.message.content});let d=a.prompt_eval_count||0,c=a.eval_count||0;return {content:l,model:a.model||e.model,usage:{input_tokens:d,output_tokens:c},stop_reason:(a.done,"end_turn"),provider:"ollama",costUsd:0,durationMs:o,fallbackChain:["ollama:success"]}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OLLAMA_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder,o=e.model;return (async function*(){let l="",d=false,c=false;yield {type:"message_start",message:{model:o,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:p,value:y}=await i.read();if(p)break;l+=a.decode(y,{stream:!0});let m=l.split(`
13
13
  `);l=m.pop()||"";for(let _ of m){let u=_.trim();if(u)try{let f=JSON.parse(u);if(f.message?.content&&(d||(d=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:f.message.content}}),f.done){d&&(yield {type:"content_block_stop",index:0}),yield {type:"message_delta",delta:{stop_reason:"end_turn"},usage:{input_tokens:f.prompt_eval_count||0,output_tokens:f.eval_count||0}},yield {type:"message_stop"},c=!0;return}}catch{}}}c||(yield {type:"message_stop"});}finally{try{i.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0;return {estimatedInputTokens:t+r,estimatedCost:0,model:e.model,provider:"ollama"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildRequestBody(e,t){if(e.tools&&e.tools.length>0)throw new Error(`OLLAMA_TOOLS_NOT_SUPPORTED: The Ollama provider received ${e.tools.length} tool definition(s) in params.tools, but this provider does not implement function calling in v1.3.x. For tool-use workflows route to 'anthropic-api' or 'openai-api' instead. Tracking issue: 1.4.0 ships an Ollama tool-use shim for models that support native function calling (llama3.1, mistral-nemo, etc.).`);let r=Ct(e.messages,e.system),s={model:e.model,messages:r,stream:t};return e.temperature!==void 0&&(s.options={temperature:e.temperature}),s}handleErrorResponse(e){let t=e.status;throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),t===404?(this.health.status="unhealthy",this.health.lastError="Model not found",new Error("OLLAMA_MODEL_NOT_FOUND: Requested model is not available locally (404)")):(this.health.status="unhealthy",this.health.lastError=`Request failed with status ${t}`,new Error(`OLLAMA_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};var $=class extends events.EventEmitter{constructor(){super(),this.setMaxListeners(50);}emitTyped(e){return this.emit(e.kind,e)}onTyped(e,t){return this.on(e,t)}offTyped(e,t){return this.off(e,t)}};var We=200;function ne(n,e){if(e instanceof b)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,We)||"unknown"}`}var Fe=new Set(["anthropic-api","openai-api","ollama"]),q=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}};function Be(n){return n.messages.some(e=>typeof e.content=="string"?false:Array.isArray(e.content)&&e.content.some(t=>t.type==="image"||t.type==="image_url"))}function _e(n){if(!(n instanceof Error))return "unknown";let e=n.code;if(typeof e=="string"){if(e==="LICENSE_REJECTED")return "auth_failed";if(e==="GATEWAY_FETCH_FAILED"||e==="GATEWAY_VERIFICATION_FAILED"||e==="GATEWAY_LOAD_FAILED")return "gateway_unavailable"}let t=n.message.toLowerCase(),r=n.name.toLowerCase();return t.startsWith("openai_model_translation_required:")||t.startsWith("ollama_tools_not_supported:")||t.startsWith("multimodal_cli_too_old:")?"provider_incompatible":t.includes("rate limit")||t.includes("429")||r.includes("ratelimit")?"rate_limited":t.includes("auth")||t.includes("401")||t.includes("403")||t.includes("unauthorized")||t.includes("forbidden")?"auth_failed":t.includes("timeout")||t.includes("timed out")||t.includes("aborted")||r==="aborterror"||r==="timeouterror"?"timeout":"unknown"}function He(n){return [...n].sort((e,t)=>e.priority-t.priority)}var j=class n{healthMap=new Map;engineEvents=new $;static UNHEALTHY_TTL_MS=300*1e3;getHealthStatus(e){let t=this.healthMap.get(e);return t?t.status==="unhealthy"&&Date.now()-t.updatedAt>=n.UNHEALTHY_TTL_MS?(this.healthMap.delete(e),"healthy"):t.status:"healthy"}markUnhealthy(e,t){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now()});}markDegraded(e,t){this.healthMap.set(e,{status:"degraded",lastError:t,updatedAt:Date.now()});}markHealthy(e){this.healthMap.set(e,{status:"healthy",updatedAt:Date.now()});}resetHealth(){this.healthMap.clear();}async execute(e,t,r){let s=He(t),i=[],a=Be(e),o=crypto$1.randomUUID(),l=Date.now();for(let d of s){let c=d.type;if(this.getHealthStatus(c)==="unhealthy"){i.push(`${c}:skipped:unhealthy`);continue}if(a&&!d.supportsMultimodal){i.push(`${c}:skipped:no_multimodal`);continue}let y=re(e.model);if(y&&y!==c&&Fe.has(c)){i.push(`${c}:skipped:wrong_provider`);continue}try{let m=await d.execute(e,{signal:r?.signal});return this.markHealthy(c),i.push(`${c}:success`),this.emitEngineEvent({kind:"stream_complete",callId:o,id:crypto$1.randomUUID(),ts:Date.now(),stitched:!1,segments:[{provider:c,inputTokens:m.usage.input_tokens,outputTokens:m.usage.output_tokens,costUsd:m.costUsd,userCostUsd:m.userCostUsd??0}],provider:c,model:m.model,inputTokens:m.usage.input_tokens,outputTokens:m.usage.output_tokens,costUsd:m.costUsd,userCostUsd:m.userCostUsd,durationMs:m.durationMs??Date.now()-l,stopReason:m.stop_reason,fallbackChain:i,rateLimitHit:!1,securityState:r?.licenseState}),{...m,fallbackChain:i}}catch(m){if(m?.name==="AbortError"||r?.signal?.aborted)throw m;switch(_e(m)){case "rate_limited":d.reportRateLimit({provider:c,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(c,"rate_limited"),i.push(`${c}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(c,"auth_failed"),i.push(`${c}:failed:auth_failed`);break;case "timeout":i.push(`${c}:failed:timeout`);break;case "provider_incompatible":i.push(`${c}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(c,"gateway_unavailable"),i.push(ne(c,m));break;default:i.push(ne(c,m));break}}}throw new q(i)}async stream(e,t,r){let s=crypto$1.randomUUID(),i=He(t),a=Be(e),o=Date.now(),l=[],d=null,c=null;for(let h of i){let g=h.type;if(this.getHealthStatus(g)==="unhealthy"){l.push(`${g}:skipped:unhealthy`);continue}if(a&&!h.supportsMultimodal){l.push(`${g}:skipped:no_multimodal`);continue}if(!h.supportsStreaming){l.push(`${g}:skipped:no_streaming`);continue}let C=re(e.model);if(C&&C!==g&&Fe.has(g)){l.push(`${g}:skipped:wrong_provider`);continue}try{c=await h.streamRaw(e,{signal:r?.signal}),d=h,l.push(`${g}:success`);break}catch(E){if(E?.name==="AbortError"||r?.signal?.aborted)throw E;switch(_e(E)){case "rate_limited":h.reportRateLimit({provider:g,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(g,"rate_limited"),l.push(`${g}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(g,"auth_failed"),l.push(`${g}:failed:auth_failed`);break;case "timeout":l.push(`${g}:failed:timeout`);break;case "provider_incompatible":l.push(`${g}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(g,"gateway_unavailable"),l.push(ne(g,E));break;default:l.push(ne(g,E));break}}}if(!d||!c)throw new q(l);let y=this,m=r?.maxMidStreamFailovers??2,_=new Set([d]);async function*u(){let h=d,g=c[Symbol.asyncIterator](),C={role:"assistant",content:[]},E={segments:[]},I=Ge(h.type);E.segments.push(I);let Re=0,z=null,X=false,de=m,O="",N="";for(y.emitEngineEvent({kind:"segment_start",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type});;)try{for(;;){let A=await g.next();if(A.done)break;let T=A.value,k=Pt(T,Re,C,X,z);if(k.action==="suppress"){"coalesceMode"in k&&(z=k.coalesceMode),k.clearedJustFailedOver&&(X=!1);continue}k.coalesceModeCleared&&(z=null),k.clearedJustFailedOver&&(X=!1);let v=k.event;if(St(C,v),v.type==="message_start"){if(E.segments.length>1)continue;O=v.message?.model||O,v.message?.usage?.input_tokens!=null&&(I.inputTokens=v.message.usage.input_tokens);}if(v.type==="message_delta"&&(v.delta?.stop_reason&&(N=v.delta.stop_reason),v.usage)){Rt(I,h.type,v.usage),yield {...v,usage:void 0};continue}if(v.type==="message_stop")break;yield v;}if(C.content.length===0&&I.outputTokens===0)throw new Error("stream ended without producing any content");y.markHealthy(h.type),y.emitEngineEvent({kind:"segment_complete",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type,usage:{...I}});let S=Ke(E.segments);yield {type:"message_delta",delta:{stop_reason:N||"end_turn"},usage:S},yield {type:"message_stop"},y.emitEngineEvent({kind:"stream_complete",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),stitched:E.segments.length>1,segments:E.segments.map(A=>({...A})),provider:E.segments.map(A=>A.provider).join("+"),model:O,inputTokens:S.input_tokens,outputTokens:S.output_tokens,costUsd:E.segments.reduce((A,T)=>A+T.costUsd,0),userCostUsd:E.segments.reduce((A,T)=>A+T.userCostUsd,0),durationMs:Date.now()-o,stopReason:N||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(S){if(S?.name==="AbortError"||r?.signal?.aborted)throw S;let A=_e(S);try{await g.return?.();}catch{}if(y.markUnhealthy(h.type,String(S)),y.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),from:h.type,bytesBuffered:Ve(C),errorClass:A,retriesLeft:de}),l.push(`${h.type}:partial(${Ve(C)}b)`),de<=0)throw y.emitTerminalExhaustion(s,E,O,N,l,o,r?.licenseState),S;let T=kt(C.content),k=[...e.messages,{role:"assistant",content:T}],v=null,Q=null,Se=h;for(;;){let w=y.nextHealthyProvider(i,Se,a,_);if(!w)break;Se=w,_.add(w);let je={...e,messages:k,...w.type!=="anthropic-api"&&w.type!=="claude-cli"?{system:wt(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{Q=await w.streamRaw(je,{signal:r?.signal}),v=w;break}catch(Pe){y.markUnhealthy(w.type,String(Pe)),l.push(`${w.type}:failed_connect:${String(Pe).slice(0,We)}`);}}if(!v||!Q)throw y.emitTerminalExhaustion(s,E,O,N,l,o,r?.licenseState),S;l.push(`${v.type}:stitched`),y.emitEngineEvent({kind:"mid_stream_failover_success",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),from:h.type,to:v.type}),Re=It(C)+1,de--,h=v,g=Q[Symbol.asyncIterator](),X=true,z=null,I=Ge(h.type),E.segments.push(I),y.emitEngineEvent({kind:"segment_start",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type});}}let f=u();return r?.licenseState==="SEC_DEGRADED"&&(f=Tt(f)),L(f)}nextHealthyProvider(e,t,r,s){let i=e.indexOf(t);if(i===-1)return null;for(let a=i+1;a<e.length;a++){let o=e[a];if(!s.has(o)&&!(r&&!o.supportsMultimodal)&&o.supportsStreaming)return o}return null}emitEngineEvent(e){this.engineEvents.emitTyped(e);}emitTerminalExhaustion(e,t,r,s,i,a,o){let l=Ke(t.segments);this.emitEngineEvent({kind:"stream_complete",callId:e,id:crypto$1.randomUUID(),ts:Date.now(),stitched:t.segments.length>1,segments:t.segments.map(d=>({...d})),provider:t.segments.map(d=>d.provider).join("+"),model:r,inputTokens:l.input_tokens,outputTokens:l.output_tokens,costUsd:t.segments.reduce((d,c)=>d+c.costUsd,0),userCostUsd:t.segments.reduce((d,c)=>d+c.userCostUsd,0),durationMs:Date.now()-a,stopReason:s||"error",fallbackChain:i,rateLimitHit:false,securityState:o});}};function Ge(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function Rt(n,e,t){typeof t.input_tokens=="number"&&(n.inputTokens=t.input_tokens),typeof t.output_tokens=="number"&&(e==="anthropic-api"||e==="claude-cli"?n.outputTokens+=t.output_tokens:n.outputTokens=t.output_tokens);}function Ke(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function St(n,e){if(e.type==="content_block_start"){let t=e.content_block;t?.type==="text"?n.content.push({type:"text",text:t.text||"",open:true}):t?.type==="tool_use"&&n.content.push({type:"tool_use",id:t.id,name:t.name,input:{},_partialJson:"",open:true});}else if(e.type==="content_block_delta"){let t=n.content[n.content.length-1];if(!t)return;t.type==="text"&&e.delta?.type==="text_delta"?t.text+=e.delta.text||"":t.type==="tool_use"&&e.delta?.type==="input_json_delta"&&(t._partialJson=(t._partialJson||"")+(e.delta.partial_json||""));}else if(e.type==="content_block_stop"){for(let t=n.content.length-1;t>=0;t--)if(n.content[t].open){if(n.content[t].open=false,n.content[t].type==="tool_use"){let r=n.content[t];try{r.input=JSON.parse(r._partialJson||"{}");}catch{}delete r._partialJson;}break}}}function Pt(n,e,t,r,s){if(s&&n.type==="content_block_delta"&&n.index===s.fromIndex)return {action:"yield",event:{...n,index:s.toIndex}};if(s&&n.type==="content_block_stop"&&n.index===s.fromIndex)return {action:"suppress",coalesceMode:null,coalesceModeCleared:true};if(r&&n.type==="content_block_start"&&n.content_block?.type==="text"){let a=t.content[t.content.length-1];if(a?.type==="text"&&a.open===true)return {action:"suppress",coalesceMode:{fromIndex:n.index+e,toIndex:t.content.length-1},clearedJustFailedOver:true}}let i=r&&n.type==="content_block_start";return typeof n.index=="number"&&e>0?{action:"yield",event:{...n,index:n.index+e},clearedJustFailedOver:i}:{action:"yield",event:n,clearedJustFailedOver:i}}function kt(n){let e=[];for(let t of n)t.type==="text"?t.text&&e.push({type:"text",text:t.text}):t.type==="tool_use"&&!t.open&&t.input&&Object.keys(t.input).length>0&&e.push({type:"tool_use",id:t.id,name:t.name,input:t.input});return e}function wt(n,e){return n?`${n}
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
7
7
  7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
8
8
  Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
9
9
  UQIDAQAB
10
- -----END PUBLIC KEY-----`,pe={version:"1.0.0",cliVersion:"2.1.87",eventTypes:{system:"system",streamEvent:"stream_event",assistant:"assistant",result:"result"},fieldMappings:{sessionId:"session_id",model:"model",cliVersion:"claude_code_version",content:"content",usage:"usage",inputTokens:"input_tokens",outputTokens:"output_tokens",stopReason:"stop_reason",isError:"is_error",totalCostUsd:"total_cost_usd",durationMs:"duration_ms",error:"error",event:"event"},syntheticModel:"<synthetic>"},M=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(me,"RS256"),{payload:i}=await t(e,s),a=JSON.parse(new TextDecoder().decode(i));return this.verificationFailures=0,this.cachedManifest=a,this.currentSecurityState="SEC_NOMINAL",{manifest:a,securityState:"SEC_NOMINAL"}}catch{if(this.verificationFailures++,this.verificationFailures>=3){this.currentSecurityState="SEC_DEGRADED";let t=2e3+Math.random()*3e3;return await new Promise(r=>setTimeout(r,t)),console.warn("[inference-relay] Logic synchronization mismatch. Routing via local recovery."),{manifest:pe,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:pe,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},Ze=new M;function ke(){Ze.clearCache();}function et(){return pe}function tt(n,e){return e.split(".").reduce((t,r)=>{if(!(r==="__proto__"||r==="constructor"||r==="prototype"))return t&&t[r]},n)}var at=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function ge(n){return join(homedir(),".inference-relay","gateway",n)}function Te(n){return join(ge(n),"bundle.js")}function xe(n){return join(ge(n),"meta.json")}var b=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},F=new Map,B=class{static async load(e,t,r=at){let s=`${t}:${e.slice(-8)}`;if(F.has(s))return F.get(s);try{let p=await this.tryLoadFromDisk(t);if(p)return F.set(s,p),p}catch{}let{bytes:i,sha256:a,signature:o,libraryVersion:l}=await this.fetchFromAuthority(e,t,r);if(createHash("sha256").update(i).digest("hex")!==a)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(o,l,a);try{let p=ge(t);mkdirSync(p,{recursive:!0}),writeFileSync(Te(t),i),writeFileSync(xe(t),JSON.stringify({sha256:a,signature:o,libraryVersion:l}));}catch{}let c=this.loadIntoVm(i.toString("utf-8"));return F.set(s,c),c}static async loadFromDisk(e){if(!existsSync(e))throw new b(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Te(e),r=xe(e);if(!existsSync(t)||!existsSync(r))return null;let s=readFileSync(t),i=JSON.parse(readFileSync(r,"utf-8"));return createHash("sha256").update(s).digest("hex")!==i.sha256?null:(await this.verifySignature(i.signature,i.libraryVersion,i.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r){let s,i=[0,1e3,4e3],a;for(let c of i){c>0&&await new Promise(p=>setTimeout(p,c));try{let p=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(p.status===401||p.status===403)throw new b("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(p.status>=500&&p.status<600){a=new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");continue}if(!p.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");s=await p.json(),a=null;break}catch(p){if(p instanceof b&&p.code==="LICENSE_REJECTED")throw p;a=p;}}if(a||!s)throw a instanceof b?a:new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)","GATEWAY_FETCH_FAILED",a);let o;try{o=await fetch(s.bundleUrl);}catch(c){throw new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)","GATEWAY_FETCH_FAILED",c)}if(!o.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${o.status})`,"GATEWAY_FETCH_FAILED");let l=await o.arrayBuffer();return {bytes:Buffer.from(l),sha256:s.sha256,signature:s.signature,libraryVersion:s.libraryVersion,bundleVersion:s.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:i}=await import('jose'),a=await i(me,"RS256"),{payload:o}=await s(e,a),l=JSON.parse(new TextDecoder().decode(o));if(l.purpose!=="gateway-bundle")throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof b?s:new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=join(homedir(),".inference-relay","gateway","runtime.cjs"),r=dirname(t),s=createRequire(t),i={exports:{}};compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(i.exports,s,i,t,r);let o=i.exports;if(!o.ClaudeCLIProvider)throw new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return o}catch(t){throw t instanceof b?t:new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){F.clear();}};var pt="1.5.0",te=class extends R{type="claude-cli";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";licenseKey;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.licenseKey=e;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await B.load(this.licenseKey,pt)).ClaudeCLIProvider,r=new t;return this.loadedProvider=r,r}catch(e){throw this.loadingPromise=null,this.health.status="unhealthy",this.health.errorCount++,e instanceof b?this.health.lastError=e.message:e instanceof Error&&(this.health.lastError=e.message),e}})(),this.loadingPromise)}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(ee(),Me));return e()}async execute(e,t){return (await this.ensureLoaded()).execute(e,t)}async streamRaw(e,t){return (await this.ensureLoaded()).streamRaw(e,t)}estimateCost(e){if(this.loadedProvider)return this.loadedProvider.estimateCost(e);let r=JSON.stringify(e.messages).length/4+5e3,s=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(s*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};var G=[{canonical:"claude-haiku-4-5",apiId:"claude-haiku-4-5-20251001",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[.8,4]},{canonical:"claude-sonnet-4-6",apiId:"claude-sonnet-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[3,15]},{canonical:"claude-opus-4-6",apiId:"claude-opus-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[15,75]},{canonical:"gpt-4.1",apiId:"gpt-4.1",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[2,8]},{canonical:"gpt-4.1-mini",apiId:"gpt-4.1-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.4,1.6]},{canonical:"gpt-4.1-nano",apiId:"gpt-4.1-nano",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.1,.4]},{canonical:"gpt-4o",apiId:"gpt-4o",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[2.5,10]},{canonical:"gpt-4o-mini",apiId:"gpt-4o-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[.15,.6]},{canonical:"o4-mini",apiId:"o4-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o3",apiId:"o3",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[.4,1.6]},{canonical:"o3-mini",apiId:"o3-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o1",apiId:"o1",provider:"openai-api",capabilities:{streaming:false,tools:false,multimodal:false,contextWindow:2e5},pricing:[15,60]},{canonical:"llama3.1",apiId:"llama3.1",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"mistral",apiId:"mistral",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}},{canonical:"mistral-nemo",apiId:"mistral-nemo",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"llava",apiId:"llava",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:true,contextWindow:32e3}},{canonical:"qwen2:0.5b",apiId:"qwen2:0.5b",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}}],K=Object.fromEntries(G.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));K["claude-sonnet-4"]="claude-sonnet-4-20250514";K["claude-opus-4"]="claude-opus-4-20250514";K["claude-haiku-4"]="claude-haiku-4-5-20251001";function fe(n){return K[n]||n}function mt(n){return G.find(e=>e.canonical===n)}function re(n){return G.find(e=>e.canonical===n)?.provider}function ht(n){return G.filter(e=>e.provider===n)}var yt="https://api.anthropic.com/v1/messages",gt="2023-06-01",be={"claude-sonnet-4-5-20250514":[3,15],"claude-sonnet-4-20250514":[3,15],"claude-haiku-4-5-20250414":[.8,4],"claude-opus-4-20250514":[15,75]};function De(n){if(be[n])return be[n];for(let[e,t]of Object.entries(be))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var V=class extends R{type="anthropic-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;dangerousDirectBrowserAccess;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||yt,this.dangerousDirectBrowserAccess=e.dangerousDirectBrowserAccess??false;}async probe(){try{let e=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{available:!0,authenticated:!1}:e.ok||e.status===429?{available:!0,authenticated:!0,rateLimitTier:e.headers.get("anthropic-ratelimit-tier")??void 0}:e.status===529?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let[l,d]=De(a.model||e.model),c=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*d)/1e6,p={},y=["request-id","x-request-id","anthropic-ratelimit-requests-limit","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-reset","anthropic-ratelimit-tokens-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-reset","anthropic-ratelimit-tier"];for(let m of y){let _=i.headers.get(m);_&&(p[m]=_);}return {content:a.content||[],model:a.model||e.model,usage:{input_tokens:a.usage?.input_tokens||0,output_tokens:a.usage?.output_tokens||0},stop_reason:a.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(c*1e6)/1e6,durationMs:o,fallbackChain:["anthropic-api:success"],headers:Object.keys(p).length>0?p:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder;return (async function*(){let o="",l=false;try{for(;;){let{done:d,value:c}=await i.read();if(d)break;o+=a.decode(c,{stream:!0});let p=o.split(`
10
+ -----END PUBLIC KEY-----`,pe={version:"1.0.0",cliVersion:"2.1.87",eventTypes:{system:"system",streamEvent:"stream_event",assistant:"assistant",result:"result"},fieldMappings:{sessionId:"session_id",model:"model",cliVersion:"claude_code_version",content:"content",usage:"usage",inputTokens:"input_tokens",outputTokens:"output_tokens",stopReason:"stop_reason",isError:"is_error",totalCostUsd:"total_cost_usd",durationMs:"duration_ms",error:"error",event:"event"},syntheticModel:"<synthetic>"},M=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(me,"RS256"),{payload:i}=await t(e,s),a=JSON.parse(new TextDecoder().decode(i));return this.verificationFailures=0,this.cachedManifest=a,this.currentSecurityState="SEC_NOMINAL",{manifest:a,securityState:"SEC_NOMINAL"}}catch{if(this.verificationFailures++,this.verificationFailures>=3){this.currentSecurityState="SEC_DEGRADED";let t=2e3+Math.random()*3e3;return await new Promise(r=>setTimeout(r,t)),console.warn("[inference-relay] Logic synchronization mismatch. Routing via local recovery."),{manifest:pe,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:pe,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},Ze=new M;function ke(){Ze.clearCache();}function et(){return pe}function tt(n,e){return e.split(".").reduce((t,r)=>{if(!(r==="__proto__"||r==="constructor"||r==="prototype"))return t&&t[r]},n)}var at=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function ge(n){return join(homedir(),".inference-relay","gateway",n)}function Te(n){return join(ge(n),"bundle.js")}function xe(n){return join(ge(n),"meta.json")}var b=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},F=new Map,B=class{static async load(e,t,r=at){let s=`${t}:${e.slice(-8)}`;if(F.has(s))return F.get(s);try{let p=await this.tryLoadFromDisk(t);if(p)return F.set(s,p),p}catch{}let{bytes:i,sha256:a,signature:o,libraryVersion:l}=await this.fetchFromAuthority(e,t,r);if(createHash("sha256").update(i).digest("hex")!==a)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(o,l,a);try{let p=ge(t);mkdirSync(p,{recursive:!0}),writeFileSync(Te(t),i),writeFileSync(xe(t),JSON.stringify({sha256:a,signature:o,libraryVersion:l}));}catch{}let c=this.loadIntoVm(i.toString("utf-8"));return F.set(s,c),c}static async loadFromDisk(e){if(!existsSync(e))throw new b(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Te(e),r=xe(e);if(!existsSync(t)||!existsSync(r))return null;let s=readFileSync(t),i=JSON.parse(readFileSync(r,"utf-8"));return createHash("sha256").update(s).digest("hex")!==i.sha256?null:(await this.verifySignature(i.signature,i.libraryVersion,i.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r){let s,i=[0,1e3,4e3],a;for(let c of i){c>0&&await new Promise(p=>setTimeout(p,c));try{let p=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(p.status===401||p.status===403)throw new b("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(p.status>=500&&p.status<600){a=new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");continue}if(!p.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${p.status})`,"GATEWAY_FETCH_FAILED");s=await p.json(),a=null;break}catch(p){if(p instanceof b&&p.code==="LICENSE_REJECTED")throw p;a=p;}}if(a||!s)throw a instanceof b?a:new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)","GATEWAY_FETCH_FAILED",a);let o;try{o=await fetch(s.bundleUrl);}catch(c){throw new b("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)","GATEWAY_FETCH_FAILED",c)}if(!o.ok)throw new b(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${o.status})`,"GATEWAY_FETCH_FAILED");let l=await o.arrayBuffer();return {bytes:Buffer.from(l),sha256:s.sha256,signature:s.signature,libraryVersion:s.libraryVersion,bundleVersion:s.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:i}=await import('jose'),a=await i(me,"RS256"),{payload:o}=await s(e,a),l=JSON.parse(new TextDecoder().decode(o));if(l.purpose!=="gateway-bundle")throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof b?s:new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=join(homedir(),".inference-relay","gateway","runtime.cjs"),r=dirname(t),s=createRequire(t),i={exports:{}};compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(i.exports,s,i,t,r);let o=i.exports;if(!o.ClaudeCLIProvider)throw new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return o}catch(t){throw t instanceof b?t:new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){F.clear();}};var pt="1.5.2",te=class extends R{type="claude-cli";supportsStreaming=true;supportsMultimodal=true;platformRequirement="desktop";licenseKey;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.licenseKey=e;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await B.load(this.licenseKey,pt)).ClaudeCLIProvider,r=new t;return this.loadedProvider=r,r}catch(e){throw this.loadingPromise=null,this.health.status="unhealthy",this.health.errorCount++,e instanceof b?this.health.lastError=e.message:e instanceof Error&&(this.health.lastError=e.message),e}})(),this.loadingPromise)}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(ee(),Me));return e()}async execute(e,t){return (await this.ensureLoaded()).execute(e,t)}async streamRaw(e,t){return (await this.ensureLoaded()).streamRaw(e,t)}estimateCost(e){if(this.loadedProvider)return this.loadedProvider.estimateCost(e);let r=JSON.stringify(e.messages).length/4+5e3,s=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(s*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};var G=[{canonical:"claude-haiku-4-5",apiId:"claude-haiku-4-5-20251001",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[.8,4]},{canonical:"claude-sonnet-4-6",apiId:"claude-sonnet-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[3,15]},{canonical:"claude-opus-4-6",apiId:"claude-opus-4-20250514",provider:"anthropic-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:2e5},pricing:[15,75]},{canonical:"gpt-4.1",apiId:"gpt-4.1",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[2,8]},{canonical:"gpt-4.1-mini",apiId:"gpt-4.1-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.4,1.6]},{canonical:"gpt-4.1-nano",apiId:"gpt-4.1-nano",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:1e6},pricing:[.1,.4]},{canonical:"gpt-4o",apiId:"gpt-4o",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[2.5,10]},{canonical:"gpt-4o-mini",apiId:"gpt-4o-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:true,contextWindow:128e3},pricing:[.15,.6]},{canonical:"o4-mini",apiId:"o4-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o3",apiId:"o3",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[.4,1.6]},{canonical:"o3-mini",apiId:"o3-mini",provider:"openai-api",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:2e5},pricing:[1.1,4.4]},{canonical:"o1",apiId:"o1",provider:"openai-api",capabilities:{streaming:false,tools:false,multimodal:false,contextWindow:2e5},pricing:[15,60]},{canonical:"llama3.1",apiId:"llama3.1",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"mistral",apiId:"mistral",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}},{canonical:"mistral-nemo",apiId:"mistral-nemo",provider:"ollama",capabilities:{streaming:true,tools:true,multimodal:false,contextWindow:128e3}},{canonical:"llava",apiId:"llava",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:true,contextWindow:32e3}},{canonical:"qwen2:0.5b",apiId:"qwen2:0.5b",provider:"ollama",capabilities:{streaming:true,tools:false,multimodal:false,contextWindow:32e3}}],K=Object.fromEntries(G.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));K["claude-sonnet-4"]="claude-sonnet-4-20250514";K["claude-opus-4"]="claude-opus-4-20250514";K["claude-haiku-4"]="claude-haiku-4-5-20251001";function fe(n){return K[n]||n}function mt(n){return G.find(e=>e.canonical===n)}function re(n){return G.find(e=>e.canonical===n)?.provider}function ht(n){return G.filter(e=>e.provider===n)}var yt="https://api.anthropic.com/v1/messages",gt="2023-06-01",be={"claude-sonnet-4-5-20250514":[3,15],"claude-sonnet-4-20250514":[3,15],"claude-haiku-4-5-20250414":[.8,4],"claude-opus-4-20250514":[15,75]};function De(n){if(be[n])return be[n];for(let[e,t]of Object.entries(be))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var V=class extends R{type="anthropic-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;dangerousDirectBrowserAccess;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||yt,this.dangerousDirectBrowserAccess=e.dangerousDirectBrowserAccess??false;}async probe(){try{let e=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{available:!0,authenticated:!1}:e.ok||e.status===429?{available:!0,authenticated:!0,rateLimitTier:e.headers.get("anthropic-ratelimit-tier")??void 0}:e.status===529?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let[l,d]=De(a.model||e.model),c=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*d)/1e6,p={},y=["request-id","x-request-id","anthropic-ratelimit-requests-limit","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-reset","anthropic-ratelimit-tokens-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-reset","anthropic-ratelimit-tier"];for(let m of y){let _=i.headers.get(m);_&&(p[m]=_);}return {content:a.content||[],model:a.model||e.model,usage:{input_tokens:a.usage?.input_tokens||0,output_tokens:a.usage?.output_tokens||0},stop_reason:a.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(c*1e6)/1e6,durationMs:o,fallbackChain:["anthropic-api:success"],headers:Object.keys(p).length>0?p:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder;return (async function*(){let o="",l=false;try{for(;;){let{done:d,value:c}=await i.read();if(d)break;o+=a.decode(c,{stream:!0});let p=o.split(`
11
11
  `);o=p.pop()||"";let y=null;for(let m of p)if(m.startsWith("event: "))y=m.slice(7).trim();else if(m.startsWith("data: ")){let _=m.slice(6);if(y&&_)try{let u=JSON.parse(_);u.type==="message_stop"&&(l=!0),yield u;}catch{console.warn("[inference-relay] Skipped malformed SSE data:",_.substring(0,100));}y=null;}else m.trim()===""&&(y=null);}l||(yield {type:"message_stop"});}finally{try{i.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[i,a]=De(e.model),o=(s*i+1e3*a)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(o*1e4)/1e4,model:e.model,provider:"anthropic-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){let e={"content-type":"application/json","x-api-key":this.apiKey,"anthropic-version":gt};return this.dangerousDirectBrowserAccess&&(e["anthropic-dangerous-direct-browser-access"]="true"),e}buildRequestBody(e,t){let r={model:fe(e.model),max_tokens:e.max_tokens,messages:e.messages};return t&&(r.stream=true),e.system&&(r.system=e.system),e.temperature!==void 0&&(r.temperature=e.temperature),e.tools&&e.tools.length>0&&(r.tools=e.tools),e.metadata&&(r.metadata=e.metadata),r}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let i=new Error(`ANTHROPIC_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw i.retryAfterMs=s,i}throw t===529?(this.health.status="degraded",this.health.lastError="API overloaded",this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_OVERLOADED: API is temporarily overloaded (529)")):(this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`ANTHROPIC_API_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};var ft="https://api.openai.com/v1/chat/completions",Oe=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],Ee={"gpt-4.1":[2,8],"gpt-4.1-mini":[.4,1.6],"gpt-4.1-nano":[.1,.4],"gpt-4o":[2.5,10],"gpt-4o-mini":[.15,.6],"o4-mini":[1.1,4.4],o3:[.4,1.6],"o3-mini":[1.1,4.4],o1:[15,60],"o1-mini":[3,12],"gpt-4-turbo":[10,30],"gpt-4":[30,60],"gpt-3.5-turbo":[.5,1.5]};function Ne(n){if(Ee[n])return Ee[n];for(let[e,t]of Object.entries(Ee))if(n.startsWith(e))return t;return [2.5,10]}function bt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Et(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n){let s=bt(r.content);if(r.role==="assistant"&&Array.isArray(r.content)){let i=r.content.filter(a=>a.type==="tool_use");if(i.length>0){t.push({role:"assistant",content:s||"",tool_calls:i.map(a=>({id:a.id||`call_${Math.random().toString(36).slice(2)}`,type:"function",function:{name:a.name,arguments:typeof a.input=="string"?a.input:JSON.stringify(a.input)}}))});continue}}t.push({role:r.role,content:s});}return t}function Ue(n){switch(n){case "stop":return "end_turn";case "length":return "max_tokens";case "tool_calls":case "function_call":return "tool_use";default:return "end_turn"}}var W=class extends R{type="openai-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||ft;}async probe(){try{let e=this.baseUrl.replace(/\/chat\/completions$/,"/models"),t=await fetch(e,{method:"GET",headers:this.buildHeaders()});return t.status===401?{available:!0,authenticated:!1}:t.ok||t.status===429?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let l=a.choices?.[0],d=[];if(l?.message?.content&&d.push({type:"text",text:l.message.content}),l?.message?.tool_calls)for(let h of l.message.tool_calls)d.push({type:"tool_use",id:h.id,name:h.function?.name,input:h.function?.arguments?JSON.parse(h.function.arguments):{}});let c=a.usage?.prompt_tokens||0,p=a.usage?.completion_tokens||0,[y,m]=Ne(a.model||e.model),_=(c*y+p*m)/1e6,u={},f=["x-request-id","x-ratelimit-limit-requests","x-ratelimit-remaining-requests","x-ratelimit-limit-tokens","x-ratelimit-remaining-tokens","x-ratelimit-reset-requests","x-ratelimit-reset-tokens"];for(let h of f){let g=i.headers.get(h);g&&(u[h]=g);}return {content:d,model:a.model||e.model,usage:{input_tokens:c,output_tokens:p},stop_reason:Ue(l?.finish_reason),provider:"openai-api",costUsd:Math.round(_*1e6)/1e6,durationMs:o,fallbackChain:["openai-api:success"],headers:Object.keys(u).length>0?u:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OPENAI_API_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder,o=e.model;return (async function*(){let l="",d=false,c=false,p,y;yield {type:"message_start",message:{model:o,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:m,value:_}=await i.read();if(m)break;l+=a.decode(_,{stream:!0});let u=l.split(`
12
12
  `);l=u.pop()||"";for(let f of u){if(!f.startsWith("data: "))continue;let h=f.slice(6).trim();if(h==="[DONE]"){yield {type:"message_delta",delta:{stop_reason:y||"end_turn"},usage:p||{}},yield {type:"message_stop"},c=!0;return}try{let g=JSON.parse(h);g.usage&&(p={input_tokens:g.usage.prompt_tokens||0,output_tokens:g.usage.completion_tokens||0});let C=g.choices?.[0];if(!C)continue;let E=C.delta;E?.content&&!d&&(d=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),E?.content&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:E.content}}),C.finish_reason&&(d&&(yield {type:"content_block_stop",index:0}),y=Ue(C.finish_reason));}catch{}}}c||(yield {type:"message_delta",delta:{stop_reason:y||"end_turn"},usage:p||{}},yield {type:"message_stop"});}finally{try{i.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[i,a]=Ne(e.model),o=(s*i+1e3*a)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(o*1e4)/1e4,model:e.model,provider:"openai-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}}buildRequestBody(e,t){let r=e.model.toLowerCase();if(!Oe.some(o=>r.startsWith(o)))throw new Error(`OPENAI_MODEL_TRANSLATION_REQUIRED: The OpenAI provider received the model name '${e.model}', which does not match any known OpenAI model prefix (${Oe.join(", ")}). The relay does NOT auto-translate model names across providers in v1.3.x. Either (a) pass an OpenAI model name like 'gpt-4o-mini' when routing to this provider, or (b) route non-OpenAI models through a provider that understands them (e.g. 'anthropic-api' for Claude models).`);let i=Et(e.messages,e.system),a={model:e.model,max_tokens:e.max_tokens,messages:i};return t&&(a.stream=true,a.stream_options={include_usage:true}),e.temperature!==void 0&&(a.temperature=e.temperature),e.tools&&e.tools.length>0&&(a.tools=e.tools),a}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("OPENAI_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let i=new Error(`OPENAI_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw i.retryAfterMs=s,i}throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`OPENAI_API_ERROR: Request failed with status ${t}`)}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};var _t="http://localhost:11434";function vt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Ct(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:vt(r.content)});return t}var Y=class extends R{type="ollama";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.baseUrl=e?.baseUrl?.replace(/\/$/,"")||_t;}async probe(){try{return (await fetch(`${this.baseUrl}/api/tags`,{method:"GET"})).ok?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),i=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),signal:t?.signal});if(!i.ok)throw this.handleErrorResponse(i),new Error("unreachable");let a=await i.json(),o=Date.now()-r;this.recordSuccess();let l=[];a.message?.content&&l.push({type:"text",text:a.message.content});let d=a.prompt_eval_count||0,c=a.eval_count||0;return {content:l,model:a.model||e.model,usage:{input_tokens:d,output_tokens:c},stop_reason:(a.done,"end_turn"),provider:"ollama",costUsd:0,durationMs:o,fallbackChain:["ollama:success"]}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OLLAMA_ERROR: Response body is null \u2014 streaming unavailable");let i=s.body.getReader(),a=new TextDecoder,o=e.model;return (async function*(){let l="",d=false,c=false;yield {type:"message_start",message:{model:o,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:p,value:y}=await i.read();if(p)break;l+=a.decode(y,{stream:!0});let m=l.split(`
13
13
  `);l=m.pop()||"";for(let _ of m){let u=_.trim();if(u)try{let f=JSON.parse(u);if(f.message?.content&&(d||(d=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:f.message.content}}),f.done){d&&(yield {type:"content_block_stop",index:0}),yield {type:"message_delta",delta:{stop_reason:"end_turn"},usage:{input_tokens:f.prompt_eval_count||0,output_tokens:f.eval_count||0}},yield {type:"message_stop"},c=!0;return}}catch{}}}c||(yield {type:"message_stop"});}finally{try{i.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0;return {estimatedInputTokens:t+r,estimatedCost:0,model:e.model,provider:"ollama"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildRequestBody(e,t){if(e.tools&&e.tools.length>0)throw new Error(`OLLAMA_TOOLS_NOT_SUPPORTED: The Ollama provider received ${e.tools.length} tool definition(s) in params.tools, but this provider does not implement function calling in v1.3.x. For tool-use workflows route to 'anthropic-api' or 'openai-api' instead. Tracking issue: 1.4.0 ships an Ollama tool-use shim for models that support native function calling (llama3.1, mistral-nemo, etc.).`);let r=Ct(e.messages,e.system),s={model:e.model,messages:r,stream:t};return e.temperature!==void 0&&(s.options={temperature:e.temperature}),s}handleErrorResponse(e){let t=e.status;throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),t===404?(this.health.status="unhealthy",this.health.lastError="Model not found",new Error("OLLAMA_MODEL_NOT_FOUND: Requested model is not available locally (404)")):(this.health.status="unhealthy",this.health.lastError=`Request failed with status ${t}`,new Error(`OLLAMA_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};var $=class extends EventEmitter{constructor(){super(),this.setMaxListeners(50);}emitTyped(e){return this.emit(e.kind,e)}onTyped(e,t){return this.on(e,t)}offTyped(e,t){return this.off(e,t)}};var We=200;function ne(n,e){if(e instanceof b)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,We)||"unknown"}`}var Fe=new Set(["anthropic-api","openai-api","ollama"]),q=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}};function Be(n){return n.messages.some(e=>typeof e.content=="string"?false:Array.isArray(e.content)&&e.content.some(t=>t.type==="image"||t.type==="image_url"))}function _e(n){if(!(n instanceof Error))return "unknown";let e=n.code;if(typeof e=="string"){if(e==="LICENSE_REJECTED")return "auth_failed";if(e==="GATEWAY_FETCH_FAILED"||e==="GATEWAY_VERIFICATION_FAILED"||e==="GATEWAY_LOAD_FAILED")return "gateway_unavailable"}let t=n.message.toLowerCase(),r=n.name.toLowerCase();return t.startsWith("openai_model_translation_required:")||t.startsWith("ollama_tools_not_supported:")||t.startsWith("multimodal_cli_too_old:")?"provider_incompatible":t.includes("rate limit")||t.includes("429")||r.includes("ratelimit")?"rate_limited":t.includes("auth")||t.includes("401")||t.includes("403")||t.includes("unauthorized")||t.includes("forbidden")?"auth_failed":t.includes("timeout")||t.includes("timed out")||t.includes("aborted")||r==="aborterror"||r==="timeouterror"?"timeout":"unknown"}function He(n){return [...n].sort((e,t)=>e.priority-t.priority)}var j=class n{healthMap=new Map;engineEvents=new $;static UNHEALTHY_TTL_MS=300*1e3;getHealthStatus(e){let t=this.healthMap.get(e);return t?t.status==="unhealthy"&&Date.now()-t.updatedAt>=n.UNHEALTHY_TTL_MS?(this.healthMap.delete(e),"healthy"):t.status:"healthy"}markUnhealthy(e,t){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now()});}markDegraded(e,t){this.healthMap.set(e,{status:"degraded",lastError:t,updatedAt:Date.now()});}markHealthy(e){this.healthMap.set(e,{status:"healthy",updatedAt:Date.now()});}resetHealth(){this.healthMap.clear();}async execute(e,t,r){let s=He(t),i=[],a=Be(e),o=randomUUID(),l=Date.now();for(let d of s){let c=d.type;if(this.getHealthStatus(c)==="unhealthy"){i.push(`${c}:skipped:unhealthy`);continue}if(a&&!d.supportsMultimodal){i.push(`${c}:skipped:no_multimodal`);continue}let y=re(e.model);if(y&&y!==c&&Fe.has(c)){i.push(`${c}:skipped:wrong_provider`);continue}try{let m=await d.execute(e,{signal:r?.signal});return this.markHealthy(c),i.push(`${c}:success`),this.emitEngineEvent({kind:"stream_complete",callId:o,id:randomUUID(),ts:Date.now(),stitched:!1,segments:[{provider:c,inputTokens:m.usage.input_tokens,outputTokens:m.usage.output_tokens,costUsd:m.costUsd,userCostUsd:m.userCostUsd??0}],provider:c,model:m.model,inputTokens:m.usage.input_tokens,outputTokens:m.usage.output_tokens,costUsd:m.costUsd,userCostUsd:m.userCostUsd,durationMs:m.durationMs??Date.now()-l,stopReason:m.stop_reason,fallbackChain:i,rateLimitHit:!1,securityState:r?.licenseState}),{...m,fallbackChain:i}}catch(m){if(m?.name==="AbortError"||r?.signal?.aborted)throw m;switch(_e(m)){case "rate_limited":d.reportRateLimit({provider:c,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(c,"rate_limited"),i.push(`${c}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(c,"auth_failed"),i.push(`${c}:failed:auth_failed`);break;case "timeout":i.push(`${c}:failed:timeout`);break;case "provider_incompatible":i.push(`${c}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(c,"gateway_unavailable"),i.push(ne(c,m));break;default:i.push(ne(c,m));break}}}throw new q(i)}async stream(e,t,r){let s=randomUUID(),i=He(t),a=Be(e),o=Date.now(),l=[],d=null,c=null;for(let h of i){let g=h.type;if(this.getHealthStatus(g)==="unhealthy"){l.push(`${g}:skipped:unhealthy`);continue}if(a&&!h.supportsMultimodal){l.push(`${g}:skipped:no_multimodal`);continue}if(!h.supportsStreaming){l.push(`${g}:skipped:no_streaming`);continue}let C=re(e.model);if(C&&C!==g&&Fe.has(g)){l.push(`${g}:skipped:wrong_provider`);continue}try{c=await h.streamRaw(e,{signal:r?.signal}),d=h,l.push(`${g}:success`);break}catch(E){if(E?.name==="AbortError"||r?.signal?.aborted)throw E;switch(_e(E)){case "rate_limited":h.reportRateLimit({provider:g,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(g,"rate_limited"),l.push(`${g}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(g,"auth_failed"),l.push(`${g}:failed:auth_failed`);break;case "timeout":l.push(`${g}:failed:timeout`);break;case "provider_incompatible":l.push(`${g}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(g,"gateway_unavailable"),l.push(ne(g,E));break;default:l.push(ne(g,E));break}}}if(!d||!c)throw new q(l);let y=this,m=r?.maxMidStreamFailovers??2,_=new Set([d]);async function*u(){let h=d,g=c[Symbol.asyncIterator](),C={role:"assistant",content:[]},E={segments:[]},I=Ge(h.type);E.segments.push(I);let Re=0,z=null,X=false,de=m,O="",N="";for(y.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type});;)try{for(;;){let A=await g.next();if(A.done)break;let T=A.value,k=Pt(T,Re,C,X,z);if(k.action==="suppress"){"coalesceMode"in k&&(z=k.coalesceMode),k.clearedJustFailedOver&&(X=!1);continue}k.coalesceModeCleared&&(z=null),k.clearedJustFailedOver&&(X=!1);let v=k.event;if(St(C,v),v.type==="message_start"){if(E.segments.length>1)continue;O=v.message?.model||O,v.message?.usage?.input_tokens!=null&&(I.inputTokens=v.message.usage.input_tokens);}if(v.type==="message_delta"&&(v.delta?.stop_reason&&(N=v.delta.stop_reason),v.usage)){Rt(I,h.type,v.usage),yield {...v,usage:void 0};continue}if(v.type==="message_stop")break;yield v;}if(C.content.length===0&&I.outputTokens===0)throw new Error("stream ended without producing any content");y.markHealthy(h.type),y.emitEngineEvent({kind:"segment_complete",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type,usage:{...I}});let S=Ke(E.segments);yield {type:"message_delta",delta:{stop_reason:N||"end_turn"},usage:S},yield {type:"message_stop"},y.emitEngineEvent({kind:"stream_complete",callId:s,id:randomUUID(),ts:Date.now(),stitched:E.segments.length>1,segments:E.segments.map(A=>({...A})),provider:E.segments.map(A=>A.provider).join("+"),model:O,inputTokens:S.input_tokens,outputTokens:S.output_tokens,costUsd:E.segments.reduce((A,T)=>A+T.costUsd,0),userCostUsd:E.segments.reduce((A,T)=>A+T.userCostUsd,0),durationMs:Date.now()-o,stopReason:N||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(S){if(S?.name==="AbortError"||r?.signal?.aborted)throw S;let A=_e(S);try{await g.return?.();}catch{}if(y.markUnhealthy(h.type,String(S)),y.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:s,id:randomUUID(),ts:Date.now(),from:h.type,bytesBuffered:Ve(C),errorClass:A,retriesLeft:de}),l.push(`${h.type}:partial(${Ve(C)}b)`),de<=0)throw y.emitTerminalExhaustion(s,E,O,N,l,o,r?.licenseState),S;let T=kt(C.content),k=[...e.messages,{role:"assistant",content:T}],v=null,Q=null,Se=h;for(;;){let w=y.nextHealthyProvider(i,Se,a,_);if(!w)break;Se=w,_.add(w);let je={...e,messages:k,...w.type!=="anthropic-api"&&w.type!=="claude-cli"?{system:wt(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{Q=await w.streamRaw(je,{signal:r?.signal}),v=w;break}catch(Pe){y.markUnhealthy(w.type,String(Pe)),l.push(`${w.type}:failed_connect:${String(Pe).slice(0,We)}`);}}if(!v||!Q)throw y.emitTerminalExhaustion(s,E,O,N,l,o,r?.licenseState),S;l.push(`${v.type}:stitched`),y.emitEngineEvent({kind:"mid_stream_failover_success",callId:s,id:randomUUID(),ts:Date.now(),from:h.type,to:v.type}),Re=It(C)+1,de--,h=v,g=Q[Symbol.asyncIterator](),X=true,z=null,I=Ge(h.type),E.segments.push(I),y.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type});}}let f=u();return r?.licenseState==="SEC_DEGRADED"&&(f=Tt(f)),L(f)}nextHealthyProvider(e,t,r,s){let i=e.indexOf(t);if(i===-1)return null;for(let a=i+1;a<e.length;a++){let o=e[a];if(!s.has(o)&&!(r&&!o.supportsMultimodal)&&o.supportsStreaming)return o}return null}emitEngineEvent(e){this.engineEvents.emitTyped(e);}emitTerminalExhaustion(e,t,r,s,i,a,o){let l=Ke(t.segments);this.emitEngineEvent({kind:"stream_complete",callId:e,id:randomUUID(),ts:Date.now(),stitched:t.segments.length>1,segments:t.segments.map(d=>({...d})),provider:t.segments.map(d=>d.provider).join("+"),model:r,inputTokens:l.input_tokens,outputTokens:l.output_tokens,costUsd:t.segments.reduce((d,c)=>d+c.costUsd,0),userCostUsd:t.segments.reduce((d,c)=>d+c.userCostUsd,0),durationMs:Date.now()-a,stopReason:s||"error",fallbackChain:i,rateLimitHit:false,securityState:o});}};function Ge(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function Rt(n,e,t){typeof t.input_tokens=="number"&&(n.inputTokens=t.input_tokens),typeof t.output_tokens=="number"&&(e==="anthropic-api"||e==="claude-cli"?n.outputTokens+=t.output_tokens:n.outputTokens=t.output_tokens);}function Ke(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function St(n,e){if(e.type==="content_block_start"){let t=e.content_block;t?.type==="text"?n.content.push({type:"text",text:t.text||"",open:true}):t?.type==="tool_use"&&n.content.push({type:"tool_use",id:t.id,name:t.name,input:{},_partialJson:"",open:true});}else if(e.type==="content_block_delta"){let t=n.content[n.content.length-1];if(!t)return;t.type==="text"&&e.delta?.type==="text_delta"?t.text+=e.delta.text||"":t.type==="tool_use"&&e.delta?.type==="input_json_delta"&&(t._partialJson=(t._partialJson||"")+(e.delta.partial_json||""));}else if(e.type==="content_block_stop"){for(let t=n.content.length-1;t>=0;t--)if(n.content[t].open){if(n.content[t].open=false,n.content[t].type==="tool_use"){let r=n.content[t];try{r.input=JSON.parse(r._partialJson||"{}");}catch{}delete r._partialJson;}break}}}function Pt(n,e,t,r,s){if(s&&n.type==="content_block_delta"&&n.index===s.fromIndex)return {action:"yield",event:{...n,index:s.toIndex}};if(s&&n.type==="content_block_stop"&&n.index===s.fromIndex)return {action:"suppress",coalesceMode:null,coalesceModeCleared:true};if(r&&n.type==="content_block_start"&&n.content_block?.type==="text"){let a=t.content[t.content.length-1];if(a?.type==="text"&&a.open===true)return {action:"suppress",coalesceMode:{fromIndex:n.index+e,toIndex:t.content.length-1},clearedJustFailedOver:true}}let i=r&&n.type==="content_block_start";return typeof n.index=="number"&&e>0?{action:"yield",event:{...n,index:n.index+e},clearedJustFailedOver:i}:{action:"yield",event:n,clearedJustFailedOver:i}}function kt(n){let e=[];for(let t of n)t.type==="text"?t.text&&e.push({type:"text",text:t.text}):t.type==="tool_use"&&!t.open&&t.input&&Object.keys(t.input).length>0&&e.push({type:"tool_use",id:t.id,name:t.name,input:t.input});return e}function wt(n,e){return n?`${n}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inference-relay",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "private": false,
5
5
  "description": "Route AI inference to the user's existing subscription",
6
6
  "type": "module",
@@ -59,7 +59,7 @@
59
59
  "lint": "eslint src/",
60
60
  "typecheck": "tsc --noEmit",
61
61
  "clean": "rm -rf dist",
62
- "prepublishOnly": "echo '[publish] 1.5.0 release — guard intentionally relaxed for this publish' && exit 0"
62
+ "prepublishOnly": "echo '[publish] 1.5.2 release — guard intentionally relaxed for this publish' && exit 0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@types/node": "^22.0.0",