inference-relay 1.6.1 → 1.6.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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import {execSync}from'child_process';import {mkdirSync,writeFileSync,existsSync,readFileSync}from'fs';import {join,dirname}from'path';import {homedir}from'os';import {createHash,randomUUID}from'crypto';import {compileFunction}from'vm';import {createRequire}from'module';import {EventEmitter}from'events';/*! inference-relay (c) 2026 L2B II LLC. Patent pending. Proprietary. See LICENSE. */
2
- var Je=Object.defineProperty;var ze=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+n+'" is not supported')});var Xe=(n,e)=>()=>(n&&(e=n(n=0)),e);var Qe=(n,e)=>{for(var t in e)Je(n,t,{get:e[t],enumerable:true});};var Me={};Qe(Me,{detectCLI:()=>H});function dt(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(i=>i.toLowerCase()):[""];for(let i of e.split(r))if(i)for(let a of s){let o=join(i,n+a);if(existsSync(o))return o}return null}async function H(){if(!dt("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&&!ut.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 ut,ee=Xe(()=>{ut=["2.1.87"];});var U=class n extends Error{code="RELAY_CAP_EXCEEDED";tier;baseCap;topUps;effectiveCap;usedThisCycle;resolutionUrl;constructor(e){let t=e.resolutionUrl??"https://inference-relay.com/dashboard/billing?topup=1";super(`Cap reached (${e.usedThisCycle} / ${e.effectiveCap??"\u221E"} calls this cycle). Buy a top-up or upgrade at ${t}`),this.name="RelayCapExceededError",this.tier=e.tier,this.baseCap=e.baseCap,this.topUps=e.topUps,this.effectiveCap=e.effectiveCap,this.usedThisCycle=e.usedThisCycle,this.resolutionUrl=t,Object.setPrototypeOf(this,n.prototype);}};function L(n,e){let t=new Map,r=null,s=null,i=new Promise((u,f)=>{r=u,s=f;});i.catch(()=>{});let a=[],o=null,l="",d="";function c(u,...f){let h=t.get(u);h&&h.forEach(g=>g(...f));}async function*p(){try{for await(let u of n)if(yield u,u.type==="content_block_start")a[u.index]=u.content_block;else if(u.type==="content_block_delta"){let f=a[u.index];f&&u.delta?.type==="text_delta"&&(f.text=(f.text||"")+u.delta.text,c("text",u.delta.text));}else if(u.type==="message_start")l=u.message?.model||"",o=u.message?.usage;else if(u.type==="message_delta")d=u.delta?.stop_reason||"",u.usage&&(o={...o,...u.usage});else if(u.type==="message_stop"){let f={role:"assistant",model:l,content:a.filter(Boolean),usage:o,stop_reason:d};c("message",f),r&&(r(f),r=null),e&&e(f);}if(r){let u={role:"assistant",model:l,content:a.filter(Boolean),usage:o,stop_reason:d||"end_turn"};c("message",u),r(u),r=null,e&&e(u);}}catch(u){throw c("error",u),s&&(s(u),s=null),u}}let y=p(),m=false,E={[Symbol.asyncIterator](){if(m)throw new Error("[inference-relay] RelayStream can only be iterated once");return m=true,y},on(u,f){return t.has(u)||t.set(u,[]),t.get(u).push(f),E},finalMessage(){let u,f=new Promise((h,g)=>{u=setTimeout(()=>g(new Error("[inference-relay] finalMessage() timed out \u2014 no message_stop received after 5 minutes")),3e5);});return Promise.race([i,f]).finally(()=>clearTimeout(u))}};return E}var R=class{priority=100;async streamRaw(e,t){throw new Error(`[inference-relay] Provider '${this.type}' does not implement streamRaw(). Override either stream() or streamRaw() in the provider class.`)}async stream(e,t){return L(await this.streamRaw(e,t))}};var me=`-----BEGIN PUBLIC KEY-----
2
+ var Xe=Object.defineProperty;var Qe=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+n+'" is not supported')});var Ze=(n,e)=>()=>(n&&(e=n(n=0)),e);var et=(n,e)=>{for(var t in e)Xe(n,t,{get:e[t],enumerable:true});};var Oe={};et(Oe,{detectCLI:()=>K});function yt(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(i=>i.toLowerCase()):[""];for(let i of e.split(r))if(i)for(let a of s){let o=join(i,n+a);if(existsSync(o))return o}return null}async function K(){if(!yt("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&&!ht.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 ht,re=Ze(()=>{ht=["2.1.87"];});var B=class n extends Error{code="RELAY_CAP_EXCEEDED";tier;baseCap;topUps;effectiveCap;usedThisCycle;resolutionUrl;constructor(e){let t=e.resolutionUrl??"https://inference-relay.com/dashboard/billing?topup=1";super(`Cap reached (${e.usedThisCycle} / ${e.effectiveCap??"\u221E"} calls this cycle). Buy a top-up or upgrade at ${t}`),this.name="RelayCapExceededError",this.tier=e.tier,this.baseCap=e.baseCap,this.topUps=e.topUps,this.effectiveCap=e.effectiveCap,this.usedThisCycle=e.usedThisCycle,this.resolutionUrl=t,Object.setPrototypeOf(this,n.prototype);}};function D(n,e){let t=new Map,r=null,s=null,i=new Promise((d,f)=>{r=d,s=f;});i.catch(()=>{});let a=[],o=null,l="",p="";function u(d,...f){let h=t.get(d);h&&h.forEach(y=>y(...f));}async function*g(){try{for await(let d of n)if(yield d,d.type==="content_block_start")a[d.index]=d.content_block;else if(d.type==="content_block_delta"){let f=a[d.index];f&&d.delta?.type==="text_delta"&&(f.text=(f.text||"")+d.delta.text,u("text",d.delta.text));}else if(d.type==="message_start")l=d.message?.model||"",o=d.message?.usage;else if(d.type==="message_delta")p=d.delta?.stop_reason||"",d.usage&&(o={...o,...d.usage});else if(d.type==="message_stop"){let f={role:"assistant",model:l,content:a.filter(Boolean),usage:o,stop_reason:p};u("message",f),r&&(r(f),r=null),e&&e(f);}if(r){let d={role:"assistant",model:l,content:a.filter(Boolean),usage:o,stop_reason:p||"end_turn"};u("message",d),r(d),r=null,e&&e(d);}}catch(d){throw u("error",d),s&&(s(d),s=null),d}}let m=g(),c=false,E={[Symbol.asyncIterator](){if(c)throw new Error("[inference-relay] RelayStream can only be iterated once");return c=true,m},on(d,f){return t.has(d)||t.set(d,[]),t.get(d).push(f),E},finalMessage(){let d,f=new Promise((h,y)=>{d=setTimeout(()=>y(new Error("[inference-relay] finalMessage() timed out \u2014 no message_stop received after 5 minutes")),3e5);});return Promise.race([i,f]).finally(()=>clearTimeout(d))}};return E}var A=class{priority=100;async streamRaw(e,t){throw new Error(`[inference-relay] Provider '${this.type}' does not implement streamRaw(). Override either stream() or streamRaw() in the provider class.`)}async stream(e,t){return D(await this.streamRaw(e,t))}};var ye=`-----BEGIN PUBLIC KEY-----
3
3
  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzk88Bt9LZSmuSd8ulKqy
4
4
  EGNiPB+r8u1ZinBvMM4qX8dp4kzJEC/47L1RYrrxCphD05HToREjljbj+upH6rZH
5
5
  t6D/5funYPi2TO1IOSC6BRVRwMqqTmJGVJcLcG/WF3gTE+2UQ3q5EppWJCEKcz6x
@@ -7,12 +7,12 @@ 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.6.1",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 E=i.headers.get(m);E&&(p[m]=E);}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
- `);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 E=m.slice(6);if(y&&E)try{let u=JSON.parse(E);u.type==="message_stop"&&(l=!0),yield u;}catch{console.warn("[inference-relay] Skipped malformed SSE data:",E.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:"],_e={"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(_e[n])return _e[n];for(let[e,t]of Object.entries(_e))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 _t(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),E=(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(E*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:E}=await i.read();if(m)break;l+=a.decode(E,{stream:!0});let u=l.split(`
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 _=C.delta;_?.content&&!d&&(d=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),_?.content&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:_.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=_t(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 Et="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(/\/$/,"")||Et;}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
- `);l=m.pop()||"";for(let E of m){let u=E.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 Ee(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:")||t.startsWith("stream_json_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(Ee(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(_){if(_?.name==="AbortError"||r?.signal?.aborted)throw _;switch(Ee(_)){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,_));break;default:l.push(ne(g,_));break}}}if(!d||!c)throw new q(l);let y=this,m=r?.maxMidStreamFailovers??2,E=new Set([d]);async function*u(){let h=d,g=c[Symbol.asyncIterator](),C={role:"assistant",content:[]},_={segments:[]},I=Ge(h.type);_.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(_.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(_.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:_.segments.length>1,segments:_.segments.map(A=>({...A})),provider:_.segments.map(A=>A.provider).join("+"),model:O,inputTokens:S.input_tokens,outputTokens:S.output_tokens,costUsd:_.segments.reduce((A,T)=>A+T.costUsd,0),userCostUsd:_.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=Ee(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,_,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,E);if(!w)break;Se=w,E.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,_,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),_.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}
10
+ -----END PUBLIC KEY-----`,he={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>"},O=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(ye,"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:he,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:he,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},tt=new O;function Ie(){tt.clearCache();}function rt(){return he}function nt(n,e){return e.split(".").reduce((t,r)=>{if(!(r==="__proto__"||r==="constructor"||r==="prototype"))return t&&t[r]},n)}function S(n,...e){process.env.IR_DEBUG==="1"&&console.error(`[ir-debug:${n}]`,...e);}var lt=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function be(n){return join(homedir(),".inference-relay","gateway",n)}function Le(n){return join(be(n),"bundle.js")}function Me(n){return join(be(n),"meta.json")}var _=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},x=class extends _{constructor(e,t){super(e,"GATEWAY_FETCH_FAILED",t);}},H=new Map,ct=[0,1e3,4e3];function ut(n){let e=(r,s)=>{if(!Array.isArray(r)||r.length===0)return null;let i=[];for(let a of r){let o=typeof a=="string"?Number(a):a;if(typeof o!="number"||!Number.isFinite(o)||o<0)return S("loader.retry-config-invalid",{source:s,badValue:a}),null;i.push(o);}return i};if(n!==void 0){let r=e(n,"option");if(r)return r}let t=process.env.IR_GATEWAY_RETRY_DELAYS_MS;if(t){let r=e(t.split(",").map(s=>s.trim()),"env");if(r)return r}return ct}var G=class{static async load(e,t,r=lt,s){let i=`${t}:${e.slice(-8)}`;if(H.has(i))return H.get(i);try{let m=await this.tryLoadFromDisk(t);if(m)return S("loader.cache-hit",{libraryVersion:t}),H.set(i,m),m}catch{}S("loader.cache-miss",{libraryVersion:t});let{bytes:a,sha256:o,signature:l,libraryVersion:p}=await this.fetchFromAuthority(e,t,r,s);if(createHash("sha256").update(a).digest("hex")!==o)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,p,o);try{let m=be(t);mkdirSync(m,{recursive:!0}),writeFileSync(Le(t),a),writeFileSync(Me(t),JSON.stringify({sha256:o,signature:l,libraryVersion:p}));}catch{}let g=this.loadIntoVm(a.toString("utf-8"));return H.set(i,g),g}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=Le(e),r=Me(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,s){let i,a=ut(s?.retryDelaysMs),o;for(let g=0;g<a.length;g++){let m=a[g];m>0&&await new Promise(c=>setTimeout(c,m)),S("loader.fetch",{url:`${r}/v1/gateway/fetch`,libraryVersion:t,attempt:g+1,delayMs:m});try{let c=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(S("loader.fetch-result",{status:c.status,attempt:g+1}),c.status===401||c.status===403)throw new _("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(c.status>=500&&c.status<600){o=new x(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${c.status})`);continue}if(!c.ok)throw new x(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${c.status})`);i=await c.json(),o=null;break}catch(c){if(c instanceof _&&c.code==="LICENSE_REJECTED")throw c;o=c;}}if(o||!i)throw o instanceof _?o:new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)",o);let l;try{l=await fetch(i.bundleUrl);}catch(g){throw new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)",g)}if(!l.ok)throw new x(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${l.status})`);let p=await l.arrayBuffer();return {bytes:Buffer.from(p),sha256:i.sha256,signature:i.signature,libraryVersion:i.libraryVersion,bundleVersion:i.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:i}=await import('jose'),a=await i(ye,"RS256"),{payload:o}=await s(e,a),l=JSON.parse(new TextDecoder().decode(o));if(l.purpose!=="gateway-bundle")throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new _("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.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),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 _("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return o}catch(t){throw t instanceof _?t:new _("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){H.clear();}};var gt="1.6.2",ne=class extends A{type="claude-cli";supportsStreaming=true;supportsMultimodal=true;platformRequirement="desktop";licenseKey;loadOptions;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e,t){super(),this.licenseKey=e,this.loadOptions=t;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await G.load(this.licenseKey,gt,void 0,this.loadOptions)).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 warmup(){await this.ensureLoaded();}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(re(),Oe));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 V=[{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}}],W=Object.fromEntries(V.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));W["claude-sonnet-4"]="claude-sonnet-4-20250514";W["claude-opus-4"]="claude-opus-4-20250514";W["claude-haiku-4"]="claude-haiku-4-5-20251001";function _e(n){return W[n]||n}function ft(n){return V.find(e=>e.canonical===n)}function se(n){return V.find(e=>e.canonical===n)?.provider}function bt(n){return V.filter(e=>e.provider===n)}var _t="https://api.anthropic.com/v1/messages",Et="2023-06-01",Ee={"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 Ne(n){if(Ee[n])return Ee[n];for(let[e,t]of Object.entries(Ee))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var $=class extends A{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(/\/$/,"")||_t,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,p]=Ne(a.model||e.model),u=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*p)/1e6,g={},m=["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 c of m){let E=i.headers.get(c);E&&(g[c]=E);}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(u*1e6)/1e6,durationMs:o,fallbackChain:["anthropic-api:success"],headers:Object.keys(g).length>0?g: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:p,value:u}=await i.read();if(p)break;o+=a.decode(u,{stream:!0});let g=o.split(`
11
+ `);o=g.pop()||"";let m=null;for(let c of g)if(c.startsWith("event: "))m=c.slice(7).trim();else if(c.startsWith("data: ")){let E=c.slice(6);if(m&&E)try{let d=JSON.parse(E);d.type==="message_stop"&&(l=!0),yield d;}catch{console.warn("[inference-relay] Skipped malformed SSE data:",E.substring(0,100));}m=null;}else c.trim()===""&&(m=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]=Ne(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":Et};return this.dangerousDirectBrowserAccess&&(e["anthropic-dangerous-direct-browser-access"]="true"),e}buildRequestBody(e,t){let r={model:_e(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 vt="https://api.openai.com/v1/chat/completions",Ue=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],ve={"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 Fe(n){if(ve[n])return ve[n];for(let[e,t]of Object.entries(ve))if(n.startsWith(e))return t;return [2.5,10]}function Ct(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Rt(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n){let s=Ct(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 Be(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 Y=class extends A{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(/\/$/,"")||vt;}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],p=[];if(l?.message?.content&&p.push({type:"text",text:l.message.content}),l?.message?.tool_calls)for(let h of l.message.tool_calls)p.push({type:"tool_use",id:h.id,name:h.function?.name,input:h.function?.arguments?JSON.parse(h.function.arguments):{}});let u=a.usage?.prompt_tokens||0,g=a.usage?.completion_tokens||0,[m,c]=Fe(a.model||e.model),E=(u*m+g*c)/1e6,d={},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 y=i.headers.get(h);y&&(d[h]=y);}return {content:p,model:a.model||e.model,usage:{input_tokens:u,output_tokens:g},stop_reason:Be(l?.finish_reason),provider:"openai-api",costUsd:Math.round(E*1e6)/1e6,durationMs:o,fallbackChain:["openai-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("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="",p=false,u=false,g,m;yield {type:"message_start",message:{model:o,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:c,value:E}=await i.read();if(c)break;l+=a.decode(E,{stream:!0});let d=l.split(`
12
+ `);l=d.pop()||"";for(let f of d){if(!f.startsWith("data: "))continue;let h=f.slice(6).trim();if(h==="[DONE]"){yield {type:"message_delta",delta:{stop_reason:m||"end_turn"},usage:g||{}},yield {type:"message_stop"},u=!0;return}try{let y=JSON.parse(h);y.usage&&(g={input_tokens:y.usage.prompt_tokens||0,output_tokens:y.usage.completion_tokens||0});let C=y.choices?.[0];if(!C)continue;let b=C.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}}),C.finish_reason&&(p&&(yield {type:"content_block_stop",index:0}),m=Be(C.finish_reason));}catch{}}}u||(yield {type:"message_delta",delta:{stop_reason:m||"end_turn"},usage:g||{}},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]=Fe(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(!Ue.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 (${Ue.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=Rt(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 At="http://localhost:11434";function St(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function wt(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:St(r.content)});return t}var q=class extends A{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(/\/$/,"")||At;}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 p=a.prompt_eval_count||0,u=a.eval_count||0;return {content:l,model:a.model||e.model,usage:{input_tokens:p,output_tokens:u},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="",p=false,u=false;yield {type:"message_start",message:{model:o,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:g,value:m}=await i.read();if(g)break;l+=a.decode(m,{stream:!0});let c=l.split(`
13
+ `);l=c.pop()||"";for(let E of c){let d=E.trim();if(d)try{let f=JSON.parse(d);if(f.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:f.message.content}}),f.done){p&&(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"},u=!0;return}}catch{}}}u||(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=wt(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 j=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 Ye=200;function ie(n,e){if(e instanceof _)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,Ye)||"unknown"}`}var He=new Set(["anthropic-api","openai-api","ollama"]),J=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 Ge(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 Ce(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:")||t.startsWith("stream_json_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 Ke(n){return [...n].sort((e,t)=>e.priority-t.priority)}var z=class n{healthMap=new Map;engineEvents=new j;static UNHEALTHY_TTL_MS=300*1e3;getHealthStatus(e){let t=this.healthMap.get(e);if(!t)return "healthy";if(t.status==="unhealthy"&&Date.now()-t.updatedAt>=n.UNHEALTHY_TTL_MS){let r=Date.now()-t.updatedAt;return this.healthMap.delete(e),S("engine.recovered",{providerType:e,ageMs:r}),"healthy"}return t.status}markUnhealthy(e,t){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now()}),S("engine.unhealthy",{providerType:e,reason:t});}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=Ke(t),i=[],a=Ge(e),o=randomUUID(),l=Date.now();for(let p of s){let u=p.type;if(this.getHealthStatus(u)==="unhealthy"){i.push(`${u}:skipped:unhealthy`);continue}if(a&&!p.supportsMultimodal){i.push(`${u}:skipped:no_multimodal`);continue}let m=se(e.model);if(m&&m!==u&&He.has(u)){i.push(`${u}:skipped:wrong_provider`);continue}try{let c=await p.execute(e,{signal:r?.signal});return this.markHealthy(u),i.push(`${u}:success`),this.emitEngineEvent({kind:"stream_complete",callId:o,id:randomUUID(),ts:Date.now(),stitched:!1,segments:[{provider:u,inputTokens:c.usage.input_tokens,outputTokens:c.usage.output_tokens,costUsd:c.costUsd,userCostUsd:c.userCostUsd??0}],provider:u,model:c.model,inputTokens:c.usage.input_tokens,outputTokens:c.usage.output_tokens,costUsd:c.costUsd,userCostUsd:c.userCostUsd,durationMs:c.durationMs??Date.now()-l,stopReason:c.stop_reason,fallbackChain:i,rateLimitHit:!1,securityState:r?.licenseState}),{...c,fallbackChain:i}}catch(c){if(c?.name==="AbortError"||r?.signal?.aborted)throw c;switch(Ce(c)){case "rate_limited":p.reportRateLimit({provider:u,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(u,"rate_limited"),i.push(`${u}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(u,"auth_failed"),i.push(`${u}:failed:auth_failed`);break;case "timeout":i.push(`${u}:failed:timeout`);break;case "provider_incompatible":i.push(`${u}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(u,"gateway_unavailable"),i.push(ie(u,c));break;default:i.push(ie(u,c));break}}}throw S("engine.cascade-exhausted",{chain:i,mode:"execute"}),new J(i)}async stream(e,t,r){let s=randomUUID(),i=Ke(t),a=Ge(e),o=Date.now(),l=[],p=null,u=null;for(let h of i){let y=h.type;if(this.getHealthStatus(y)==="unhealthy"){l.push(`${y}:skipped:unhealthy`);continue}if(a&&!h.supportsMultimodal){l.push(`${y}:skipped:no_multimodal`);continue}if(!h.supportsStreaming){l.push(`${y}:skipped:no_streaming`);continue}let C=se(e.model);if(C&&C!==y&&He.has(y)){l.push(`${y}:skipped:wrong_provider`);continue}try{u=await h.streamRaw(e,{signal:r?.signal}),p=h,l.push(`${y}:success`);break}catch(b){if(b?.name==="AbortError"||r?.signal?.aborted)throw b;switch(Ce(b)){case "rate_limited":h.reportRateLimit({provider:y,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(y,"rate_limited"),l.push(`${y}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(y,"auth_failed"),l.push(`${y}:failed:auth_failed`);break;case "timeout":l.push(`${y}:failed:timeout`);break;case "provider_incompatible":l.push(`${y}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(y,"gateway_unavailable"),l.push(ie(y,b));break;default:l.push(ie(y,b));break}}}if(!p||!u)throw S("engine.cascade-exhausted",{chain:l,mode:"stream"}),new J(l);let m=this,c=r?.maxMidStreamFailovers??2,E=new Set([p]);async function*d(){let h=p,y=u[Symbol.asyncIterator](),C={role:"assistant",content:[]},b={segments:[]},T=Ve(h.type);b.segments.push(T);let we=0,Q=null,Z=false,me=c,U="",F="";for(m.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type});;)try{for(;;){let R=await y.next();if(R.done)break;let L=R.value,k=Tt(L,we,C,Z,Q);if(k.action==="suppress"){"coalesceMode"in k&&(Q=k.coalesceMode),k.clearedJustFailedOver&&(Z=!1);continue}k.coalesceModeCleared&&(Q=null),k.clearedJustFailedOver&&(Z=!1);let v=k.event;if(It(C,v),v.type==="message_start"){if(b.segments.length>1)continue;U=v.message?.model||U,v.message?.usage?.input_tokens!=null&&(T.inputTokens=v.message.usage.input_tokens);}if(v.type==="message_delta"&&(v.delta?.stop_reason&&(F=v.delta.stop_reason),v.usage)){kt(T,h.type,v.usage),yield {...v,usage:void 0};continue}if(v.type==="message_stop")break;yield v;}if(C.content.length===0&&T.outputTokens===0)throw new Error("stream ended without producing any content");m.markHealthy(h.type),m.emitEngineEvent({kind:"segment_complete",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type,usage:{...T}});let w=We(b.segments);yield {type:"message_delta",delta:{stop_reason:F||"end_turn"},usage:w},yield {type:"message_stop"},m.emitEngineEvent({kind:"stream_complete",callId:s,id:randomUUID(),ts:Date.now(),stitched:b.segments.length>1,segments:b.segments.map(R=>({...R})),provider:b.segments.map(R=>R.provider).join("+"),model:U,inputTokens:w.input_tokens,outputTokens:w.output_tokens,costUsd:b.segments.reduce((R,L)=>R+L.costUsd,0),userCostUsd:b.segments.reduce((R,L)=>R+L.userCostUsd,0),durationMs:Date.now()-o,stopReason:F||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(w){if(w?.name==="AbortError"||r?.signal?.aborted)throw w;let R=Ce(w);try{await y.return?.();}catch{}if(m.markUnhealthy(h.type,String(w)),m.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:s,id:randomUUID(),ts:Date.now(),from:h.type,bytesBuffered:$e(C),errorClass:R,retriesLeft:me}),l.push(`${h.type}:partial(${$e(C)}b)`),me<=0)throw m.emitTerminalExhaustion(s,b,U,F,l,o,r?.licenseState),w;let L=xt(C.content),k=[...e.messages,{role:"assistant",content:L}],v=null,ee=null,Pe=h;for(;;){let I=m.nextHealthyProvider(i,Pe,a,E);if(!I)break;Pe=I,E.add(I);let ze={...e,messages:k,...I.type!=="anthropic-api"&&I.type!=="claude-cli"?{system:Lt(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{ee=await I.streamRaw(ze,{signal:r?.signal}),v=I;break}catch(ke){m.markUnhealthy(I.type,String(ke)),l.push(`${I.type}:failed_connect:${String(ke).slice(0,Ye)}`);}}if(!v||!ee)throw m.emitTerminalExhaustion(s,b,U,F,l,o,r?.licenseState),w;l.push(`${v.type}:stitched`),m.emitEngineEvent({kind:"mid_stream_failover_success",callId:s,id:randomUUID(),ts:Date.now(),from:h.type,to:v.type}),we=Mt(C)+1,me--,h=v,y=ee[Symbol.asyncIterator](),Z=true,Q=null,T=Ve(h.type),b.segments.push(T),m.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type});}}let f=d();return r?.licenseState==="SEC_DEGRADED"&&(f=Dt(f)),D(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=We(t.segments);this.emitEngineEvent({kind:"stream_complete",callId:e,id:randomUUID(),ts:Date.now(),stitched:t.segments.length>1,segments:t.segments.map(p=>({...p})),provider:t.segments.map(p=>p.provider).join("+"),model:r,inputTokens:l.input_tokens,outputTokens:l.output_tokens,costUsd:t.segments.reduce((p,u)=>p+u.costUsd,0),userCostUsd:t.segments.reduce((p,u)=>p+u.userCostUsd,0),durationMs:Date.now()-a,stopReason:s||"error",fallbackChain:i,rateLimitHit:false,securityState:o});}};function Ve(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function kt(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 We(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function It(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 Tt(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 xt(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 Lt(n,e){return n?`${n}
14
14
 
15
- ${e}`:e}function Ve(n){let e=0;for(let t of n.content)t.type==="text"?e+=t.text.length:t.type==="tool_use"&&(e+=(t._partialJson||"").length);return e}function It(n){return Math.max(0,n.content.length-1)}async function*Tt(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}ee();function se(n,e){if(e==="prefer-user"){let s=n.filter(a=>a.type==="claude-cli"),i=n.filter(a=>a.type!=="claude-cli");return [...s,...i]}if(e==="prefer-app"){let s=n.filter(a=>a.type==="claude-cli");return [...n.filter(a=>a.type!=="claude-cli"),...s]}let t=n.filter(s=>s.type===e),r=n.filter(s=>s.type!==e);return [...t,...r]}function ie(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var ve={"claude-opus-4":[15,75],"claude-sonnet-4":[3,15],"claude-haiku-4":[.8,4],"gpt-4o":[2.5,10],"gpt-4o-mini":[.15,.6],"gpt-4-turbo":[10,30],"gpt-3.5-turbo":[.5,1.5],llama:[0,0],mistral:[0,0],codellama:[0,0]};function ae(n){if(ve[n])return ve[n];for(let[e,t]of Object.entries(ve))if(n.startsWith(e))return t;return [3,15]}function oe(n){let e=0;for(let o of n.messages)if(typeof o.content=="string")e+=o.content.length;else if(Array.isArray(o.content))for(let l of o.content)l.type==="text"&&l.text&&(e+=l.text.length);n.system&&(e+=n.system.length);let t=Math.ceil(e/4),r=Math.min(n.max_tokens||1024,4096),[s,i]=ae(n.model),a=(t*s+r*i)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(a*1e4)/1e4,model:n.model,provider:""}}var D=class{endpoint;enabled;keyId;lineageBuffer=new Map;unsubscribers=[];constructor(e){this.endpoint=e.endpoint||"https://api.inference-relay.com/v1/events",this.enabled=e.enabled??true,this.keyId=e.keyId||"";}subscribeToEngine(e){let t=s=>this.bufferLineageEvent(s),r=s=>{s.kind==="stream_complete"&&this.flushLineageForCall(s);};e.engineEvents.onTyped("segment_start",t),e.engineEvents.onTyped("segment_complete",t),e.engineEvents.onTyped("mid_stream_failover_attempt",t),e.engineEvents.onTyped("mid_stream_failover_success",t),e.engineEvents.onTyped("stream_complete",r),this.unsubscribers.push(()=>{e.engineEvents.offTyped("segment_start",t),e.engineEvents.offTyped("segment_complete",t),e.engineEvents.offTyped("mid_stream_failover_attempt",t),e.engineEvents.offTyped("mid_stream_failover_success",t),e.engineEvents.offTyped("stream_complete",r);});}unsubscribe(){for(let e of this.unsubscribers)e();this.unsubscribers=[],this.lineageBuffer.clear();}bufferLineageEvent(e){let t=this.lineageBuffer.get(e.callId)??[];t.push(e),this.lineageBuffer.set(e.callId,t);}flushLineageForCall(e){let t=this.lineageBuffer.get(e.callId)??[];this.lineageBuffer.delete(e.callId);let r={timestamp:e.ts,provider:e.provider,model:e.model,inputTokens:e.inputTokens,outputTokens:e.outputTokens,costUsd:e.costUsd,userCostUsd:e.userCostUsd,durationMs:e.durationMs,stopReason:e.stopReason,fallbackChain:e.fallbackChain,rateLimitHit:e.rateLimitHit,securityState:e.securityState,stitched:e.stitched,segments:e.segments,lineage:t.map(s=>s.id),promptContent:false,completionContent:false};this.report(r);}report(e){!this.enabled||!this.keyId||fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({keyId:this.keyId,provider:e.provider,model:e.model,inputTokens:e.inputTokens,outputTokens:e.outputTokens,costUsd:e.costUsd,...e.userCostUsd!==void 0?{userCostUsd:e.userCostUsd}:{},durationMs:e.durationMs,fallback:e.fallbackChain.length>1,timestamp:e.timestamp,...e.stitched?{stitched:true,segmentCount:e.segments?.length??0}:{},...e.lineage?{lineageIds:e.lineage}:{}})}).catch(()=>{});}};var xt="https://api.inference-relay.com",Lt="/v1/validate",Mt=1440*60*1e3,Dt=10080*60*1e3,Ot=`-----BEGIN PUBLIC KEY-----
15
+ ${e}`:e}function $e(n){let e=0;for(let t of n.content)t.type==="text"?e+=t.text.length:t.type==="tool_use"&&(e+=(t._partialJson||"").length);return e}function Mt(n){return Math.max(0,n.content.length-1)}async function*Dt(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}re();function ae(n,e){if(e==="prefer-user"){let s=n.filter(a=>a.type==="claude-cli"),i=n.filter(a=>a.type!=="claude-cli");return [...s,...i]}if(e==="prefer-app"){let s=n.filter(a=>a.type==="claude-cli");return [...n.filter(a=>a.type!=="claude-cli"),...s]}let t=n.filter(s=>s.type===e),r=n.filter(s=>s.type!==e);return [...t,...r]}function oe(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var Re={"claude-opus-4":[15,75],"claude-sonnet-4":[3,15],"claude-haiku-4":[.8,4],"gpt-4o":[2.5,10],"gpt-4o-mini":[.15,.6],"gpt-4-turbo":[10,30],"gpt-3.5-turbo":[.5,1.5],llama:[0,0],mistral:[0,0],codellama:[0,0]};function le(n){if(Re[n])return Re[n];for(let[e,t]of Object.entries(Re))if(n.startsWith(e))return t;return [3,15]}function ce(n){let e=0;for(let o of n.messages)if(typeof o.content=="string")e+=o.content.length;else if(Array.isArray(o.content))for(let l of o.content)l.type==="text"&&l.text&&(e+=l.text.length);n.system&&(e+=n.system.length);let t=Math.ceil(e/4),r=Math.min(n.max_tokens||1024,4096),[s,i]=le(n.model),a=(t*s+r*i)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(a*1e4)/1e4,model:n.model,provider:""}}var N=class{endpoint;enabled;keyId;lineageBuffer=new Map;unsubscribers=[];constructor(e){this.endpoint=e.endpoint||"https://api.inference-relay.com/v1/events",this.enabled=e.enabled??true,this.keyId=e.keyId||"";}subscribeToEngine(e){let t=s=>this.bufferLineageEvent(s),r=s=>{s.kind==="stream_complete"&&this.flushLineageForCall(s);};e.engineEvents.onTyped("segment_start",t),e.engineEvents.onTyped("segment_complete",t),e.engineEvents.onTyped("mid_stream_failover_attempt",t),e.engineEvents.onTyped("mid_stream_failover_success",t),e.engineEvents.onTyped("stream_complete",r),this.unsubscribers.push(()=>{e.engineEvents.offTyped("segment_start",t),e.engineEvents.offTyped("segment_complete",t),e.engineEvents.offTyped("mid_stream_failover_attempt",t),e.engineEvents.offTyped("mid_stream_failover_success",t),e.engineEvents.offTyped("stream_complete",r);});}unsubscribe(){for(let e of this.unsubscribers)e();this.unsubscribers=[],this.lineageBuffer.clear();}bufferLineageEvent(e){let t=this.lineageBuffer.get(e.callId)??[];t.push(e),this.lineageBuffer.set(e.callId,t);}flushLineageForCall(e){let t=this.lineageBuffer.get(e.callId)??[];this.lineageBuffer.delete(e.callId);let r={timestamp:e.ts,provider:e.provider,model:e.model,inputTokens:e.inputTokens,outputTokens:e.outputTokens,costUsd:e.costUsd,userCostUsd:e.userCostUsd,durationMs:e.durationMs,stopReason:e.stopReason,fallbackChain:e.fallbackChain,rateLimitHit:e.rateLimitHit,securityState:e.securityState,stitched:e.stitched,segments:e.segments,lineage:t.map(s=>s.id),promptContent:false,completionContent:false};this.report(r);}report(e){!this.enabled||!this.keyId||fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({keyId:this.keyId,provider:e.provider,model:e.model,inputTokens:e.inputTokens,outputTokens:e.outputTokens,costUsd:e.costUsd,...e.userCostUsd!==void 0?{userCostUsd:e.userCostUsd}:{},durationMs:e.durationMs,fallback:e.fallbackChain.length>1,timestamp:e.timestamp,...e.stitched?{stitched:true,segmentCount:e.segments?.length??0}:{},...e.lineage?{lineageIds:e.lineage}:{}})}).catch(()=>{});}};var Ot="https://api.inference-relay.com",Nt="/v1/validate",Ut=1440*60*1e3,Ft=10080*60*1e3,Bt=`-----BEGIN PUBLIC KEY-----
16
16
  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzk88Bt9LZSmuSd8ulKqy
17
17
  EGNiPB+r8u1ZinBvMM4qX8dp4kzJEC/47L1RYrrxCphD05HToREjljbj+upH6rZH
18
18
  t6D/5funYPi2TO1IOSC6BRVRwMqqTmJGVJcLcG/WF3gTE+2UQ3q5EppWJCEKcz6x
@@ -20,5 +20,5 @@ kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
20
20
  7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
21
21
  Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
22
22
  UQIDAQAB
23
- -----END PUBLIC KEY-----`,x=new Map;async function Ce(n,e){if(!n)return {valid:false,error:"License key required. Get one at inference-relay.com"};let t=x.get(n);if(t&&Date.now()-t.cachedAt<t.ttl)return t.result;let r=new AbortController,i=!x.has(n)?3e3:1e3,a=setTimeout(()=>r.abort(),i),o;try{let d=(e||xt)+Lt;o=await(await fetch(d,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:n}),signal:r.signal})).json();}catch{return clearTimeout(a),t&&Date.now()-t.cachedAt<Dt?t.result:{valid:false,error:"License validation failed (network error). Visit inference-relay.com"}}clearTimeout(a);let l;if(o.jws)try{let{compactVerify:d,importSPKI:c}=await import('jose'),p=await c(Ot,"RS256"),{payload:y}=await d(o.jws,p);l=JSON.parse(new TextDecoder().decode(y));}catch{return x.delete(n),{valid:false,error:"License validation signature invalid. Possible MITM \u2014 refusing to start."}}else if(l=o,l.valid)return x.delete(n),{valid:false,error:"License validation response not signed. Possible MITM."};return x.set(n,{result:l,cachedAt:Date.now(),ttl:l.valid?Mt:6e4}),l}var Ae=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new M;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new j,this.telemetryReporter=new D({endpoint:e.endpoint?`${e.endpoint}/v1/events`:void 0,enabled:e.telemetry!==false,keyId:e.licenseKey}),this.telemetryReporter.subscribeToEngine(this.fallbackEngine),e.routing&&(this.routingFn=ie(e.routing)),e.providers)for(let s of e.providers){let i=typeof s=="string"?{type:s}:s,a=this.createProvider(i);a&&(i.priority!==void 0&&(a.priority=i.priority),this.providers.push(a));}let t=100,r=3600*1e3;this.messages={create:async(s,i)=>{let a=this.license&&(this.callsSinceValidation>=t||Date.now()-this.licenseValidatedAt>=r);if(a&&(this.license=null),!this.license){this.licensePromise||(this.licensePromise=Ce(this.config.licenseKey,this.config.endpoint));try{this.license=await this.licensePromise;}finally{this.licensePromise=null;}if(this.licenseValidatedAt=Date.now(),this.callsSinceValidation=0,this.license.valid){if(this.license.capExceeded)throw this.startCapProbe(),new U({tier:this.license.tier||"solo",baseCap:this.license.baseCap??this.license.usageCap??null,topUps:this.license.topUpGrants??0,effectiveCap:this.license.usageCap??null,usedThisCycle:this.license.usageThisMonth??0});a||console.log(`[inference-relay] LICENSE AUTHORIZED [${(this.license.tier||"unknown").toUpperCase()} TIER] \u2014 READY.`);}else throw new Error(`[inference-relay] ${this.license.error||"License key invalid or expired. Visit inference-relay.com"}`)}return this.callsSinceValidation++,s.stream?this.streamMessage(s,i):this.executeMessage(s,i)}};}startCapProbe(){if(this.capProbeTimer!==null)return;let e=15e3,t=20,r=4;this.capProbeTicksRemaining=t;let s=async()=>{this.capProbeTicksRemaining-=1;let i=Math.ceil(this.capProbeTicksRemaining*e/6e4);this.capProbeTicksRemaining>0&&this.capProbeTicksRemaining%r===0&&console.log(`[inference-relay] cap exceeded \u2014 checking for top-up every 15s (${i}m remaining)`),this.config.licenseKey&&x.delete(this.config.licenseKey);try{let a=await this.probeValidate();if(a.valid&&a.capExceeded===!1){console.log("[inference-relay] cap cleared \u2014 probe exiting, inference resuming"),this.license=a,this.licenseValidatedAt=Date.now(),this.callsSinceValidation=0,this.stopCapProbe();return}}catch{}this.capProbeTicksRemaining<=0&&(console.log("[inference-relay] cap probe exhausted (5 min) \u2014 stopping"),this.stopCapProbe());};this.capProbeTimer=setInterval(s,e),typeof this.capProbeTimer.unref=="function"&&this.capProbeTimer.unref();}async probeValidate(){return Ce(this.config.licenseKey,this.config.endpoint)}stopCapProbe(){this.capProbeTimer!==null&&(clearInterval(this.capProbeTimer),this.capProbeTimer=null),this.capProbeTicksRemaining=0;}static async autoDetect(e){let t=[],r=await H();return r.available&&r.authenticated!==false&&t.push({type:"claude-cli",priority:1}),process.env.ANTHROPIC_API_KEY&&t.push({type:"anthropic-api",priority:2,apiKey:process.env.ANTHROPIC_API_KEY}),new n({licenseKey:e?.licenseKey||process.env.IR_LICENSE_KEY||"",providers:t,fallback:e?.fallback??true,...e})}dispose(){this.providers=[],this.config.licenseKey&&x.delete(this.config.licenseKey),this.license=null,this.licensePromise=null,this.callsSinceValidation=0,this.stopCapProbe(),this.telemetryReporter.unsubscribe(),this.manifestDecryptor.clearCache(),ke();}resolveProviders(e){if(!this.routingFn)return this.providers;let t=oe(e),r=this.routingFn(e,t);return se(this.providers,r)}async executeMessage(e,t){let r=this.resolveProviders(e);return this.fallbackEngine.execute(e,r,{signal:t?.signal,licenseState:this.manifestDecryptor.getSecurityState()})}async streamMessage(e,t){let r=this.resolveProviders(e);return this.fallbackEngine.stream(e,r,{signal:t?.signal,licenseState:this.manifestDecryptor.getSecurityState()})}createProvider(e){switch(e.type){case "claude-cli":return new te(this.config.licenseKey);case "anthropic-api":return e.apiKey?new V({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new W({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new Y({baseUrl:e.baseUrl});default:return null}}};ee();var Nt="https://api.anthropic.com/v1/messages",Ut="2023-06-01";async function Ye(n){try{let e=await fetch(Nt,{method:"POST",headers:{"content-type":"application/json","x-api-key":n,"anthropic-version":Ut},body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{valid:!1,error:"Invalid API key (401)"}:e.ok?{valid:!0}:e.status===429?{valid:!0,error:"Rate limited (429)"}:e.status===529?{valid:!0,error:"API overloaded (529)"}:{valid:!1,error:`Unexpected status ${e.status}`}}catch(e){return {valid:false,error:`Network error: ${e.message}`}}}var le=class{filePath;safeStorage=null;memoryFallback=new Map;constructor(e){let t=e?.storagePath||join(homedir(),".inference-relay");existsSync(t)||mkdirSync(t,{recursive:true}),this.filePath=join(t,"credentials.enc");try{let r=ze("electron");r?.safeStorage?.isEncryptionAvailable?.()&&(this.safeStorage=r.safeStorage);}catch{}}readDisk(){if(!existsSync(this.filePath))return {};try{let e=readFileSync(this.filePath,"utf-8");return JSON.parse(e)}catch{return {}}}writeDisk(e){writeFileSync(this.filePath,JSON.stringify(e,null,2),{mode:384});}async get(e){if(!this.safeStorage)return this.memoryFallback.get(e)??null;let r=this.readDisk()[e];if(!r)return null;try{let s=Buffer.from(r.data,"base64");return this.safeStorage.decryptString(s)}catch{return null}}async set(e,t){if(!this.safeStorage){this.memoryFallback.set(e,t);return}let r=this.readDisk(),s=this.safeStorage.encryptString(t);r[e]={data:s.toString("base64")},this.writeDisk(r);}async delete(e){if(!this.safeStorage){this.memoryFallback.delete(e);return}let t=this.readDisk();e in t&&(delete t[e],this.writeDisk(t));}async has(e){if(!this.safeStorage)return this.memoryFallback.has(e);let t=this.readDisk();return e in t}};var J="AES-GCM";var ce=class{dbName="inference-relay-credentials";storeName="keys";cryptoKey=null;passphrase;initPromise=null;constructor(e){this.passphrase=e?.passphrase,e?.dbName&&(this.dbName=e.dbName);}async ensureReady(){if(!this.cryptoKey)return this.initPromise?this.initPromise:(this.initPromise=this.init(),this.initPromise)}async init(){if(await this.openDB(),this.passphrase)this.cryptoKey=await this.deriveKey(this.passphrase,this.getOrCreateSessionSalt());else {let e=typeof sessionStorage<"u"?sessionStorage.getItem("ir-cred-key"):null;if(e){let t=Uint8Array.from(atob(e),r=>r.charCodeAt(0));this.cryptoKey=await crypto.subtle.importKey("raw",t,J,false,["encrypt","decrypt"]);}else {this.cryptoKey=await crypto.subtle.generateKey({name:J,length:256},true,["encrypt","decrypt"]);let t=await crypto.subtle.exportKey("raw",this.cryptoKey),r=btoa(String.fromCharCode(...new Uint8Array(t)));typeof sessionStorage<"u"&&sessionStorage.setItem("ir-cred-key",r);}}}openDB(){return new Promise((e,t)=>{let r=indexedDB.open(this.dbName,1);r.onupgradeneeded=()=>{let s=r.result;s.objectStoreNames.contains(this.storeName)||s.createObjectStore(this.storeName);},r.onsuccess=()=>e(r.result),r.onerror=()=>t(r.error);})}async idbGet(e){let t=await this.openDB();return new Promise((r,s)=>{let o=t.transaction(this.storeName,"readonly").objectStore(this.storeName).get(e);o.onsuccess=()=>r(o.result),o.onerror=()=>s(o.error);})}async idbPut(e,t){let r=await this.openDB();return new Promise((s,i)=>{let l=r.transaction(this.storeName,"readwrite").objectStore(this.storeName).put(t,e);l.onsuccess=()=>s(),l.onerror=()=>i(l.error);})}async idbDelete(e){let t=await this.openDB();return new Promise((r,s)=>{let o=t.transaction(this.storeName,"readwrite").objectStore(this.storeName).delete(e);o.onsuccess=()=>r(),o.onerror=()=>s(o.error);})}async idbHas(e){let t=await this.openDB();return new Promise((r,s)=>{let o=t.transaction(this.storeName,"readonly").objectStore(this.storeName).count(e);o.onsuccess=()=>r(o.result>0),o.onerror=()=>s(o.error);})}getOrCreateSessionSalt(){let e="ir-cred-salt";if(typeof sessionStorage<"u"){let r=sessionStorage.getItem(e);if(r)return Uint8Array.from(atob(r),s=>s.charCodeAt(0))}let t=crypto.getRandomValues(new Uint8Array(16));return typeof sessionStorage<"u"&&sessionStorage.setItem(e,btoa(String.fromCharCode(...t))),t}async deriveKey(e,t){let r=new TextEncoder,s=await crypto.subtle.importKey("raw",r.encode(e),"PBKDF2",false,["deriveKey"]);return crypto.subtle.deriveKey({name:"PBKDF2",salt:t.buffer,iterations:1e5,hash:"SHA-256"},s,{name:J,length:256},false,["encrypt","decrypt"])}async encrypt(e){let t=crypto.getRandomValues(new Uint8Array(12)),r=this.getOrCreateSessionSalt(),s=new TextEncoder().encode(e),i=await crypto.subtle.encrypt({name:J,iv:t},this.cryptoKey,s);return {iv:btoa(String.fromCharCode(...t)),ciphertext:btoa(String.fromCharCode(...new Uint8Array(i))),salt:btoa(String.fromCharCode(...r))}}async decrypt(e){let t=Uint8Array.from(atob(e.iv),i=>i.charCodeAt(0)),r=Uint8Array.from(atob(e.ciphertext),i=>i.charCodeAt(0)),s=await crypto.subtle.decrypt({name:J,iv:t},this.cryptoKey,r);return new TextDecoder().decode(s)}async get(e){await this.ensureReady();let t=await this.idbGet(e);if(!t)return null;try{return await this.decrypt(t)}catch{return null}}async set(e,t){await this.ensureReady();let r=await this.encrypt(t);await this.idbPut(e,r);}async delete(e){await this.ensureReady(),await this.idbDelete(e);}async has(e){return await this.ensureReady(),this.idbHas(e)}};var ue=class{store=new Map;async get(e){return this.store.get(e)??null}async set(e,t){this.store.set(e,t);}async delete(e){this.store.delete(e);}async has(e){return this.store.has(e)}};
24
- export{V as AnthropicAPIProvider,R as BaseProvider,le as ElectronCredentialStore,$ as EngineEventEmitter,j as FallbackEngine,B as GatewayLoader,b as GatewayLoaderError,ce as IndexedDBCredentialStore,Ae as InferenceRelay,K as MODEL_ALIASES,G as MODEL_REGISTRY,M as ManifestDecryptor,ue as MemoryCredentialStore,Y as OllamaProvider,W as OpenAIAPIProvider,U as RelayCapExceededError,q as RelayError,D as TelemetryReporter,se as applyRouting,L as createRelayStream,ie as createRoutingFunction,H as detectCLI,oe as estimateCost,mt as findModel,et as getLastKnownGoodManifest,ae as getModelPricing,tt as getValue,ht as modelsForProvider,fe as normalizeModel,re as providerForModel,Ye as validateAnthropicKey,Ce as validateLicense};
23
+ -----END PUBLIC KEY-----`,M=new Map;async function Ae(n,e){if(!n)return {valid:false,error:"License key required. Get one at inference-relay.com"};let t=M.get(n);if(t&&Date.now()-t.cachedAt<t.ttl)return t.result;let r=new AbortController,i=!M.has(n)?3e3:1e3,a=setTimeout(()=>r.abort(),i),o;try{let p=(e||Ot)+Nt;o=await(await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:n}),signal:r.signal})).json();}catch{return clearTimeout(a),t&&Date.now()-t.cachedAt<Ft?t.result:{valid:false,error:"License validation failed (network error). Visit inference-relay.com"}}clearTimeout(a);let l;if(o.jws)try{let{compactVerify:p,importSPKI:u}=await import('jose'),g=await u(Bt,"RS256"),{payload:m}=await p(o.jws,g);l=JSON.parse(new TextDecoder().decode(m));}catch{return M.delete(n),{valid:false,error:"License validation signature invalid. Possible MITM \u2014 refusing to start."}}else if(l=o,l.valid)return M.delete(n),{valid:false,error:"License validation response not signed. Possible MITM."};return M.set(n,{result:l,cachedAt:Date.now(),ttl:l.valid?Ut:6e4}),l}var Se=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new O;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new z,this.telemetryReporter=new N({endpoint:e.endpoint?`${e.endpoint}/v1/events`:void 0,enabled:e.telemetry!==false,keyId:e.licenseKey}),this.telemetryReporter.subscribeToEngine(this.fallbackEngine),e.routing&&(this.routingFn=oe(e.routing)),e.providers)for(let s of e.providers){let i=typeof s=="string"?{type:s}:s,a=this.createProvider(i);a&&(i.priority!==void 0&&(a.priority=i.priority),this.providers.push(a));}let t=100,r=3600*1e3;this.messages={create:async(s,i)=>{let a=this.license&&(this.callsSinceValidation>=t||Date.now()-this.licenseValidatedAt>=r);if(a&&(this.license=null),!this.license){this.licensePromise||(this.licensePromise=Ae(this.config.licenseKey,this.config.endpoint));try{this.license=await this.licensePromise;}finally{this.licensePromise=null;}if(this.licenseValidatedAt=Date.now(),this.callsSinceValidation=0,this.license.valid){if(this.license.capExceeded)throw this.startCapProbe(),new B({tier:this.license.tier||"solo",baseCap:this.license.baseCap??this.license.usageCap??null,topUps:this.license.topUpGrants??0,effectiveCap:this.license.usageCap??null,usedThisCycle:this.license.usageThisMonth??0});a||console.log(`[inference-relay] LICENSE AUTHORIZED [${(this.license.tier||"unknown").toUpperCase()} TIER] \u2014 READY.`);}else throw new Error(`[inference-relay] ${this.license.error||"License key invalid or expired. Visit inference-relay.com"}`)}return this.callsSinceValidation++,s.stream?this.streamMessage(s,i):this.executeMessage(s,i)}};}startCapProbe(){if(this.capProbeTimer!==null)return;let e=15e3,t=20,r=4;this.capProbeTicksRemaining=t;let s=async()=>{this.capProbeTicksRemaining-=1;let i=Math.ceil(this.capProbeTicksRemaining*e/6e4);this.capProbeTicksRemaining>0&&this.capProbeTicksRemaining%r===0&&console.log(`[inference-relay] cap exceeded \u2014 checking for top-up every 15s (${i}m remaining)`),this.config.licenseKey&&M.delete(this.config.licenseKey);try{let a=await this.probeValidate();if(a.valid&&a.capExceeded===!1){console.log("[inference-relay] cap cleared \u2014 probe exiting, inference resuming"),this.license=a,this.licenseValidatedAt=Date.now(),this.callsSinceValidation=0,this.stopCapProbe();return}}catch{}this.capProbeTicksRemaining<=0&&(console.log("[inference-relay] cap probe exhausted (5 min) \u2014 stopping"),this.stopCapProbe());};this.capProbeTimer=setInterval(s,e),typeof this.capProbeTimer.unref=="function"&&this.capProbeTimer.unref();}async probeValidate(){return Ae(this.config.licenseKey,this.config.endpoint)}stopCapProbe(){this.capProbeTimer!==null&&(clearInterval(this.capProbeTimer),this.capProbeTimer=null),this.capProbeTicksRemaining=0;}static async autoDetect(e){let t=[],r=await K();return r.available&&r.authenticated!==false&&t.push({type:"claude-cli",priority:1}),process.env.ANTHROPIC_API_KEY&&t.push({type:"anthropic-api",priority:2,apiKey:process.env.ANTHROPIC_API_KEY}),new n({licenseKey:e?.licenseKey||process.env.IR_LICENSE_KEY||"",providers:t,fallback:e?.fallback??true,...e})}async warmup(){let e=this.providers.find(t=>t.type==="claude-cli");e&&"warmup"in e&&typeof e.warmup=="function"&&await e.warmup();}dispose(){this.providers=[],this.config.licenseKey&&M.delete(this.config.licenseKey),this.license=null,this.licensePromise=null,this.callsSinceValidation=0,this.stopCapProbe(),this.telemetryReporter.unsubscribe(),this.manifestDecryptor.clearCache(),Ie();}resolveProviders(e){if(!this.routingFn)return this.providers;let t=ce(e),r=this.routingFn(e,t);return ae(this.providers,r)}async executeMessage(e,t){let r=this.resolveProviders(e);return this.fallbackEngine.execute(e,r,{signal:t?.signal,licenseState:this.manifestDecryptor.getSecurityState()})}async streamMessage(e,t){let r=this.resolveProviders(e);return this.fallbackEngine.stream(e,r,{signal:t?.signal,licenseState:this.manifestDecryptor.getSecurityState()})}createProvider(e){switch(e.type){case "claude-cli":return new ne(this.config.licenseKey,{retryDelaysMs:this.config.gatewayRetryDelaysMs});case "anthropic-api":return e.apiKey?new $({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new Y({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new q({baseUrl:e.baseUrl});default:return null}}};re();var Ht="https://api.anthropic.com/v1/messages",Gt="2023-06-01";async function qe(n){try{let e=await fetch(Ht,{method:"POST",headers:{"content-type":"application/json","x-api-key":n,"anthropic-version":Gt},body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{valid:!1,error:"Invalid API key (401)"}:e.ok?{valid:!0}:e.status===429?{valid:!0,error:"Rate limited (429)"}:e.status===529?{valid:!0,error:"API overloaded (529)"}:{valid:!1,error:`Unexpected status ${e.status}`}}catch(e){return {valid:false,error:`Network error: ${e.message}`}}}var ue=class{filePath;safeStorage=null;memoryFallback=new Map;constructor(e){let t=e?.storagePath||join(homedir(),".inference-relay");existsSync(t)||mkdirSync(t,{recursive:true}),this.filePath=join(t,"credentials.enc");try{let r=Qe("electron");r?.safeStorage?.isEncryptionAvailable?.()&&(this.safeStorage=r.safeStorage);}catch{}}readDisk(){if(!existsSync(this.filePath))return {};try{let e=readFileSync(this.filePath,"utf-8");return JSON.parse(e)}catch{return {}}}writeDisk(e){writeFileSync(this.filePath,JSON.stringify(e,null,2),{mode:384});}async get(e){if(!this.safeStorage)return this.memoryFallback.get(e)??null;let r=this.readDisk()[e];if(!r)return null;try{let s=Buffer.from(r.data,"base64");return this.safeStorage.decryptString(s)}catch{return null}}async set(e,t){if(!this.safeStorage){this.memoryFallback.set(e,t);return}let r=this.readDisk(),s=this.safeStorage.encryptString(t);r[e]={data:s.toString("base64")},this.writeDisk(r);}async delete(e){if(!this.safeStorage){this.memoryFallback.delete(e);return}let t=this.readDisk();e in t&&(delete t[e],this.writeDisk(t));}async has(e){if(!this.safeStorage)return this.memoryFallback.has(e);let t=this.readDisk();return e in t}};var X="AES-GCM";var de=class{dbName="inference-relay-credentials";storeName="keys";cryptoKey=null;passphrase;initPromise=null;constructor(e){this.passphrase=e?.passphrase,e?.dbName&&(this.dbName=e.dbName);}async ensureReady(){if(!this.cryptoKey)return this.initPromise?this.initPromise:(this.initPromise=this.init(),this.initPromise)}async init(){if(await this.openDB(),this.passphrase)this.cryptoKey=await this.deriveKey(this.passphrase,this.getOrCreateSessionSalt());else {let e=typeof sessionStorage<"u"?sessionStorage.getItem("ir-cred-key"):null;if(e){let t=Uint8Array.from(atob(e),r=>r.charCodeAt(0));this.cryptoKey=await crypto.subtle.importKey("raw",t,X,false,["encrypt","decrypt"]);}else {this.cryptoKey=await crypto.subtle.generateKey({name:X,length:256},true,["encrypt","decrypt"]);let t=await crypto.subtle.exportKey("raw",this.cryptoKey),r=btoa(String.fromCharCode(...new Uint8Array(t)));typeof sessionStorage<"u"&&sessionStorage.setItem("ir-cred-key",r);}}}openDB(){return new Promise((e,t)=>{let r=indexedDB.open(this.dbName,1);r.onupgradeneeded=()=>{let s=r.result;s.objectStoreNames.contains(this.storeName)||s.createObjectStore(this.storeName);},r.onsuccess=()=>e(r.result),r.onerror=()=>t(r.error);})}async idbGet(e){let t=await this.openDB();return new Promise((r,s)=>{let o=t.transaction(this.storeName,"readonly").objectStore(this.storeName).get(e);o.onsuccess=()=>r(o.result),o.onerror=()=>s(o.error);})}async idbPut(e,t){let r=await this.openDB();return new Promise((s,i)=>{let l=r.transaction(this.storeName,"readwrite").objectStore(this.storeName).put(t,e);l.onsuccess=()=>s(),l.onerror=()=>i(l.error);})}async idbDelete(e){let t=await this.openDB();return new Promise((r,s)=>{let o=t.transaction(this.storeName,"readwrite").objectStore(this.storeName).delete(e);o.onsuccess=()=>r(),o.onerror=()=>s(o.error);})}async idbHas(e){let t=await this.openDB();return new Promise((r,s)=>{let o=t.transaction(this.storeName,"readonly").objectStore(this.storeName).count(e);o.onsuccess=()=>r(o.result>0),o.onerror=()=>s(o.error);})}getOrCreateSessionSalt(){let e="ir-cred-salt";if(typeof sessionStorage<"u"){let r=sessionStorage.getItem(e);if(r)return Uint8Array.from(atob(r),s=>s.charCodeAt(0))}let t=crypto.getRandomValues(new Uint8Array(16));return typeof sessionStorage<"u"&&sessionStorage.setItem(e,btoa(String.fromCharCode(...t))),t}async deriveKey(e,t){let r=new TextEncoder,s=await crypto.subtle.importKey("raw",r.encode(e),"PBKDF2",false,["deriveKey"]);return crypto.subtle.deriveKey({name:"PBKDF2",salt:t.buffer,iterations:1e5,hash:"SHA-256"},s,{name:X,length:256},false,["encrypt","decrypt"])}async encrypt(e){let t=crypto.getRandomValues(new Uint8Array(12)),r=this.getOrCreateSessionSalt(),s=new TextEncoder().encode(e),i=await crypto.subtle.encrypt({name:X,iv:t},this.cryptoKey,s);return {iv:btoa(String.fromCharCode(...t)),ciphertext:btoa(String.fromCharCode(...new Uint8Array(i))),salt:btoa(String.fromCharCode(...r))}}async decrypt(e){let t=Uint8Array.from(atob(e.iv),i=>i.charCodeAt(0)),r=Uint8Array.from(atob(e.ciphertext),i=>i.charCodeAt(0)),s=await crypto.subtle.decrypt({name:X,iv:t},this.cryptoKey,r);return new TextDecoder().decode(s)}async get(e){await this.ensureReady();let t=await this.idbGet(e);if(!t)return null;try{return await this.decrypt(t)}catch{return null}}async set(e,t){await this.ensureReady();let r=await this.encrypt(t);await this.idbPut(e,r);}async delete(e){await this.ensureReady(),await this.idbDelete(e);}async has(e){return await this.ensureReady(),this.idbHas(e)}};var pe=class{store=new Map;async get(e){return this.store.get(e)??null}async set(e,t){this.store.set(e,t);}async delete(e){this.store.delete(e);}async has(e){return this.store.has(e)}};
24
+ export{$ as AnthropicAPIProvider,A as BaseProvider,ue as ElectronCredentialStore,j as EngineEventEmitter,z as FallbackEngine,G as GatewayLoader,_ as GatewayLoaderError,x as GatewayUnavailableError,de as IndexedDBCredentialStore,Se as InferenceRelay,W as MODEL_ALIASES,V as MODEL_REGISTRY,O as ManifestDecryptor,pe as MemoryCredentialStore,q as OllamaProvider,Y as OpenAIAPIProvider,B as RelayCapExceededError,J as RelayError,N as TelemetryReporter,ae as applyRouting,D as createRelayStream,oe as createRoutingFunction,K as detectCLI,ce as estimateCost,ft as findModel,rt as getLastKnownGoodManifest,le as getModelPricing,nt as getValue,bt as modelsForProvider,_e as normalizeModel,se as providerForModel,qe as validateAnthropicKey,Ae as validateLicense};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inference-relay",
3
- "version": "1.6.1",
3
+ "version": "1.6.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.6.1 release — guard intentionally relaxed for this publish' && exit 0"
62
+ "prepublishOnly": "node -e \"if (!process.env.IR_PUBLISH_OK) { console.error('PUBLISH BLOCKED — set IR_PUBLISH_OK=1 to publish (1.6.2+ env-gate pattern; guard stays permanent)'); process.exit(1) }\""
63
63
  },
64
64
  "devDependencies": {
65
65
  "@types/node": "^22.0.0",