inference-relay 1.6.3 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/main.js +5 -5
- package/dist/index.cjs +8 -8
- package/dist/index.d.cts +48 -3
- package/dist/index.d.ts +48 -3
- package/dist/index.js +8 -8
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {existsSync,mkdirSync,writeFileSync,readFileSync}from'fs';import {homedir}from'os';import {join,dirname}from'path';import {randomUUID,createHash}from'crypto';import {compileFunction}from'vm';import {createRequire}from'module';import {execSync}from'child_process';import {EventEmitter}from'events';/*! inference-relay CLI (c) 2026 L2B II LLC. Patent pending. */
|
|
3
|
-
var Tt=Object.defineProperty;var v=(n,e)=>()=>(n&&(e=n(n=0)),e);var Ne=(n,e)=>{for(var t in e)Tt(n,t,{get:e[t],enumerable:true});};var
|
|
3
|
+
var Tt=Object.defineProperty;var v=(n,e)=>()=>(n&&(e=n(n=0)),e);var Ne=(n,e)=>{for(var t in e)Tt(n,t,{get:e[t],enumerable:true});};var $,_e=v(()=>{$=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 Q(n,e){let t=new Map,r=null,i=null,o=new Promise((d,y)=>{r=d,i=y;});o.catch(()=>{});let s=[],a=null,l="",p="";function u(d,...y){let g=t.get(d);g&&g.forEach(f=>f(...y));}async function*h(){try{for await(let d of n)if(yield d,d.type==="content_block_start")s[d.index]=d.content_block;else if(d.type==="content_block_delta"){let y=s[d.index];y&&d.delta?.type==="text_delta"&&(y.text=(y.text||"")+d.delta.text,u("text",d.delta.text));}else if(d.type==="message_start")l=d.message?.model||"",a=d.message?.usage;else if(d.type==="message_delta")p=d.delta?.stop_reason||"",d.usage&&(a={...a,...d.usage});else if(d.type==="message_stop"){let y={role:"assistant",model:l,content:s.filter(Boolean),usage:a,stop_reason:p};u("message",y),r&&(r(y),r=null),e&&e(y);}if(r){let d={role:"assistant",model:l,content:s.filter(Boolean),usage:a,stop_reason:p||"end_turn"};u("message",d),r(d),r=null,e&&e(d);}}catch(d){throw u("error",d),i&&(i(d),i=null),d}}let m=h(),c=false,b={[Symbol.asyncIterator](){if(c)throw new Error("[inference-relay] RelayStream can only be iterated once");return c=true,m},on(d,y){return t.has(d)||t.set(d,[]),t.get(d).push(y),b},finalMessage(){let d,y=new Promise((g,f)=>{d=setTimeout(()=>f(new Error("[inference-relay] finalMessage() timed out \u2014 no message_stop received after 5 minutes")),3e5);});return Promise.race([o,y]).finally(()=>clearTimeout(d))}};return b}var Ee=v(()=>{});var P,Y=v(()=>{Ee();P=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 Q(await this.streamRaw(e,t))}};});function He(){It.clearCache();}var be,Fe,W,It,ve=v(()=>{be=`-----BEGIN PUBLIC KEY-----
|
|
4
4
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzk88Bt9LZSmuSd8ulKqy
|
|
5
5
|
EGNiPB+r8u1ZinBvMM4qX8dp4kzJEC/47L1RYrrxCphD05HToREjljbj+upH6rZH
|
|
6
6
|
t6D/5funYPi2TO1IOSC6BRVRwMqqTmJGVJcLcG/WF3gTE+2UQ3q5EppWJCEKcz6x
|
|
@@ -8,12 +8,12 @@ kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
|
|
|
8
8
|
7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
|
|
9
9
|
Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
|
|
10
10
|
UQIDAQAB
|
|
11
|
-
-----END PUBLIC KEY-----`,Fe={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>"},W=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),i=await r(be,"RS256"),{payload:o}=await t(e,i),s=JSON.parse(new TextDecoder().decode(o));return this.verificationFailures=0,this.cachedManifest=s,this.currentSecurityState="SEC_NOMINAL",{manifest:s,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:Fe,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:Fe,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},It=new W;});function I(n,...e){process.env.IR_DEBUG==="1"&&console.error(`[ir-debug:${n}]`,...e);}var Ce=v(()=>{});function ke(n){return join(homedir(),".inference-relay","gateway",n)}function Ve(n){return join(ke(n),"bundle.js")}function Ge(n){return join(ke(n),"meta.json")}function Ot(n){let e=(r,i)=>{if(!Array.isArray(r)||r.length===0)return null;let o=[];for(let s of r){let a=typeof s=="string"?Number(s):s;if(typeof a!="number"||!Number.isFinite(a)||a<0)return I("loader.retry-config-invalid",{source:i,badValue:s}),null;o.push(a);}return o};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(i=>i.trim()),"env");if(r)return r}return Mt}var Dt,C,N,K,Mt,Z,we=v(()=>{ve();Ce();Dt=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";C=class extends Error{constructor(t,r,i){super(t);this.code=r;this.cause=i;this.name="GatewayLoaderError";}code;cause},N=class extends C{constructor(e,t){super(e,"GATEWAY_FETCH_FAILED",t);}},K=new Map,Mt=[0,1e3,4e3];Z=class{static async load(e,t,r=Dt,i){let o=`${t}:${e.slice(-8)}`;if(K.has(o))return K.get(o);try{let m=await this.tryLoadFromDisk(t);if(m)return I("loader.cache-hit",{libraryVersion:t}),K.set(o,m),m}catch{}I("loader.cache-miss",{libraryVersion:t});let{bytes:s,sha256:a,signature:l,libraryVersion:p}=await this.fetchFromAuthority(e,t,r,i);if(createHash("sha256").update(s).digest("hex")!==a)throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,p,a);try{let m=ke(t);mkdirSync(m,{recursive:!0}),writeFileSync(Ve(t),s),writeFileSync(Ge(t),JSON.stringify({sha256:a,signature:l,libraryVersion:p}));}catch{}let h=this.loadIntoVm(s.toString("utf-8"));return K.set(o,h),h}static async loadFromDisk(e){if(!existsSync(e))throw new C(`[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=Ve(e),r=Ge(e);if(!existsSync(t)||!existsSync(r))return null;let i=readFileSync(t),o=JSON.parse(readFileSync(r,"utf-8"));return createHash("sha256").update(i).digest("hex")!==o.sha256?null:(await this.verifySignature(o.signature,o.libraryVersion,o.sha256),this.loadIntoVm(i.toString("utf-8")))}static async fetchFromAuthority(e,t,r,i){let o,s=Ot(i?.retryDelaysMs),a;for(let h=0;h<s.length;h++){let m=s[h];m>0&&await new Promise(c=>setTimeout(c,m)),I("loader.fetch",{url:`${r}/v1/gateway/fetch`,libraryVersion:t,attempt:h+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(I("loader.fetch-result",{status:c.status,attempt:h+1}),c.status===401||c.status===403)throw new C("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(c.status>=500&&c.status<600){a=new N(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${c.status})`);continue}if(!c.ok)throw new N(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${c.status})`);o=await c.json(),a=null;break}catch(c){if(c instanceof C&&c.code==="LICENSE_REJECTED")throw c;a=c;}}if(a||!o)throw a instanceof C?a:new N("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)",a);let l;try{l=await fetch(o.bundleUrl);}catch(h){throw new N("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)",h)}if(!l.ok)throw new N(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${l.status})`);let p=await l.arrayBuffer();return {bytes:Buffer.from(p),sha256:o.sha256,signature:o.signature,libraryVersion:o.libraryVersion,bundleVersion:o.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:i,importSPKI:o}=await import('jose'),s=await o(be,"RS256"),{payload:a}=await i(e,s),l=JSON.parse(new TextDecoder().decode(a));if(l.purpose!=="gateway-bundle")throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(i){throw i instanceof C?i:new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",i)}}static loadIntoVm(e){try{let t=join(homedir(),".inference-relay","gateway","runtime.cjs"),r=dirname(t),i=createRequire(t),o={exports:{}};compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(o.exports,i,o,t,r);let a=o.exports;if(!a.ClaudeCLIProvider)throw new C("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return a}catch(t){throw t instanceof C?t:new C("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){K.clear();}};});var We={};Ne(We,{detectCLI:()=>H});function Bt(n){let e=process.env.PATH;if(!e)return null;let t=process.platform==="win32",r=t?";":":",i=t?(process.env.PATHEXT??".COM;.EXE;.BAT;.CMD").split(";").map(o=>o.toLowerCase()):[""];for(let o of e.split(r))if(o)for(let s of i){let a=join(o,n+s);if(existsSync(a))return a}return null}async function H(){if(!Bt("claude"))return {available:false,authenticated:false};let e=null;try{let r=execSync("claude --version",{encoding:"utf-8",timeout:5e3}).trim(),i=r.match(/(\d+\.\d+\.\d+)/);e=i?i[1]:r;}catch{}let t;return e&&!$t.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 $t,te=v(()=>{$t=["2.1.87"];});var Ht,ne,Ke=v(()=>{Y();we();Ht="1.6.3",ne=class extends P{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 Z.load(this.licenseKey,Ht,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 C?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(()=>(te(),We));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,i=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(i*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};});function je(n){return re[n]||n}function Te(n){return qe.find(e=>e.canonical===n)?.provider}var qe,re,Ie=v(()=>{qe=[{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}}],re=Object.fromEntries(qe.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));re["claude-sonnet-4"]="claude-sonnet-4-20250514";re["claude-opus-4"]="claude-opus-4-20250514";re["claude-haiku-4"]="claude-haiku-4-5-20251001";});function Je(n){if(Se[n])return Se[n];for(let[e,t]of Object.entries(Se))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Vt,Gt,Se,se,ze=v(()=>{Y();Ie();Vt="https://api.anthropic.com/v1/messages",Gt="2023-06-01",Se={"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]};se=class extends P{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(/\/$/,"")||Vt,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(),i=this.buildRequestBody(e,false),o=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(i),signal:t?.signal});if(!o.ok)throw this.handleErrorResponse(o),new Error("unreachable");let s=await o.json(),a=Date.now()-r;this.recordSuccess();let[l,p]=Je(s.model||e.model),u=((s.usage?.input_tokens||0)*l+(s.usage?.output_tokens||0)*p)/1e6,h={},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 b=o.headers.get(c);b&&(h[c]=b);}return {content:s.content||[],model:s.model||e.model,usage:{input_tokens:s.usage?.input_tokens||0,output_tokens:s.usage?.output_tokens||0},stop_reason:s.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(u*1e6)/1e6,durationMs:a,fallbackChain:["anthropic-api:success"],headers:Object.keys(h).length>0?h:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(i.ok||this.handleErrorResponse(i),!i.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let o=i.body.getReader(),s=new TextDecoder;return (async function*(){let a="",l=false;try{for(;;){let{done:p,value:u}=await o.read();if(p)break;a+=s.decode(u,{stream:!0});let h=a.split(`
|
|
11
|
+
-----END PUBLIC KEY-----`,Fe={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>"},W=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),i=await r(be,"RS256"),{payload:o}=await t(e,i),s=JSON.parse(new TextDecoder().decode(o));return this.verificationFailures=0,this.cachedManifest=s,this.currentSecurityState="SEC_NOMINAL",{manifest:s,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:Fe,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:Fe,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},It=new W;});function I(n,...e){process.env.IR_DEBUG==="1"&&console.error(`[ir-debug:${n}]`,...e);}var Ce=v(()=>{});function ke(n){return join(homedir(),".inference-relay","gateway",n)}function Ve(n){return join(ke(n),"bundle.js")}function Ge(n){return join(ke(n),"meta.json")}function Ot(n){let e=(r,i)=>{if(!Array.isArray(r)||r.length===0)return null;let o=[];for(let s of r){let a=typeof s=="string"?Number(s):s;if(typeof a!="number"||!Number.isFinite(a)||a<0)return I("loader.retry-config-invalid",{source:i,badValue:s}),null;o.push(a);}return o};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(i=>i.trim()),"env");if(r)return r}return Mt}var Dt,C,N,K,Mt,Z,we=v(()=>{ve();Ce();Dt=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";C=class extends Error{constructor(t,r,i){super(t);this.code=r;this.cause=i;this.name="GatewayLoaderError";}code;cause},N=class extends C{constructor(e,t){super(e,"GATEWAY_FETCH_FAILED",t);}},K=new Map,Mt=[0,1e3,4e3];Z=class{static async load(e,t,r=Dt,i){let o=`${t}:${e.slice(-8)}`;if(K.has(o))return K.get(o);try{let m=await this.tryLoadFromDisk(t);if(m)return I("loader.cache-hit",{libraryVersion:t}),K.set(o,m),m}catch{}I("loader.cache-miss",{libraryVersion:t});let{bytes:s,sha256:a,signature:l,libraryVersion:p}=await this.fetchFromAuthority(e,t,r,i);if(createHash("sha256").update(s).digest("hex")!==a)throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,p,a);try{let m=ke(t);mkdirSync(m,{recursive:!0}),writeFileSync(Ve(t),s),writeFileSync(Ge(t),JSON.stringify({sha256:a,signature:l,libraryVersion:p}));}catch{}let h=this.loadIntoVm(s.toString("utf-8"));return K.set(o,h),h}static async loadFromDisk(e){if(!existsSync(e))throw new C(`[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=Ve(e),r=Ge(e);if(!existsSync(t)||!existsSync(r))return null;let i=readFileSync(t),o=JSON.parse(readFileSync(r,"utf-8"));return createHash("sha256").update(i).digest("hex")!==o.sha256?null:(await this.verifySignature(o.signature,o.libraryVersion,o.sha256),this.loadIntoVm(i.toString("utf-8")))}static async fetchFromAuthority(e,t,r,i){let o,s=Ot(i?.retryDelaysMs),a;for(let h=0;h<s.length;h++){let m=s[h];m>0&&await new Promise(c=>setTimeout(c,m)),I("loader.fetch",{url:`${r}/v1/gateway/fetch`,libraryVersion:t,attempt:h+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(I("loader.fetch-result",{status:c.status,attempt:h+1}),c.status===401||c.status===403)throw new C("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(c.status>=500&&c.status<600){a=new N(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${c.status})`);continue}if(!c.ok)throw new N(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${c.status})`);o=await c.json(),a=null;break}catch(c){if(c instanceof C&&c.code==="LICENSE_REJECTED")throw c;a=c;}}if(a||!o)throw a instanceof C?a:new N("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)",a);let l;try{l=await fetch(o.bundleUrl);}catch(h){throw new N("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)",h)}if(!l.ok)throw new N(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${l.status})`);let p=await l.arrayBuffer();return {bytes:Buffer.from(p),sha256:o.sha256,signature:o.signature,libraryVersion:o.libraryVersion,bundleVersion:o.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:i,importSPKI:o}=await import('jose'),s=await o(be,"RS256"),{payload:a}=await i(e,s),l=JSON.parse(new TextDecoder().decode(a));if(l.purpose!=="gateway-bundle")throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(i){throw i instanceof C?i:new C("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",i)}}static loadIntoVm(e){try{let t=join(homedir(),".inference-relay","gateway","runtime.cjs"),r=dirname(t),i=createRequire(t),o={exports:{}};compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(o.exports,i,o,t,r);let a=o.exports;if(!a.ClaudeCLIProvider)throw new C("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return a}catch(t){throw t instanceof C?t:new C("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){K.clear();}};});var We={};Ne(We,{detectCLI:()=>B});function $t(n){let e=process.env.PATH;if(!e)return null;let t=process.platform==="win32",r=t?";":":",i=t?(process.env.PATHEXT??".COM;.EXE;.BAT;.CMD").split(";").map(o=>o.toLowerCase()):[""];for(let o of e.split(r))if(o)for(let s of i){let a=join(o,n+s);if(existsSync(a))return a}return null}async function B(){if(!$t("claude"))return {available:false,authenticated:false};let e=null;try{let r=execSync("claude --version",{encoding:"utf-8",timeout:5e3}).trim(),i=r.match(/(\d+\.\d+\.\d+)/);e=i?i[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,te=v(()=>{Ht=["2.1.87"];});var Bt,ne,Ke=v(()=>{Y();we();Bt="1.6.4",ne=class extends P{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 Z.load(this.licenseKey,Bt,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 C?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(()=>(te(),We));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,i=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(i*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};});function je(n){return re[n]||n}function Te(n){return qe.find(e=>e.canonical===n)?.provider}var qe,re,Ie=v(()=>{qe=[{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}}],re=Object.fromEntries(qe.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));re["claude-sonnet-4"]="claude-sonnet-4-20250514";re["claude-opus-4"]="claude-opus-4-20250514";re["claude-haiku-4"]="claude-haiku-4-5-20251001";});function Je(n){if(Se[n])return Se[n];for(let[e,t]of Object.entries(Se))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Vt,Gt,Se,se,ze=v(()=>{Y();Ie();Vt="https://api.anthropic.com/v1/messages",Gt="2023-06-01",Se={"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]};se=class extends P{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(/\/$/,"")||Vt,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(),i=this.buildRequestBody(e,false),o=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(i),signal:t?.signal});if(!o.ok)throw this.handleErrorResponse(o),new Error("unreachable");let s=await o.json(),a=Date.now()-r;this.recordSuccess();let[l,p]=Je(s.model||e.model),u=((s.usage?.input_tokens||0)*l+(s.usage?.output_tokens||0)*p)/1e6,h={},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 b=o.headers.get(c);b&&(h[c]=b);}return {content:s.content||[],model:s.model||e.model,usage:{input_tokens:s.usage?.input_tokens||0,output_tokens:s.usage?.output_tokens||0},stop_reason:s.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(u*1e6)/1e6,durationMs:a,fallbackChain:["anthropic-api:success"],headers:Object.keys(h).length>0?h:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(i.ok||this.handleErrorResponse(i),!i.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let o=i.body.getReader(),s=new TextDecoder;return (async function*(){let a="",l=false;try{for(;;){let{done:p,value:u}=await o.read();if(p)break;a+=s.decode(u,{stream:!0});let h=a.split(`
|
|
12
12
|
`);a=h.pop()||"";let m=null;for(let c of h)if(c.startsWith("event: "))m=c.slice(7).trim();else if(c.startsWith("data: ")){let b=c.slice(6);if(m&&b)try{let d=JSON.parse(b);d.type==="message_stop"&&(l=!0),yield d;}catch{console.warn("[inference-relay] Skipped malformed SSE data:",b.substring(0,100));}m=null;}else c.trim()===""&&(m=null);}l||(yield {type:"message_stop"});}finally{try{o.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,i=t+r,[o,s]=Je(e.model),a=(i*o+1e3*s)/1e6;return {estimatedInputTokens:i,estimatedCost:Math.round(a*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:je(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"),i=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${i}ms`,this.health.lastCheckAt=Date.now();let o=new Error(`ANTHROPIC_RATE_LIMIT: Too many requests (429). Retry after ${i}ms`);throw o.retryAfterMs=i,o}throw t===529?(this.health.status="degraded",this.health.lastError="API overloaded",this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_OVERLOADED: API is temporarily overloaded (529)")):(this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`ANTHROPIC_API_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};});function Qe(n){if(Pe[n])return Pe[n];for(let[e,t]of Object.entries(Pe))if(n.startsWith(e))return t;return [2.5,10]}function Wt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Kt(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n){let i=Wt(r.content);if(r.role==="assistant"&&Array.isArray(r.content)){let o=r.content.filter(s=>s.type==="tool_use");if(o.length>0){t.push({role:"assistant",content:i||"",tool_calls:o.map(s=>({id:s.id||`call_${Math.random().toString(36).slice(2)}`,type:"function",function:{name:s.name,arguments:typeof s.input=="string"?s.input:JSON.stringify(s.input)}}))});continue}}t.push({role:r.role,content:i});}return t}function Ze(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 Yt,Xe,Pe,ie,et=v(()=>{Y();Yt="https://api.openai.com/v1/chat/completions",Xe=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],Pe={"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]};ie=class extends P{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(/\/$/,"")||Yt;}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(),i=this.buildRequestBody(e,false),o=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(i),signal:t?.signal});if(!o.ok)throw this.handleErrorResponse(o),new Error("unreachable");let s=await o.json(),a=Date.now()-r;this.recordSuccess();let l=s.choices?.[0],p=[];if(l?.message?.content&&p.push({type:"text",text:l.message.content}),l?.message?.tool_calls)for(let g of l.message.tool_calls)p.push({type:"tool_use",id:g.id,name:g.function?.name,input:g.function?.arguments?JSON.parse(g.function.arguments):{}});let u=s.usage?.prompt_tokens||0,h=s.usage?.completion_tokens||0,[m,c]=Qe(s.model||e.model),b=(u*m+h*c)/1e6,d={},y=["x-request-id","x-ratelimit-limit-requests","x-ratelimit-remaining-requests","x-ratelimit-limit-tokens","x-ratelimit-remaining-tokens","x-ratelimit-reset-requests","x-ratelimit-reset-tokens"];for(let g of y){let f=o.headers.get(g);f&&(d[g]=f);}return {content:p,model:s.model||e.model,usage:{input_tokens:u,output_tokens:h},stop_reason:Ze(l?.finish_reason),provider:"openai-api",costUsd:Math.round(b*1e6)/1e6,durationMs:a,fallbackChain:["openai-api:success"],headers:Object.keys(d).length>0?d:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),i=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(i.ok||this.handleErrorResponse(i),!i.body)throw new Error("OPENAI_API_ERROR: Response body is null \u2014 streaming unavailable");let o=i.body.getReader(),s=new TextDecoder,a=e.model;return (async function*(){let l="",p=false,u=false,h,m;yield {type:"message_start",message:{model:a,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:c,value:b}=await o.read();if(c)break;l+=s.decode(b,{stream:!0});let d=l.split(`
|
|
13
13
|
`);l=d.pop()||"";for(let y of d){if(!y.startsWith("data: "))continue;let g=y.slice(6).trim();if(g==="[DONE]"){yield {type:"message_delta",delta:{stop_reason:m||"end_turn"},usage:h||{}},yield {type:"message_stop"},u=!0;return}try{let f=JSON.parse(g);f.usage&&(h={input_tokens:f.usage.prompt_tokens||0,output_tokens:f.usage.completion_tokens||0});let R=f.choices?.[0];if(!R)continue;let E=R.delta;E?.content&&!p&&(p=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),E?.content&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:E.content}}),R.finish_reason&&(p&&(yield {type:"content_block_stop",index:0}),m=Ze(R.finish_reason));}catch{}}}u||(yield {type:"message_delta",delta:{stop_reason:m||"end_turn"},usage:h||{}},yield {type:"message_stop"});}finally{try{o.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,i=t+r,[o,s]=Qe(e.model),a=(i*o+1e3*s)/1e6;return {estimatedInputTokens:i,estimatedCost:Math.round(a*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(!Xe.some(a=>r.startsWith(a)))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 (${Xe.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 o=Kt(e.messages,e.system),s={model:e.model,max_tokens:e.max_tokens,messages:o};return t&&(s.stream=true,s.stream_options={include_usage:true}),e.temperature!==void 0&&(s.temperature=e.temperature),e.tools&&e.tools.length>0&&(s.tools=e.tools),s}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"),i=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${i}ms`,this.health.lastCheckAt=Date.now();let o=new Error(`OPENAI_RATE_LIMIT: Too many requests (429). Retry after ${i}ms`);throw o.retryAfterMs=i,o}throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`OPENAI_API_ERROR: Request failed with status ${t}`)}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};});function jt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Jt(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:jt(r.content)});return t}var qt,oe,tt=v(()=>{Y();qt="http://localhost:11434";oe=class extends P{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(/\/$/,"")||qt;}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(),i=this.buildRequestBody(e,false),o=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i),signal:t?.signal});if(!o.ok)throw this.handleErrorResponse(o),new Error("unreachable");let s=await o.json(),a=Date.now()-r;this.recordSuccess();let l=[];s.message?.content&&l.push({type:"text",text:s.message.content});let p=s.prompt_eval_count||0,u=s.eval_count||0;return {content:l,model:s.model||e.model,usage:{input_tokens:p,output_tokens:u},stop_reason:(s.done,"end_turn"),provider:"ollama",costUsd:0,durationMs:a,fallbackChain:["ollama:success"]}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),i=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),signal:t?.signal});if(i.ok||this.handleErrorResponse(i),!i.body)throw new Error("OLLAMA_ERROR: Response body is null \u2014 streaming unavailable");let o=i.body.getReader(),s=new TextDecoder,a=e.model;return (async function*(){let l="",p=false,u=false;yield {type:"message_start",message:{model:a,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:h,value:m}=await o.read();if(h)break;l+=s.decode(m,{stream:!0});let c=l.split(`
|
|
14
|
-
`);l=c.pop()||"";for(let b of c){let d=b.trim();if(d)try{let y=JSON.parse(d);if(y.message?.content&&(p||(p=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:y.message.content}}),y.done){p&&(yield {type:"content_block_stop",index:0}),yield {type:"message_delta",delta:{stop_reason:"end_turn"},usage:{input_tokens:y.prompt_eval_count||0,output_tokens:y.eval_count||0}},yield {type:"message_stop"},u=!0;return}}catch{}}}u||(yield {type:"message_stop"});}finally{try{o.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=Jt(e.messages,e.system),i={model:e.model,messages:r,stream:t};return e.temperature!==void 0&&(i.options={temperature:e.temperature}),i}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 ae,nt=v(()=>{ae=class extends EventEmitter{constructor(){super(),this.setMaxListeners(50);}emitTyped(e){return this.emit(e.kind,e)}onTyped(e,t){return this.on(e,t)}offTyped(e,t){return this.off(e,t)}};});function le(n,e){if(e instanceof C)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,ut)||"unknown"}`}function rt(n){let e=n.filter(t=>t.includes(":failed:"));return e.length===0?false:e.every(t=>t.endsWith(":failed:request_too_large"))}function it(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
|
|
14
|
+
`);l=c.pop()||"";for(let b of c){let d=b.trim();if(d)try{let y=JSON.parse(d);if(y.message?.content&&(p||(p=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:y.message.content}}),y.done){p&&(yield {type:"content_block_stop",index:0}),yield {type:"message_delta",delta:{stop_reason:"end_turn"},usage:{input_tokens:y.prompt_eval_count||0,output_tokens:y.eval_count||0}},yield {type:"message_stop"},u=!0;return}}catch{}}}u||(yield {type:"message_stop"});}finally{try{o.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=Jt(e.messages,e.system),i={model:e.model,messages:r,stream:t};return e.temperature!==void 0&&(i.options={temperature:e.temperature}),i}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 ae,nt=v(()=>{ae=class extends EventEmitter{constructor(){super(),this.setMaxListeners(50);}emitTyped(e){return this.emit(e.kind,e)}onTyped(e,t){return this.on(e,t)}offTyped(e,t){return this.off(e,t)}};});function le(n,e){if(e instanceof C)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,ut)||"unknown"}`}function rt(n){let e=n.filter(t=>t.includes(":failed:"));return e.length===0?false:e.every(t=>t.endsWith(":failed:request_too_large"))}function it(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 Le(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.includes("prompt is too long")||t.includes("prompt too long")||t.includes("input length")||t.includes("input is too long")||t.includes("context_length_exceeded")||t.includes("context length exceeded")||t.includes("request too large")||t.includes("tokens exceed")||t.includes("exceeds the maximum")||t.includes("too many tokens")?"request_too_large":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 ot(n){return [...n].sort((e,t)=>e.priority-t.priority)}function at(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function Xt(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 lt(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function Qt(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 Zt(n,e,t,r,i){if(i&&n.type==="content_block_delta"&&n.index===i.fromIndex)return {action:"yield",event:{...n,index:i.toIndex}};if(i&&n.type==="content_block_stop"&&n.index===i.fromIndex)return {action:"suppress",coalesceMode:null,coalesceModeCleared:true};if(r&&n.type==="content_block_start"&&n.content_block?.type==="text"){let s=t.content[t.content.length-1];if(s?.type==="text"&&s.open===true)return {action:"suppress",coalesceMode:{fromIndex:n.index+e,toIndex:t.content.length-1},clearedJustFailedOver:true}}let o=r&&n.type==="content_block_start";return typeof n.index=="number"&&e>0?{action:"yield",event:{...n,index:n.index+e},clearedJustFailedOver:o}:{action:"yield",event:n,clearedJustFailedOver:o}}function en(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 tn(n,e){return n?`${n}
|
|
15
15
|
|
|
16
|
-
${e}`:e}function ct(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 nn(n){return Math.max(0,n.content.length-1)}async function*rn(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}var ut,st,F,ce,ue,Le=v(()=>{Ee();nt();Ie();we();Ce();ut=200;st=new Set(["anthropic-api","openai-api","ollama"]),F=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}},ce=class extends F{constructor(e){super(e);}};ue=class n{healthMap=new Map;engineEvents=new ae;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),I("engine.recovered",{providerType:e,ageMs:r}),"healthy"}return t.status}markUnhealthy(e,t){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now()}),I("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 i=ot(t),o=[],s=it(e),a=randomUUID(),l=Date.now();for(let p of i){let u=p.type;if(this.getHealthStatus(u)==="unhealthy"){o.push(`${u}:skipped:unhealthy`);continue}if(s&&!p.supportsMultimodal){o.push(`${u}:skipped:no_multimodal`);continue}let m=Te(e.model);if(m&&m!==u&&st.has(u)){o.push(`${u}:skipped:wrong_provider`);continue}try{let c=await p.execute(e,{signal:r?.signal});return this.markHealthy(u),o.push(`${u}:success`),this.emitEngineEvent({kind:"stream_complete",callId:a,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:o,rateLimitHit:!1,securityState:r?.licenseState}),{...c,fallbackChain:o}}catch(c){if(c?.name==="AbortError"||r?.signal?.aborted)throw c;switch(xe(c)){case "rate_limited":p.reportRateLimit({provider:u,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(u,"rate_limited"),o.push(`${u}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(u,"auth_failed"),o.push(`${u}:failed:auth_failed`);break;case "timeout":o.push(`${u}:failed:timeout`);break;case "provider_incompatible":o.push(`${u}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(u,"gateway_unavailable"),o.push(le(u,c));break;case "request_too_large":o.push(`${u}:failed:request_too_large`);break;default:o.push(le(u,c));break}}}throw I("engine.cascade-exhausted",{chain:o,mode:"execute"}),rt(o)?new ce(o):new F(o)}async stream(e,t,r){let i=randomUUID(),o=ot(t),s=it(e),a=Date.now(),l=[],p=null,u=null;for(let g of o){let f=g.type;if(this.getHealthStatus(f)==="unhealthy"){l.push(`${f}:skipped:unhealthy`);continue}if(s&&!g.supportsMultimodal){l.push(`${f}:skipped:no_multimodal`);continue}if(!g.supportsStreaming){l.push(`${f}:skipped:no_streaming`);continue}let R=Te(e.model);if(R&&R!==f&&st.has(f)){l.push(`${f}:skipped:wrong_provider`);continue}try{u=await g.streamRaw(e,{signal:r?.signal}),p=g,l.push(`${f}:success`);break}catch(E){if(E?.name==="AbortError"||r?.signal?.aborted)throw E;switch(xe(E)){case "rate_limited":g.reportRateLimit({provider:f,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(f,"rate_limited"),l.push(`${f}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(f,"auth_failed"),l.push(`${f}:failed:auth_failed`);break;case "timeout":l.push(`${f}:failed:timeout`);break;case "provider_incompatible":l.push(`${f}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(f,"gateway_unavailable"),l.push(le(f,E));break;case "request_too_large":l.push(`${f}:failed:request_too_large`);break;default:l.push(le(f,E));break}}}if(!p||!u)throw I("engine.cascade-exhausted",{chain:l,mode:"stream"}),rt(l)?new ce(l):new F(l);let m=this,c=r?.maxMidStreamFailovers??2,b=new Set([p]);async function*d(){let g=p,f=u[Symbol.asyncIterator](),R={role:"assistant",content:[]},E={segments:[]},k=at(g.type);E.segments.push(k);let Me=0,J=null,z=false,ye=c,V="",G="";for(m.emitEngineEvent({kind:"segment_start",callId:i,id:randomUUID(),ts:Date.now(),provider:g.type});;)try{for(;;){let T=await f.next();if(T.done)break;let U=T.value,L=Zt(U,Me,R,z,J);if(L.action==="suppress"){"coalesceMode"in L&&(J=L.coalesceMode),L.clearedJustFailedOver&&(z=!1);continue}L.coalesceModeCleared&&(J=null),L.clearedJustFailedOver&&(z=!1);let A=L.event;if(Qt(R,A),A.type==="message_start"){if(E.segments.length>1)continue;V=A.message?.model||V,A.message?.usage?.input_tokens!=null&&(k.inputTokens=A.message.usage.input_tokens);}if(A.type==="message_delta"&&(A.delta?.stop_reason&&(G=A.delta.stop_reason),A.usage)){Xt(k,g.type,A.usage),yield {...A,usage:void 0};continue}if(A.type==="message_stop")break;yield A;}if(R.content.length===0&&k.outputTokens===0)throw new Error("stream ended without producing any content");m.markHealthy(g.type),m.emitEngineEvent({kind:"segment_complete",callId:i,id:randomUUID(),ts:Date.now(),provider:g.type,usage:{...k}});let S=lt(E.segments);yield {type:"message_delta",delta:{stop_reason:G||"end_turn"},usage:S},yield {type:"message_stop"},m.emitEngineEvent({kind:"stream_complete",callId:i,id:randomUUID(),ts:Date.now(),stitched:E.segments.length>1,segments:E.segments.map(T=>({...T})),provider:E.segments.map(T=>T.provider).join("+"),model:V,inputTokens:S.input_tokens,outputTokens:S.output_tokens,costUsd:E.segments.reduce((T,U)=>T+U.costUsd,0),userCostUsd:E.segments.reduce((T,U)=>T+U.userCostUsd,0),durationMs:Date.now()-a,stopReason:G||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(S){if(S?.name==="AbortError"||r?.signal?.aborted)throw S;let T=xe(S);try{await f.return?.();}catch{}if(m.markUnhealthy(g.type,String(S)),m.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:i,id:randomUUID(),ts:Date.now(),from:g.type,bytesBuffered:ct(R),errorClass:T,retriesLeft:ye}),l.push(`${g.type}:partial(${ct(R)}b)`),ye<=0)throw m.emitTerminalExhaustion(i,E,V,G,l,a,r?.licenseState),S;let U=en(R.content),L=[...e.messages,{role:"assistant",content:U}],A=null,X=null,Oe=g;for(;;){let D=m.nextHealthyProvider(o,Oe,s,b);if(!D)break;Oe=D,b.add(D);let wt={...e,messages:L,...D.type!=="anthropic-api"&&D.type!=="claude-cli"?{system:tn(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{X=await D.streamRaw(wt,{signal:r?.signal}),A=D;break}catch(Ue){m.markUnhealthy(D.type,String(Ue)),l.push(`${D.type}:failed_connect:${String(Ue).slice(0,ut)}`);}}if(!A||!X)throw m.emitTerminalExhaustion(i,E,V,G,l,a,r?.licenseState),S;l.push(`${A.type}:stitched`),m.emitEngineEvent({kind:"mid_stream_failover_success",callId:i,id:randomUUID(),ts:Date.now(),from:g.type,to:A.type}),Me=nn(R)+1,ye--,g=A,f=X[Symbol.asyncIterator](),z=true,J=null,k=at(g.type),E.segments.push(k),m.emitEngineEvent({kind:"segment_start",callId:i,id:randomUUID(),ts:Date.now(),provider:g.type});}}let y=d();return r?.licenseState==="SEC_DEGRADED"&&(y=rn(y)),Q(y)}nextHealthyProvider(e,t,r,i){let o=e.indexOf(t);if(o===-1)return null;for(let s=o+1;s<e.length;s++){let a=e[s];if(!i.has(a)&&!(r&&!a.supportsMultimodal)&&a.supportsStreaming)return a}return null}emitEngineEvent(e){this.engineEvents.emitTyped(e);}emitTerminalExhaustion(e,t,r,i,o,s,a){let l=lt(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()-s,stopReason:i||"error",fallbackChain:o,rateLimitHit:false,securityState:a});}};});function dt(n,e){if(e==="prefer-user"){let i=n.filter(s=>s.type==="claude-cli"),o=n.filter(s=>s.type!=="claude-cli");return [...i,...o]}if(e==="prefer-app"){let i=n.filter(s=>s.type==="claude-cli");return [...n.filter(s=>s.type!=="claude-cli"),...i]}let t=n.filter(i=>i.type===e),r=n.filter(i=>i.type!==e);return [...t,...r]}function pt(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var mt=v(()=>{});function ht(n){if(De[n])return De[n];for(let[e,t]of Object.entries(De))if(n.startsWith(e))return t;return [3,15]}var De,gt=v(()=>{De={"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 ft(n){let e=0;for(let a of n.messages)if(typeof a.content=="string")e+=a.content.length;else if(Array.isArray(a.content))for(let l of a.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),[i,o]=ht(n.model),s=(t*i+r*o)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(s*1e4)/1e4,model:n.model,provider:""}}var yt=v(()=>{gt();});var de,_t=v(()=>{de=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=i=>this.bufferLineageEvent(i),r=i=>{i.kind==="stream_complete"&&this.flushLineageForCall(i);};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(i=>i.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(()=>{});}};});async function pe(n,e){if(!n)return {valid:false,error:"License key required. Get one at inference-relay.com"};let t=$.get(n);if(t&&Date.now()-t.cachedAt<t.ttl)return t.result;let r=new AbortController,o=!$.has(n)?3e3:1e3,s=setTimeout(()=>r.abort(),o),a;try{let p=(e||sn)+on;a=await(await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:n}),signal:r.signal})).json();}catch{return clearTimeout(s),t&&Date.now()-t.cachedAt<ln?t.result:{valid:false,error:"License validation failed (network error). Visit inference-relay.com"}}clearTimeout(s);let l;if(a.jws)try{let{compactVerify:p,importSPKI:u}=await import('jose'),h=await u(cn,"RS256"),{payload:m}=await p(a.jws,h);l=JSON.parse(new TextDecoder().decode(m));}catch{return $.delete(n),{valid:false,error:"License validation signature invalid. Possible MITM \u2014 refusing to start."}}else if(l=a,l.valid)return $.delete(n),{valid:false,error:"License validation response not signed. Possible MITM."};return $.set(n,{result:l,cachedAt:Date.now(),ttl:l.valid?an:6e4}),l}var sn,on,an,ln,cn,$,me,Et=v(()=>{_e();Ke();ze();et();tt();Le();te();mt();yt();ve();_t();sn="https://api.inference-relay.com",on="/v1/validate",an=1440*60*1e3,ln=10080*60*1e3,cn=`-----BEGIN PUBLIC KEY-----
|
|
16
|
+
${e}`:e}function ct(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 nn(n){return Math.max(0,n.content.length-1)}async function*rn(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}var ut,st,F,ce,ue,xe=v(()=>{Ee();nt();Ie();we();Ce();ut=200;st=new Set(["anthropic-api","openai-api","ollama"]),F=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}},ce=class extends F{constructor(e){super(e);}};ue=class n{healthMap=new Map;engineEvents=new ae;static UNHEALTHY_TTL_DEFAULT_MS=300*1e3;static UNHEALTHY_TTL_AUTH_MS=30*1e3;getHealthStatus(e){let t=this.healthMap.get(e);if(!t)return "healthy";let r=t.ttlMs??n.UNHEALTHY_TTL_DEFAULT_MS;if(t.status==="unhealthy"&&Date.now()-t.updatedAt>=r){let i=Date.now()-t.updatedAt;return this.healthMap.delete(e),I("engine.recovered",{providerType:e,ageMs:i,ttlMs:r}),"healthy"}return t.status}markUnhealthy(e,t,r){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now(),ttlMs:r}),I("engine.unhealthy",{providerType:e,reason:t,ttlMs:r});}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 i=ot(t),o=[],s=it(e),a=randomUUID(),l=Date.now();for(let p of i){let u=p.type;if(this.getHealthStatus(u)==="unhealthy"){o.push(`${u}:skipped:unhealthy`);continue}if(s&&!p.supportsMultimodal){o.push(`${u}:skipped:no_multimodal`);continue}let m=Te(e.model);if(m&&m!==u&&st.has(u)){o.push(`${u}:skipped:wrong_provider`);continue}try{let c=await p.execute(e,{signal:r?.signal});return this.markHealthy(u),o.push(`${u}:success`),this.emitEngineEvent({kind:"stream_complete",callId:a,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:o,rateLimitHit:!1,securityState:r?.licenseState}),{...c,fallbackChain:o}}catch(c){if(c?.name==="AbortError"||r?.signal?.aborted)throw c;switch(Le(c)){case "rate_limited":p.reportRateLimit({provider:u,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(u,"rate_limited"),o.push(`${u}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(u,"auth_failed",n.UNHEALTHY_TTL_AUTH_MS),o.push(`${u}:failed:auth_failed`);break;case "timeout":o.push(`${u}:failed:timeout`);break;case "provider_incompatible":o.push(`${u}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(u,"gateway_unavailable"),o.push(le(u,c));break;case "request_too_large":o.push(`${u}:failed:request_too_large`);break;default:o.push(le(u,c));break}}}throw I("engine.cascade-exhausted",{chain:o,mode:"execute"}),rt(o)?new ce(o):new F(o)}async stream(e,t,r){let i=randomUUID(),o=ot(t),s=it(e),a=Date.now(),l=[],p=null,u=null;for(let g of o){let f=g.type;if(this.getHealthStatus(f)==="unhealthy"){l.push(`${f}:skipped:unhealthy`);continue}if(s&&!g.supportsMultimodal){l.push(`${f}:skipped:no_multimodal`);continue}if(!g.supportsStreaming){l.push(`${f}:skipped:no_streaming`);continue}let R=Te(e.model);if(R&&R!==f&&st.has(f)){l.push(`${f}:skipped:wrong_provider`);continue}try{u=await g.streamRaw(e,{signal:r?.signal}),p=g,l.push(`${f}:success`);break}catch(E){if(E?.name==="AbortError"||r?.signal?.aborted)throw E;switch(Le(E)){case "rate_limited":g.reportRateLimit({provider:f,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(f,"rate_limited"),l.push(`${f}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(f,"auth_failed",n.UNHEALTHY_TTL_AUTH_MS),l.push(`${f}:failed:auth_failed`);break;case "timeout":l.push(`${f}:failed:timeout`);break;case "provider_incompatible":l.push(`${f}:incompatible`);break;case "gateway_unavailable":this.markUnhealthy(f,"gateway_unavailable"),l.push(le(f,E));break;case "request_too_large":l.push(`${f}:failed:request_too_large`);break;default:l.push(le(f,E));break}}}if(!p||!u)throw I("engine.cascade-exhausted",{chain:l,mode:"stream"}),rt(l)?new ce(l):new F(l);let m=this,c=r?.maxMidStreamFailovers??2,b=new Set([p]);async function*d(){let g=p,f=u[Symbol.asyncIterator](),R={role:"assistant",content:[]},E={segments:[]},k=at(g.type);E.segments.push(k);let Me=0,J=null,z=false,ye=c,V="",G="";for(m.emitEngineEvent({kind:"segment_start",callId:i,id:randomUUID(),ts:Date.now(),provider:g.type});;)try{for(;;){let T=await f.next();if(T.done)break;let U=T.value,x=Zt(U,Me,R,z,J);if(x.action==="suppress"){"coalesceMode"in x&&(J=x.coalesceMode),x.clearedJustFailedOver&&(z=!1);continue}x.coalesceModeCleared&&(J=null),x.clearedJustFailedOver&&(z=!1);let A=x.event;if(Qt(R,A),A.type==="message_start"){if(E.segments.length>1)continue;V=A.message?.model||V,A.message?.usage?.input_tokens!=null&&(k.inputTokens=A.message.usage.input_tokens);}if(A.type==="message_delta"&&(A.delta?.stop_reason&&(G=A.delta.stop_reason),A.usage)){Xt(k,g.type,A.usage),yield {...A,usage:void 0};continue}if(A.type==="message_stop")break;yield A;}if(R.content.length===0&&k.outputTokens===0)throw new Error("stream ended without producing any content");m.markHealthy(g.type),m.emitEngineEvent({kind:"segment_complete",callId:i,id:randomUUID(),ts:Date.now(),provider:g.type,usage:{...k}});let S=lt(E.segments);yield {type:"message_delta",delta:{stop_reason:G||"end_turn"},usage:S},yield {type:"message_stop"},m.emitEngineEvent({kind:"stream_complete",callId:i,id:randomUUID(),ts:Date.now(),stitched:E.segments.length>1,segments:E.segments.map(T=>({...T})),provider:E.segments.map(T=>T.provider).join("+"),model:V,inputTokens:S.input_tokens,outputTokens:S.output_tokens,costUsd:E.segments.reduce((T,U)=>T+U.costUsd,0),userCostUsd:E.segments.reduce((T,U)=>T+U.userCostUsd,0),durationMs:Date.now()-a,stopReason:G||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(S){if(S?.name==="AbortError"||r?.signal?.aborted)throw S;let T=Le(S);try{await f.return?.();}catch{}if(m.markUnhealthy(g.type,String(S)),m.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:i,id:randomUUID(),ts:Date.now(),from:g.type,bytesBuffered:ct(R),errorClass:T,retriesLeft:ye}),l.push(`${g.type}:partial(${ct(R)}b)`),ye<=0)throw m.emitTerminalExhaustion(i,E,V,G,l,a,r?.licenseState),S;let U=en(R.content),x=[...e.messages,{role:"assistant",content:U}],A=null,X=null,Oe=g;for(;;){let D=m.nextHealthyProvider(o,Oe,s,b);if(!D)break;Oe=D,b.add(D);let wt={...e,messages:x,...D.type!=="anthropic-api"&&D.type!=="claude-cli"?{system:tn(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{X=await D.streamRaw(wt,{signal:r?.signal}),A=D;break}catch(Ue){m.markUnhealthy(D.type,String(Ue)),l.push(`${D.type}:failed_connect:${String(Ue).slice(0,ut)}`);}}if(!A||!X)throw m.emitTerminalExhaustion(i,E,V,G,l,a,r?.licenseState),S;l.push(`${A.type}:stitched`),m.emitEngineEvent({kind:"mid_stream_failover_success",callId:i,id:randomUUID(),ts:Date.now(),from:g.type,to:A.type}),Me=nn(R)+1,ye--,g=A,f=X[Symbol.asyncIterator](),z=true,J=null,k=at(g.type),E.segments.push(k),m.emitEngineEvent({kind:"segment_start",callId:i,id:randomUUID(),ts:Date.now(),provider:g.type});}}let y=d();return r?.licenseState==="SEC_DEGRADED"&&(y=rn(y)),Q(y)}nextHealthyProvider(e,t,r,i){let o=e.indexOf(t);if(o===-1)return null;for(let s=o+1;s<e.length;s++){let a=e[s];if(!i.has(a)&&!(r&&!a.supportsMultimodal)&&a.supportsStreaming)return a}return null}emitEngineEvent(e){this.engineEvents.emitTyped(e);}emitTerminalExhaustion(e,t,r,i,o,s,a){let l=lt(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()-s,stopReason:i||"error",fallbackChain:o,rateLimitHit:false,securityState:a});}};});function dt(n,e){if(e==="prefer-user"){let i=n.filter(s=>s.type==="claude-cli"),o=n.filter(s=>s.type!=="claude-cli");return [...i,...o]}if(e==="prefer-app"){let i=n.filter(s=>s.type==="claude-cli");return [...n.filter(s=>s.type!=="claude-cli"),...i]}let t=n.filter(i=>i.type===e),r=n.filter(i=>i.type!==e);return [...t,...r]}function pt(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var mt=v(()=>{});function ht(n){if(De[n])return De[n];for(let[e,t]of Object.entries(De))if(n.startsWith(e))return t;return [3,15]}var De,gt=v(()=>{De={"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 ft(n){let e=0;for(let a of n.messages)if(typeof a.content=="string")e+=a.content.length;else if(Array.isArray(a.content))for(let l of a.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),[i,o]=ht(n.model),s=(t*i+r*o)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(s*1e4)/1e4,model:n.model,provider:""}}var yt=v(()=>{gt();});var de,_t=v(()=>{de=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=i=>this.bufferLineageEvent(i),r=i=>{i.kind==="stream_complete"&&this.flushLineageForCall(i);};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(i=>i.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(()=>{});}};});async function pe(n,e){if(!n)return {valid:false,error:"License key required. Get one at inference-relay.com"};let t=H.get(n);if(t&&Date.now()-t.cachedAt<t.ttl)return t.result;let r=new AbortController,o=!H.has(n)?3e3:1e3,s=setTimeout(()=>r.abort(),o),a;try{let p=(e||sn)+on;a=await(await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:n}),signal:r.signal})).json();}catch{return clearTimeout(s),t&&Date.now()-t.cachedAt<ln?t.result:{valid:false,error:"License validation failed (network error). Visit inference-relay.com"}}clearTimeout(s);let l;if(a.jws)try{let{compactVerify:p,importSPKI:u}=await import('jose'),h=await u(cn,"RS256"),{payload:m}=await p(a.jws,h);l=JSON.parse(new TextDecoder().decode(m));}catch{return H.delete(n),{valid:false,error:"License validation signature invalid. Possible MITM \u2014 refusing to start."}}else if(l=a,l.valid)return H.delete(n),{valid:false,error:"License validation response not signed. Possible MITM."};return H.set(n,{result:l,cachedAt:Date.now(),ttl:l.valid?an:6e4}),l}var sn,on,an,ln,cn,H,me,Et=v(()=>{_e();Ke();ze();et();tt();xe();te();mt();yt();ve();_t();sn="https://api.inference-relay.com",on="/v1/validate",an=1440*60*1e3,ln=10080*60*1e3,cn=`-----BEGIN PUBLIC KEY-----
|
|
17
17
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzk88Bt9LZSmuSd8ulKqy
|
|
18
18
|
EGNiPB+r8u1ZinBvMM4qX8dp4kzJEC/47L1RYrrxCphD05HToREjljbj+upH6rZH
|
|
19
19
|
t6D/5funYPi2TO1IOSC6BRVRwMqqTmJGVJcLcG/WF3gTE+2UQ3q5EppWJCEKcz6x
|
|
@@ -21,4 +21,4 @@ kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
|
|
|
21
21
|
7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
|
|
22
22
|
Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
|
|
23
23
|
UQIDAQAB
|
|
24
|
-
-----END PUBLIC KEY-----`,$=new Map;me=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new W;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new ue,this.telemetryReporter=new de({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=pt(e.routing)),e.providers)for(let i of e.providers){let o=typeof i=="string"?{type:i}:i,s=this.createProvider(o);s&&(o.priority!==void 0&&(s.priority=o.priority),this.providers.push(s));}let t=100,r=3600*1e3;this.messages={create:async(i,o)=>{let s=this.license&&(this.callsSinceValidation>=t||Date.now()-this.licenseValidatedAt>=r);if(s&&(this.license=null),!this.license){this.licensePromise||(this.licensePromise=pe(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});s||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++,i.stream?this.streamMessage(i,o):this.executeMessage(i,o)}};}startCapProbe(){if(this.capProbeTimer!==null)return;let e=15e3,t=20,r=4;this.capProbeTicksRemaining=t;let i=async()=>{this.capProbeTicksRemaining-=1;let o=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 (${o}m remaining)`),this.config.licenseKey&&$.delete(this.config.licenseKey);try{let s=await this.probeValidate();if(s.valid&&s.capExceeded===!1){console.log("[inference-relay] cap cleared \u2014 probe exiting, inference resuming"),this.license=s,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(i,e),typeof this.capProbeTimer.unref=="function"&&this.capProbeTimer.unref();}async probeValidate(){return pe(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})}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&&$.delete(this.config.licenseKey),this.license=null,this.licensePromise=null,this.callsSinceValidation=0,this.stopCapProbe(),this.telemetryReporter.unsubscribe(),this.manifestDecryptor.clearCache(),$e();}resolveProviders(e){if(!this.routingFn)return this.providers;let t=ft(e),r=this.routingFn(e,t);return dt(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 se({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new ie({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new oe({baseUrl:e.baseUrl});default:return null}}};});var bt=v(()=>{te();});var Ct={};Ne(Ct,{runVerify:()=>gn});function w(n,e){let t=n.padEnd(13);console.log(`${_("[ir]")} ${t}${e}`);}function ge(n){if(n instanceof B)return {label:"CAP_EXCEEDED",hint:"Monthly cap reached. Buy a top-up at https://inference-relay.com/dashboard/billing",code:1};if(n instanceof F)return {label:"ALL_PROVIDERS_FAILED",hint:`Fallback chain exhausted: ${n.fallbackChain.join(" \u2192 ")}`,code:1};if(!(n instanceof Error))return {label:"FAILED",hint:String(n).slice(0,120),code:1};let e=n.message.toLowerCase(),t=n.name.toLowerCase();return e.includes("keychain_access_denied")||e.includes("keychain access denied")?{label:"KEYCHAIN_DENIED",hint:'macOS denied keychain access. Re-run and click "Always Allow" on the prompt.',code:1}:e.includes("rate limit")||e.includes("429")||t.includes("ratelimit")?{label:"RATE_LIMITED",hint:"Claude subscription is currently rate-limited. Wait a minute and re-run.",code:1}:e.includes("auth")||e.includes("401")||e.includes("403")||e.includes("unauthorized")||e.includes("forbidden")?{label:"AUTH_FAILED",hint:"Claude CLI OAuth token rejected. Run `claude` to refresh, then re-run verify.",code:1}:e.includes("timeout")||e.includes("timed out")||e.includes("aborted")||e.includes("etimedout")||e.includes("econnrefused")||e.includes("econnreset")||t==="aborterror"||t==="timeouterror"?{label:"TIMEOUT",hint:`No response within ${j/1e3}s. Network issue, hung CLI, or keychain prompt waiting for input. Try \`curl -I api.anthropic.com\` to test connectivity.`,code:1}:e.includes("empty response")||e.includes("returned empty")?{label:"EMPTY_RESPONSE",hint:"CLI returned an empty body \u2014 possible truncation, model error, or stale CLI version.",code:1}:{label:"FAILED",hint:n.message.slice(0,120),code:1}}function vt(n){if(n.usageCap!==null&&n.usageCap!==void 0){let e=n.usageThisMonth??0,t=n.usageCap;if(t===0)console.log(_(` Usage: ${e.toLocaleString()} (unmetered)`));else {let r=Math.round(e/t*1e3)/10;console.log(_(` Usage: ${e.toLocaleString()} / ${t.toLocaleString()} (${r}%)`));}}}async function gn(n=process.argv.slice(2),e=process.env){let t=n.includes("--credentials-only"),r=e.IR_LICENSE_KEY;if(!r)return console.error(M("[ir] IR_LICENSE_KEY environment variable is not set.")),console.error(" Get a key at https://inference-relay.com/pricing"),console.error(" Then: export IR_LICENSE_KEY=ir_live_xxxx"),2;if(!/^ir_(live|test)_[a-f0-9]{32}$/.test(r))return console.error(M("[ir] IR_LICENSE_KEY does not look like a valid key.")),console.error(" Expected format: ir_live_<32 hex chars>"),console.error(` Got: ${r.slice(0,8)}... (${r.length} chars)`),2;let i;try{i=await pe(r);}catch(b){return w("IDENTITY:",M("FAILED")),console.error(` ${b.message||"unknown error"}`),1}if(!i.valid)return w("IDENTITY:",M("REJECTED")),i.error&&console.error(` ${i.error}`),1;w("IDENTITY:",q("VALIDATED"));let o=(i.tier??"unknown").toUpperCase();w("TIER:",q(o));let s;try{s=await H();}catch{s=null;}if(!s||!s.available)return w("RELAY:",he("INACTIVE")),console.log(_(" Claude CLI not detected. The relay will fall back")),console.log(_(" to direct API providers using your API keys.")),console.log(_(" For zero-cost routing, install Claude Code:")),console.log(_(" npm install -g @anthropic-ai/claude-code")),1;if(!s.authenticated)return w("RELAY:",he("CLI_UNAUTHED")),console.log(_(" Claude CLI is installed but not authenticated.")),console.log(_(" Run `claude` once to sign in, then re-run verify.")),1;if(s.versionWarning&&console.log(he(` Warning: ${s.versionWarning}`)),t)return w("RELAY:",q("READY")),console.log(_(" Credentials present. Round-trip skipped (--credentials-only).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),s.subscriptionType&&s.subscriptionType!=="unknown"&&console.log(_(` Tier: ${s.subscriptionType}`)),vt(i),0;let a=new me({licenseKey:r,providers:[{type:"claude-cli",priority:1}],fallback:false,telemetry:false}),l=new AbortController,p=setTimeout(()=>l.abort(),j),u=Date.now(),h;try{h=await a.messages.create(dn,{signal:l.signal});}catch(b){clearTimeout(p),a.dispose();let{label:d,hint:y}=ge(b);return w("RELAY:",M(`DEGRADED \u2014 ${d}`)),console.log(_(` ${y}`)),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}if(clearTimeout(p),process.platform==="win32"){let b=new AbortController,d=setTimeout(()=>b.abort(),j);try{await a.messages.create(pn,{signal:b.signal});}catch(E){clearTimeout(d),a.dispose();let{hint:k}=ge(E);return w("RELAY:",M("DEGRADED \u2014 LONG_PROMPT_FAILED")),console.log(_(` Long-system-prompt round-trip failed: ${k}`)),console.log(_(" This is the cmd.exe arg-length regression class.")),console.log(_(" Ensure inference-relay is at version >=1.5.3 (closes the bug).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}clearTimeout(d);let y=new AbortController,g=setTimeout(()=>y.abort(),j);try{await a.messages.create(mn,{signal:y.signal});}catch(E){clearTimeout(g),a.dispose();let{hint:k}=ge(E);return w("RELAY:",M("DEGRADED \u2014 TOOLS_DISPATCH_FAILED")),console.log(_(` Tools round-trip failed: ${k}`)),console.log(_(" The claude-cli provider couldn't forward params.tools.")),console.log(_(" Ensure inference-relay is at version >=1.6.0 (closes the bug).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}clearTimeout(g);let f=new AbortController,R=setTimeout(()=>f.abort(),j);try{await a.messages.create(hn,{signal:f.signal});}catch(E){clearTimeout(R),a.dispose();let{hint:k}=ge(E);return w("RELAY:",M("DEGRADED \u2014 MULTITURN_DISPATCH_FAILED")),console.log(_(` Multi-turn round-trip failed: ${k}`)),console.log(_(" The CLI rejected an assistant-role stream-json envelope.")),console.log(_(" Ensure inference-relay is at version >=1.6.0 (closes the bug),")),console.log(_(" OR ensure Claude CLI version is >=2.1.x (stream-json input floor).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}clearTimeout(R);}a.dispose();let m=Date.now()-u;return h.fallbackChain?.[0]?.startsWith("claude-cli:success")?(w("RELAY:",q("ACTIVE")),console.log(_(` Round-trip: ${m}ms via ${h.provider}`)),console.log(_(` Model echo: ${h.model}`)),console.log(_(` Tokens: ${h.usage.input_tokens} in / ${h.usage.output_tokens} out`)),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),console.log(_(` Multimodal: ${q("\u2713")} via claude-cli (subscription)`)),s.subscriptionType&&s.subscriptionType!=="unknown"&&console.log(_(` Tier: ${s.subscriptionType}`)),vt(i),0):(w("RELAY:",he("UNEXPECTED")),console.log(_(` Native Gateway did not handle the call. Chain: ${h.fallbackChain?.join(" \u2192 ")}`)),1)}var un,fe,q,M,he,_,j,dn,pn,mn,hn,At=v(()=>{Et();Le();_e();bt();un=process.stdout.isTTY===true,fe=(n,e)=>un?`\x1B[${n}m${e}\x1B[0m`:e,q=n=>fe("32",n),M=n=>fe("31",n),he=n=>fe("33",n),_=n=>fe("2",n);j=15e3,dn={model:"claude-haiku-4-5",max_tokens:1,messages:[{role:"user",content:"Reply with exactly the single character k and nothing else."}]},pn={model:"claude-haiku-4-5",max_tokens:1,system:"Sentence. ".repeat(800),messages:[{role:"user",content:"Reply with exactly the single character k and nothing else."}]},mn={model:"claude-haiku-4-5",max_tokens:50,messages:[{role:"user",content:"Reply with the single word: ok"}],tools:[{type:"web_search_20250305",name:"web_search",max_uses:1}]},hn={model:"claude-haiku-4-5",max_tokens:10,messages:[{role:"user",content:"Reply with: hello"},{role:"assistant",content:[{type:"text",text:"hello"}]},{role:"user",content:"Reply with: ok"}]};});var Rt={verify:async()=>{let{runVerify:n}=await Promise.resolve().then(()=>(At(),Ct));return n()}};function kt(){console.error("Usage: inference-relay <command>"),console.error(""),console.error("Commands:"),console.error(" verify Smoke-test your installation (license + relay availability)"),console.error(""),console.error("Docs: https://inference-relay.com/docs");}var O=process.argv[2];(!O||O==="--help"||O==="-h")&&(kt(),process.exit(O?0:2));O in Rt||(console.error(`Unknown command: ${O}`),console.error(""),kt(),process.exit(1));Rt[O]().then(n=>process.exit(n)).catch(n=>{console.error(`[ir] failed to run command "${O}":`),console.error(n),process.exit(99);});
|
|
24
|
+
-----END PUBLIC KEY-----`,H=new Map;me=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new W;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new ue,this.telemetryReporter=new de({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=pt(e.routing)),e.providers)for(let i of e.providers){let o=typeof i=="string"?{type:i}:i,s=this.createProvider(o);s&&(o.priority!==void 0&&(s.priority=o.priority),this.providers.push(s));}let t=100,r=3600*1e3;this.messages={create:async(i,o)=>{let s=this.license&&(this.callsSinceValidation>=t||Date.now()-this.licenseValidatedAt>=r);if(s&&(this.license=null),!this.license){this.licensePromise||(this.licensePromise=pe(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 $({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});s||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++,i.stream?this.streamMessage(i,o):this.executeMessage(i,o)}};}startCapProbe(){if(this.capProbeTimer!==null)return;let e=15e3,t=20,r=4;this.capProbeTicksRemaining=t;let i=async()=>{this.capProbeTicksRemaining-=1;let o=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 (${o}m remaining)`),this.config.licenseKey&&H.delete(this.config.licenseKey);try{let s=await this.probeValidate();if(s.valid&&s.capExceeded===!1){console.log("[inference-relay] cap cleared \u2014 probe exiting, inference resuming"),this.license=s,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(i,e),typeof this.capProbeTimer.unref=="function"&&this.capProbeTimer.unref();}async probeValidate(){return pe(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 B();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();}resetHealth(){this.fallbackEngine.resetHealth();}markHealthy(e){this.fallbackEngine.markHealthy(e);}dispose(){this.providers=[],this.config.licenseKey&&H.delete(this.config.licenseKey),this.license=null,this.licensePromise=null,this.callsSinceValidation=0,this.stopCapProbe(),this.telemetryReporter.unsubscribe(),this.manifestDecryptor.clearCache(),He();}resolveProviders(e){if(!this.routingFn)return this.providers;let t=ft(e),r=this.routingFn(e,t);return dt(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 se({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new ie({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new oe({baseUrl:e.baseUrl});default:return null}}};});var bt=v(()=>{te();});var Ct={};Ne(Ct,{runVerify:()=>gn});function w(n,e){let t=n.padEnd(13);console.log(`${_("[ir]")} ${t}${e}`);}function ge(n){if(n instanceof $)return {label:"CAP_EXCEEDED",hint:"Monthly cap reached. Buy a top-up at https://inference-relay.com/dashboard/billing",code:1};if(n instanceof F)return {label:"ALL_PROVIDERS_FAILED",hint:`Fallback chain exhausted: ${n.fallbackChain.join(" \u2192 ")}`,code:1};if(!(n instanceof Error))return {label:"FAILED",hint:String(n).slice(0,120),code:1};let e=n.message.toLowerCase(),t=n.name.toLowerCase();return e.includes("keychain_access_denied")||e.includes("keychain access denied")?{label:"KEYCHAIN_DENIED",hint:'macOS denied keychain access. Re-run and click "Always Allow" on the prompt.',code:1}:e.includes("rate limit")||e.includes("429")||t.includes("ratelimit")?{label:"RATE_LIMITED",hint:"Claude subscription is currently rate-limited. Wait a minute and re-run.",code:1}:e.includes("auth")||e.includes("401")||e.includes("403")||e.includes("unauthorized")||e.includes("forbidden")?{label:"AUTH_FAILED",hint:"Claude CLI OAuth token rejected. Run `claude` to refresh, then re-run verify.",code:1}:e.includes("timeout")||e.includes("timed out")||e.includes("aborted")||e.includes("etimedout")||e.includes("econnrefused")||e.includes("econnreset")||t==="aborterror"||t==="timeouterror"?{label:"TIMEOUT",hint:`No response within ${j/1e3}s. Network issue, hung CLI, or keychain prompt waiting for input. Try \`curl -I api.anthropic.com\` to test connectivity.`,code:1}:e.includes("empty response")||e.includes("returned empty")?{label:"EMPTY_RESPONSE",hint:"CLI returned an empty body \u2014 possible truncation, model error, or stale CLI version.",code:1}:{label:"FAILED",hint:n.message.slice(0,120),code:1}}function vt(n){if(n.usageCap!==null&&n.usageCap!==void 0){let e=n.usageThisMonth??0,t=n.usageCap;if(t===0)console.log(_(` Usage: ${e.toLocaleString()} (unmetered)`));else {let r=Math.round(e/t*1e3)/10;console.log(_(` Usage: ${e.toLocaleString()} / ${t.toLocaleString()} (${r}%)`));}}}async function gn(n=process.argv.slice(2),e=process.env){let t=n.includes("--credentials-only"),r=e.IR_LICENSE_KEY;if(!r)return console.error(M("[ir] IR_LICENSE_KEY environment variable is not set.")),console.error(" Get a key at https://inference-relay.com/pricing"),console.error(" Then: export IR_LICENSE_KEY=ir_live_xxxx"),2;if(!/^ir_(live|test)_[a-f0-9]{32}$/.test(r))return console.error(M("[ir] IR_LICENSE_KEY does not look like a valid key.")),console.error(" Expected format: ir_live_<32 hex chars>"),console.error(` Got: ${r.slice(0,8)}... (${r.length} chars)`),2;let i;try{i=await pe(r);}catch(b){return w("IDENTITY:",M("FAILED")),console.error(` ${b.message||"unknown error"}`),1}if(!i.valid)return w("IDENTITY:",M("REJECTED")),i.error&&console.error(` ${i.error}`),1;w("IDENTITY:",q("VALIDATED"));let o=(i.tier??"unknown").toUpperCase();w("TIER:",q(o));let s;try{s=await B();}catch{s=null;}if(!s||!s.available)return w("RELAY:",he("INACTIVE")),console.log(_(" Claude CLI not detected. The relay will fall back")),console.log(_(" to direct API providers using your API keys.")),console.log(_(" For zero-cost routing, install Claude Code:")),console.log(_(" npm install -g @anthropic-ai/claude-code")),1;if(!s.authenticated)return w("RELAY:",he("CLI_UNAUTHED")),console.log(_(" Claude CLI is installed but not authenticated.")),console.log(_(" Run `claude` once to sign in, then re-run verify.")),1;if(s.versionWarning&&console.log(he(` Warning: ${s.versionWarning}`)),t)return w("RELAY:",q("READY")),console.log(_(" Credentials present. Round-trip skipped (--credentials-only).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),s.subscriptionType&&s.subscriptionType!=="unknown"&&console.log(_(` Tier: ${s.subscriptionType}`)),vt(i),0;let a=new me({licenseKey:r,providers:[{type:"claude-cli",priority:1}],fallback:false,telemetry:false}),l=new AbortController,p=setTimeout(()=>l.abort(),j),u=Date.now(),h;try{h=await a.messages.create(dn,{signal:l.signal});}catch(b){clearTimeout(p),a.dispose();let{label:d,hint:y}=ge(b);return w("RELAY:",M(`DEGRADED \u2014 ${d}`)),console.log(_(` ${y}`)),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}if(clearTimeout(p),process.platform==="win32"){let b=new AbortController,d=setTimeout(()=>b.abort(),j);try{await a.messages.create(pn,{signal:b.signal});}catch(E){clearTimeout(d),a.dispose();let{hint:k}=ge(E);return w("RELAY:",M("DEGRADED \u2014 LONG_PROMPT_FAILED")),console.log(_(` Long-system-prompt round-trip failed: ${k}`)),console.log(_(" This is the cmd.exe arg-length regression class.")),console.log(_(" Ensure inference-relay is at version >=1.5.3 (closes the bug).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}clearTimeout(d);let y=new AbortController,g=setTimeout(()=>y.abort(),j);try{await a.messages.create(mn,{signal:y.signal});}catch(E){clearTimeout(g),a.dispose();let{hint:k}=ge(E);return w("RELAY:",M("DEGRADED \u2014 TOOLS_DISPATCH_FAILED")),console.log(_(` Tools round-trip failed: ${k}`)),console.log(_(" The claude-cli provider couldn't forward params.tools.")),console.log(_(" Ensure inference-relay is at version >=1.6.0 (closes the bug).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}clearTimeout(g);let f=new AbortController,R=setTimeout(()=>f.abort(),j);try{await a.messages.create(hn,{signal:f.signal});}catch(E){clearTimeout(R),a.dispose();let{hint:k}=ge(E);return w("RELAY:",M("DEGRADED \u2014 MULTITURN_DISPATCH_FAILED")),console.log(_(` Multi-turn round-trip failed: ${k}`)),console.log(_(" The CLI rejected an assistant-role stream-json envelope.")),console.log(_(" Ensure inference-relay is at version >=1.6.0 (closes the bug),")),console.log(_(" OR ensure Claude CLI version is >=2.1.x (stream-json input floor).")),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),1}clearTimeout(R);}a.dispose();let m=Date.now()-u;return h.fallbackChain?.[0]?.startsWith("claude-cli:success")?(w("RELAY:",q("ACTIVE")),console.log(_(` Round-trip: ${m}ms via ${h.provider}`)),console.log(_(` Model echo: ${h.model}`)),console.log(_(` Tokens: ${h.usage.input_tokens} in / ${h.usage.output_tokens} out`)),s.cliVersion&&console.log(_(` Claude CLI: v${s.cliVersion}`)),console.log(_(` Multimodal: ${q("\u2713")} via claude-cli (subscription)`)),s.subscriptionType&&s.subscriptionType!=="unknown"&&console.log(_(` Tier: ${s.subscriptionType}`)),vt(i),0):(w("RELAY:",he("UNEXPECTED")),console.log(_(` Native Gateway did not handle the call. Chain: ${h.fallbackChain?.join(" \u2192 ")}`)),1)}var un,fe,q,M,he,_,j,dn,pn,mn,hn,At=v(()=>{Et();xe();_e();bt();un=process.stdout.isTTY===true,fe=(n,e)=>un?`\x1B[${n}m${e}\x1B[0m`:e,q=n=>fe("32",n),M=n=>fe("31",n),he=n=>fe("33",n),_=n=>fe("2",n);j=15e3,dn={model:"claude-haiku-4-5",max_tokens:1,messages:[{role:"user",content:"Reply with exactly the single character k and nothing else."}]},pn={model:"claude-haiku-4-5",max_tokens:1,system:"Sentence. ".repeat(800),messages:[{role:"user",content:"Reply with exactly the single character k and nothing else."}]},mn={model:"claude-haiku-4-5",max_tokens:50,messages:[{role:"user",content:"Reply with the single word: ok"}],tools:[{type:"web_search_20250305",name:"web_search",max_uses:1}]},hn={model:"claude-haiku-4-5",max_tokens:10,messages:[{role:"user",content:"Reply with: hello"},{role:"assistant",content:[{type:"text",text:"hello"}]},{role:"user",content:"Reply with: ok"}]};});var Rt={verify:async()=>{let{runVerify:n}=await Promise.resolve().then(()=>(At(),Ct));return n()}};function kt(){console.error("Usage: inference-relay <command>"),console.error(""),console.error("Commands:"),console.error(" verify Smoke-test your installation (license + relay availability)"),console.error(""),console.error("Docs: https://inference-relay.com/docs");}var O=process.argv[2];(!O||O==="--help"||O==="-h")&&(kt(),process.exit(O?0:2));O in Rt||(console.error(`Unknown command: ${O}`),console.error(""),kt(),process.exit(1));Rt[O]().then(n=>process.exit(n)).catch(n=>{console.error(`[ir] failed to run command "${O}":`),console.error(n),process.exit(99);});
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use strict';var child_process=require('child_process'),fs=require('fs'),path=require('path'),os=require('os'),crypto$1=require('crypto'),vm=require('vm'),module$1=require('module'),events=require('events');/*! inference-relay (c) 2026 L2B II LLC. Patent pending. Proprietary. See LICENSE. */
|
|
2
|
-
var Ze=Object.defineProperty;var et=(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 tt=(n,e)=>()=>(n&&(e=n(n=0)),e);var rt=(n,e)=>{for(var t in e)Ze(n,t,{get:e[t],enumerable:true});};var Ne={};rt(Ne,{detectCLI:()=>V});function ft(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=path.join(i,n+a);if(fs.existsSync(o))return o}return null}async function V(){if(!ft("claude"))return {available:false,authenticated:false};let e=null;try{let r=child_process.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&&!yt.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 yt,ne=tt(()=>{yt=["2.1.87"];});var
|
|
2
|
+
var Ze=Object.defineProperty;var et=(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 tt=(n,e)=>()=>(n&&(e=n(n=0)),e);var rt=(n,e)=>{for(var t in e)Ze(n,t,{get:e[t],enumerable:true});};var Ne={};rt(Ne,{detectCLI:()=>V});function ft(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=path.join(i,n+a);if(fs.existsSync(o))return o}return null}async function V(){if(!ft("claude"))return {available:false,authenticated:false};let e=null;try{let r=child_process.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&&!yt.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 yt,ne=tt(()=>{yt=["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 O(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(g=>g(...f));}async function*y(){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=y(),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,g)=>{d=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(d))}};return E}var C=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 O(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-----`,ge={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>"},D=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:ge,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:ge,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},nt=new D;function Ie(){nt.clearCache();}function st(){return ge}function it(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 ut=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function be(n){return path.join(os.homedir(),".inference-relay","gateway",n)}function Me(n){return path.join(be(n),"bundle.js")}function Oe(n){return path.join(be(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},x=class extends b{constructor(e,t){super(e,"GATEWAY_FETCH_FAILED",t);}},K=new Map,dt=[0,1e3,4e3];function pt(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 dt}var G=class{static async load(e,t,r=ut,s){let i=`${t}:${e.slice(-8)}`;if(K.has(i))return K.get(i);try{let m=await this.tryLoadFromDisk(t);if(m)return S("loader.cache-hit",{libraryVersion:t}),K.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(crypto$1.createHash("sha256").update(a).digest("hex")!==o)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,p,o);try{let m=be(t);fs.mkdirSync(m,{recursive:!0}),fs.writeFileSync(Me(t),a),fs.writeFileSync(Oe(t),JSON.stringify({sha256:o,signature:l,libraryVersion:p}));}catch{}let y=this.loadIntoVm(a.toString("utf-8"));return K.set(i,y),y}static async loadFromDisk(e){if(!fs.existsSync(e))throw new b(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=fs.readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Me(e),r=Oe(e);if(!fs.existsSync(t)||!fs.existsSync(r))return null;let s=fs.readFileSync(t),i=JSON.parse(fs.readFileSync(r,"utf-8"));return crypto$1.createHash("sha256").update(s).digest("hex")!==i.sha256?null:(await this.verifySignature(i.signature,i.libraryVersion,i.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r,s){let i,a=pt(s?.retryDelaysMs),o;for(let y=0;y<a.length;y++){let m=a[y];m>0&&await new Promise(c=>setTimeout(c,m)),S("loader.fetch",{url:`${r}/v1/gateway/fetch`,libraryVersion:t,attempt:y+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:y+1}),c.status===401||c.status===403)throw new b("[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 b&&c.code==="LICENSE_REJECTED")throw c;o=c;}}if(o||!i)throw o instanceof b?o:new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)",o);let l;try{l=await fetch(i.bundleUrl);}catch(y){throw new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)",y)}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 b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof b?s:new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=path.join(os.homedir(),".inference-relay","gateway","runtime.cjs"),r=path.dirname(t),s=module$1.createRequire(t),i={exports:{}};vm.compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(i.exports,s,i,t,r);let o=i.exports;if(!o.ClaudeCLIProvider)throw new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return o}catch(t){throw t instanceof b?t:new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){K.clear();}};var _t="1.6.3",se=class extends C{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,_t,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 b?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(()=>(ne(),Ne));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 W=[{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}}],$=Object.fromEntries(W.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));$["claude-sonnet-4"]="claude-sonnet-4-20250514";$["claude-opus-4"]="claude-opus-4-20250514";$["claude-haiku-4"]="claude-haiku-4-5-20251001";function Ee(n){return $[n]||n}function bt(n){return W.find(e=>e.canonical===n)}function ie(n){return W.find(e=>e.canonical===n)?.provider}function Et(n){return W.filter(e=>e.provider===n)}var vt="https://api.anthropic.com/v1/messages",Rt="2023-06-01",ve={"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 Ue(n){if(ve[n])return ve[n];for(let[e,t]of Object.entries(ve))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Y=class extends C{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(/\/$/,"")||vt,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]=Ue(a.model||e.model),u=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*p)/1e6,y={},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&&(y[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(y).length>0?y: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 y=o.split(`
|
|
11
|
-
`);o=y.pop()||"";let m=null;for(let c of y)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]=Ue(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":
|
|
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:y||{}},yield {type:"message_stop"},u=!0;return}try{let g=JSON.parse(h);g.usage&&(y={input_tokens:g.usage.prompt_tokens||0,output_tokens:g.usage.completion_tokens||0});let
|
|
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=Pt(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 events.EventEmitter{constructor(){super(),this.setMaxListeners(50);}emitTyped(e){return this.emit(e.kind,e)}onTyped(e,t){return this.on(e,t)}offTyped(e,t){return this.off(e,t)}};var je=200;function ae(n,e){if(e instanceof b)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,je)||"unknown"}`}function Ke(n){let e=n.filter(t=>t.includes(":failed:"));return e.length===0?false:e.every(t=>t.endsWith(":failed:request_too_large"))}var Ge=new Set(["anthropic-api","openai-api","ollama"]),N=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}},z=class extends N{constructor(e){super(e);}};function Ve(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 Ae(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.includes("prompt is too long")||t.includes("prompt too long")||t.includes("input length")||t.includes("input is too long")||t.includes("context_length_exceeded")||t.includes("context length exceeded")||t.includes("request too large")||t.includes("tokens exceed")||t.includes("exceeds the maximum")||t.includes("too many tokens")?"request_too_large":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 We(n){return [...n].sort((e,t)=>e.priority-t.priority)}var X=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=We(t),i=[],a=Ve(e),o=crypto$1.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=ie(e.model);if(m&&m!==u&&Ge.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:crypto$1.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(Ae(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(ae(u,c));break;case "request_too_large":i.push(`${u}:failed:request_too_large`);break;default:i.push(ae(u,c));break}}}throw S("engine.cascade-exhausted",{chain:i,mode:"execute"}),Ke(i)?new z(i):new N(i)}async stream(e,t,r){let s=crypto$1.randomUUID(),i=We(t),a=Ve(e),o=Date.now(),l=[],p=null,u=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 R=ie(e.model);if(R&&R!==g&&Ge.has(g)){l.push(`${g}:skipped:wrong_provider`);continue}try{u=await h.streamRaw(e,{signal:r?.signal}),p=h,l.push(`${g}:success`);break}catch(_){if(_?.name==="AbortError"||r?.signal?.aborted)throw _;switch(Ae(_)){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(ae(g,_));break;case "request_too_large":l.push(`${g}:failed:request_too_large`);break;default:l.push(ae(g,_));break}}}if(!p||!u)throw S("engine.cascade-exhausted",{chain:l,mode:"stream"}),Ke(l)?new z(l):new N(l);let m=this,c=r?.maxMidStreamFailovers??2,E=new Set([p]);async function*d(){let h=p,g=u[Symbol.asyncIterator](),R={role:"assistant",content:[]},_={segments:[]},I=$e(h.type);_.segments.push(I);let ke=0,Z=null,ee=false,he=c,F="",B="";for(m.emitEngineEvent({kind:"segment_start",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type});;)try{for(;;){let A=await g.next();if(A.done)break;let L=A.value,P=Lt(L,ke,R,ee,Z);if(P.action==="suppress"){"coalesceMode"in P&&(Z=P.coalesceMode),P.clearedJustFailedOver&&(ee=!1);continue}P.coalesceModeCleared&&(Z=null),P.clearedJustFailedOver&&(ee=!1);let v=P.event;if(xt(R,v),v.type==="message_start"){if(_.segments.length>1)continue;F=v.message?.model||F,v.message?.usage?.input_tokens!=null&&(I.inputTokens=v.message.usage.input_tokens);}if(v.type==="message_delta"&&(v.delta?.stop_reason&&(B=v.delta.stop_reason),v.usage)){It(I,h.type,v.usage),yield {...v,usage:void 0};continue}if(v.type==="message_stop")break;yield v;}if(R.content.length===0&&I.outputTokens===0)throw new Error("stream ended without producing any content");m.markHealthy(h.type),m.emitEngineEvent({kind:"segment_complete",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type,usage:{...I}});let w=Ye(_.segments);yield {type:"message_delta",delta:{stop_reason:B||"end_turn"},usage:w},yield {type:"message_stop"},m.emitEngineEvent({kind:"stream_complete",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),stitched:_.segments.length>1,segments:_.segments.map(A=>({...A})),provider:_.segments.map(A=>A.provider).join("+"),model:F,inputTokens:w.input_tokens,outputTokens:w.output_tokens,costUsd:_.segments.reduce((A,L)=>A+L.costUsd,0),userCostUsd:_.segments.reduce((A,L)=>A+L.userCostUsd,0),durationMs:Date.now()-o,stopReason:B||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(w){if(w?.name==="AbortError"||r?.signal?.aborted)throw w;let A=Ae(w);try{await g.return?.();}catch{}if(m.markUnhealthy(h.type,String(w)),m.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),from:h.type,bytesBuffered:qe(R),errorClass:A,retriesLeft:he}),l.push(`${h.type}:partial(${qe(R)}b)`),he<=0)throw m.emitTerminalExhaustion(s,_,F,B,l,o,r?.licenseState),w;let L=Mt(R.content),P=[...e.messages,{role:"assistant",content:L}],v=null,te=null,Pe=h;for(;;){let T=m.nextHealthyProvider(i,Pe,a,E);if(!T)break;Pe=T,E.add(T);let Qe={...e,messages:P,...T.type!=="anthropic-api"&&T.type!=="claude-cli"?{system:Ot(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{te=await T.streamRaw(Qe,{signal:r?.signal}),v=T;break}catch(Te){m.markUnhealthy(T.type,String(Te)),l.push(`${T.type}:failed_connect:${String(Te).slice(0,je)}`);}}if(!v||!te)throw m.emitTerminalExhaustion(s,_,F,B,l,o,r?.licenseState),w;l.push(`${v.type}:stitched`),m.emitEngineEvent({kind:"mid_stream_failover_success",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),from:h.type,to:v.type}),ke=Dt(R)+1,he--,h=v,g=te[Symbol.asyncIterator](),ee=true,Z=null,I=$e(h.type),_.segments.push(I),m.emitEngineEvent({kind:"segment_start",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type});}}let f=d();return r?.licenseState==="SEC_DEGRADED"&&(f=Nt(f)),O(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=Ye(t.segments);this.emitEngineEvent({kind:"stream_complete",callId:e,id:crypto$1.randomUUID(),ts:Date.now(),stitched:t.segments.length>1,segments:t.segments.map(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 $e(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function It(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 Ye(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function xt(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 Lt(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 Mt(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 Ot(n,e){return n?`${n}
|
|
10
|
+
-----END PUBLIC KEY-----`,ge={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>"},D=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:ge,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:ge,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},nt=new D;function Ie(){nt.clearCache();}function st(){return ge}function it(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 ut=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function be(n){return path.join(os.homedir(),".inference-relay","gateway",n)}function Me(n){return path.join(be(n),"bundle.js")}function Oe(n){return path.join(be(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},x=class extends b{constructor(e,t){super(e,"GATEWAY_FETCH_FAILED",t);}},K=new Map,dt=[0,1e3,4e3];function pt(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 dt}var G=class{static async load(e,t,r=ut,s){let i=`${t}:${e.slice(-8)}`;if(K.has(i))return K.get(i);try{let m=await this.tryLoadFromDisk(t);if(m)return S("loader.cache-hit",{libraryVersion:t}),K.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(crypto$1.createHash("sha256").update(a).digest("hex")!==o)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,p,o);try{let m=be(t);fs.mkdirSync(m,{recursive:!0}),fs.writeFileSync(Me(t),a),fs.writeFileSync(Oe(t),JSON.stringify({sha256:o,signature:l,libraryVersion:p}));}catch{}let y=this.loadIntoVm(a.toString("utf-8"));return K.set(i,y),y}static async loadFromDisk(e){if(!fs.existsSync(e))throw new b(`[ir-system]: GATEWAY_LOAD_FAILED (REASON: BUNDLE_NOT_FOUND at ${e})`,"GATEWAY_LOAD_FAILED");let t=fs.readFileSync(e,"utf-8");return this.loadIntoVm(t)}static async tryLoadFromDisk(e){let t=Me(e),r=Oe(e);if(!fs.existsSync(t)||!fs.existsSync(r))return null;let s=fs.readFileSync(t),i=JSON.parse(fs.readFileSync(r,"utf-8"));return crypto$1.createHash("sha256").update(s).digest("hex")!==i.sha256?null:(await this.verifySignature(i.signature,i.libraryVersion,i.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r,s){let i,a=pt(s?.retryDelaysMs),o;for(let y=0;y<a.length;y++){let m=a[y];m>0&&await new Promise(c=>setTimeout(c,m)),S("loader.fetch",{url:`${r}/v1/gateway/fetch`,libraryVersion:t,attempt:y+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:y+1}),c.status===401||c.status===403)throw new b("[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 b&&c.code==="LICENSE_REJECTED")throw c;o=c;}}if(o||!i)throw o instanceof b?o:new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)",o);let l;try{l=await fetch(i.bundleUrl);}catch(y){throw new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)",y)}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 b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.libraryVersion!==t)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(l.sha256!==r)throw new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof b?s:new b("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=path.join(os.homedir(),".inference-relay","gateway","runtime.cjs"),r=path.dirname(t),s=module$1.createRequire(t),i={exports:{}};vm.compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(i.exports,s,i,t,r);let o=i.exports;if(!o.ClaudeCLIProvider)throw new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return o}catch(t){throw t instanceof b?t:new b("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){K.clear();}};var _t="1.6.4",se=class extends C{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,_t,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 b?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(()=>(ne(),Ne));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 W=[{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}}],$=Object.fromEntries(W.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));$["claude-sonnet-4"]="claude-sonnet-4-20250514";$["claude-opus-4"]="claude-opus-4-20250514";$["claude-haiku-4"]="claude-haiku-4-5-20251001";function Ee(n){return $[n]||n}function bt(n){return W.find(e=>e.canonical===n)}function ie(n){return W.find(e=>e.canonical===n)?.provider}function Et(n){return W.filter(e=>e.provider===n)}var vt="https://api.anthropic.com/v1/messages",At="2023-06-01",ve={"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 Ue(n){if(ve[n])return ve[n];for(let[e,t]of Object.entries(ve))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Y=class extends C{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(/\/$/,"")||vt,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]=Ue(a.model||e.model),u=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*p)/1e6,y={},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&&(y[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(y).length>0?y: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 y=o.split(`
|
|
11
|
+
`);o=y.pop()||"";let m=null;for(let c of y)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]=Ue(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":At};return this.dangerousDirectBrowserAccess&&(e["anthropic-dangerous-direct-browser-access"]="true"),e}buildRequestBody(e,t){let r={model:Ee(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 Rt="https://api.openai.com/v1/chat/completions",Fe=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],Ae={"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 He(n){if(Ae[n])return Ae[n];for(let[e,t]of Object.entries(Ae))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 St(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 q=class extends C{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(/\/$/,"")||Rt;}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,y=a.usage?.completion_tokens||0,[m,c]=He(a.model||e.model),E=(u*m+y*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 g=i.headers.get(h);g&&(d[h]=g);}return {content:p,model:a.model||e.model,usage:{input_tokens:u,output_tokens:y},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,y,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:y||{}},yield {type:"message_stop"},u=!0;return}try{let g=JSON.parse(h);g.usage&&(y={input_tokens:g.usage.prompt_tokens||0,output_tokens:g.usage.completion_tokens||0});let A=g.choices?.[0];if(!A)continue;let _=A.delta;_?.content&&!p&&(p=!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}}),A.finish_reason&&(p&&(yield {type:"content_block_stop",index:0}),m=Be(A.finish_reason));}catch{}}}u||(yield {type:"message_delta",delta:{stop_reason:m||"end_turn"},usage:y||{}},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]=He(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(!Fe.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 (${Fe.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=St(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 wt="http://localhost:11434";function kt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Pt(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:kt(r.content)});return t}var j=class extends C{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(/\/$/,"")||wt;}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:y,value:m}=await i.read();if(y)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=Pt(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 events.EventEmitter{constructor(){super(),this.setMaxListeners(50);}emitTyped(e){return this.emit(e.kind,e)}onTyped(e,t){return this.on(e,t)}offTyped(e,t){return this.off(e,t)}};var je=200;function ae(n,e){if(e instanceof b)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,je)||"unknown"}`}function Ke(n){let e=n.filter(t=>t.includes(":failed:"));return e.length===0?false:e.every(t=>t.endsWith(":failed:request_too_large"))}var Ge=new Set(["anthropic-api","openai-api","ollama"]),N=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}},z=class extends N{constructor(e){super(e);}};function Ve(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 Re(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.includes("prompt is too long")||t.includes("prompt too long")||t.includes("input length")||t.includes("input is too long")||t.includes("context_length_exceeded")||t.includes("context length exceeded")||t.includes("request too large")||t.includes("tokens exceed")||t.includes("exceeds the maximum")||t.includes("too many tokens")?"request_too_large":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 We(n){return [...n].sort((e,t)=>e.priority-t.priority)}var X=class n{healthMap=new Map;engineEvents=new J;static UNHEALTHY_TTL_DEFAULT_MS=300*1e3;static UNHEALTHY_TTL_AUTH_MS=30*1e3;getHealthStatus(e){let t=this.healthMap.get(e);if(!t)return "healthy";let r=t.ttlMs??n.UNHEALTHY_TTL_DEFAULT_MS;if(t.status==="unhealthy"&&Date.now()-t.updatedAt>=r){let s=Date.now()-t.updatedAt;return this.healthMap.delete(e),S("engine.recovered",{providerType:e,ageMs:s,ttlMs:r}),"healthy"}return t.status}markUnhealthy(e,t,r){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now(),ttlMs:r}),S("engine.unhealthy",{providerType:e,reason:t,ttlMs:r});}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=We(t),i=[],a=Ve(e),o=crypto$1.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=ie(e.model);if(m&&m!==u&&Ge.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:crypto$1.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(Re(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",n.UNHEALTHY_TTL_AUTH_MS),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(ae(u,c));break;case "request_too_large":i.push(`${u}:failed:request_too_large`);break;default:i.push(ae(u,c));break}}}throw S("engine.cascade-exhausted",{chain:i,mode:"execute"}),Ke(i)?new z(i):new N(i)}async stream(e,t,r){let s=crypto$1.randomUUID(),i=We(t),a=Ve(e),o=Date.now(),l=[],p=null,u=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 A=ie(e.model);if(A&&A!==g&&Ge.has(g)){l.push(`${g}:skipped:wrong_provider`);continue}try{u=await h.streamRaw(e,{signal:r?.signal}),p=h,l.push(`${g}:success`);break}catch(_){if(_?.name==="AbortError"||r?.signal?.aborted)throw _;switch(Re(_)){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",n.UNHEALTHY_TTL_AUTH_MS),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(ae(g,_));break;case "request_too_large":l.push(`${g}:failed:request_too_large`);break;default:l.push(ae(g,_));break}}}if(!p||!u)throw S("engine.cascade-exhausted",{chain:l,mode:"stream"}),Ke(l)?new z(l):new N(l);let m=this,c=r?.maxMidStreamFailovers??2,E=new Set([p]);async function*d(){let h=p,g=u[Symbol.asyncIterator](),A={role:"assistant",content:[]},_={segments:[]},I=$e(h.type);_.segments.push(I);let ke=0,Z=null,ee=false,he=c,F="",H="";for(m.emitEngineEvent({kind:"segment_start",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type});;)try{for(;;){let R=await g.next();if(R.done)break;let L=R.value,P=Lt(L,ke,A,ee,Z);if(P.action==="suppress"){"coalesceMode"in P&&(Z=P.coalesceMode),P.clearedJustFailedOver&&(ee=!1);continue}P.coalesceModeCleared&&(Z=null),P.clearedJustFailedOver&&(ee=!1);let v=P.event;if(xt(A,v),v.type==="message_start"){if(_.segments.length>1)continue;F=v.message?.model||F,v.message?.usage?.input_tokens!=null&&(I.inputTokens=v.message.usage.input_tokens);}if(v.type==="message_delta"&&(v.delta?.stop_reason&&(H=v.delta.stop_reason),v.usage)){It(I,h.type,v.usage),yield {...v,usage:void 0};continue}if(v.type==="message_stop")break;yield v;}if(A.content.length===0&&I.outputTokens===0)throw new Error("stream ended without producing any content");m.markHealthy(h.type),m.emitEngineEvent({kind:"segment_complete",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type,usage:{...I}});let w=Ye(_.segments);yield {type:"message_delta",delta:{stop_reason:H||"end_turn"},usage:w},yield {type:"message_stop"},m.emitEngineEvent({kind:"stream_complete",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),stitched:_.segments.length>1,segments:_.segments.map(R=>({...R})),provider:_.segments.map(R=>R.provider).join("+"),model:F,inputTokens:w.input_tokens,outputTokens:w.output_tokens,costUsd:_.segments.reduce((R,L)=>R+L.costUsd,0),userCostUsd:_.segments.reduce((R,L)=>R+L.userCostUsd,0),durationMs:Date.now()-o,stopReason:H||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(w){if(w?.name==="AbortError"||r?.signal?.aborted)throw w;let R=Re(w);try{await g.return?.();}catch{}if(m.markUnhealthy(h.type,String(w)),m.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),from:h.type,bytesBuffered:qe(A),errorClass:R,retriesLeft:he}),l.push(`${h.type}:partial(${qe(A)}b)`),he<=0)throw m.emitTerminalExhaustion(s,_,F,H,l,o,r?.licenseState),w;let L=Mt(A.content),P=[...e.messages,{role:"assistant",content:L}],v=null,te=null,Pe=h;for(;;){let T=m.nextHealthyProvider(i,Pe,a,E);if(!T)break;Pe=T,E.add(T);let Qe={...e,messages:P,...T.type!=="anthropic-api"&&T.type!=="claude-cli"?{system:Ot(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{te=await T.streamRaw(Qe,{signal:r?.signal}),v=T;break}catch(Te){m.markUnhealthy(T.type,String(Te)),l.push(`${T.type}:failed_connect:${String(Te).slice(0,je)}`);}}if(!v||!te)throw m.emitTerminalExhaustion(s,_,F,H,l,o,r?.licenseState),w;l.push(`${v.type}:stitched`),m.emitEngineEvent({kind:"mid_stream_failover_success",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),from:h.type,to:v.type}),ke=Dt(A)+1,he--,h=v,g=te[Symbol.asyncIterator](),ee=true,Z=null,I=$e(h.type),_.segments.push(I),m.emitEngineEvent({kind:"segment_start",callId:s,id:crypto$1.randomUUID(),ts:Date.now(),provider:h.type});}}let f=d();return r?.licenseState==="SEC_DEGRADED"&&(f=Nt(f)),O(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=Ye(t.segments);this.emitEngineEvent({kind:"stream_complete",callId:e,id:crypto$1.randomUUID(),ts:Date.now(),stitched:t.segments.length>1,segments:t.segments.map(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 $e(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function It(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 Ye(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function xt(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 Lt(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 Mt(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 Ot(n,e){return n?`${n}
|
|
14
14
|
|
|
15
|
-
${e}`:e}function qe(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 Dt(n){return Math.max(0,n.content.length-1)}async function*Nt(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}ne();function oe(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 le(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var Ce={"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 ce(n){if(Ce[n])return Ce[n];for(let[e,t]of Object.entries(Ce))if(n.startsWith(e))return t;return [3,15]}function ue(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]=ce(n.model),a=(t*s+r*i)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(a*1e4)/1e4,model:n.model,provider:""}}var U=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 Ut="https://api.inference-relay.com",Ft="/v1/validate",
|
|
15
|
+
${e}`:e}function qe(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 Dt(n){return Math.max(0,n.content.length-1)}async function*Nt(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}ne();function oe(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 le(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var Ce={"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 ce(n){if(Ce[n])return Ce[n];for(let[e,t]of Object.entries(Ce))if(n.startsWith(e))return t;return [3,15]}function ue(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]=ce(n.model),a=(t*s+r*i)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(a*1e4)/1e4,model:n.model,provider:""}}var U=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 Ut="https://api.inference-relay.com",Ft="/v1/validate",Ht=1440*60*1e3,Bt=10080*60*1e3,Kt=`-----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-----`,M=new Map;async function Se(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||Ut)+Ft;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<Ht?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'),y=await u(Kt,"RS256"),{payload:m}=await p(o.jws,y);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?Bt:6e4}),l}var we=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new D;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new X,this.telemetryReporter=new U({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=le(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=Se(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 H({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 Se(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 V();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=ue(e),r=this.routingFn(e,t);return oe(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 se(this.config.licenseKey,{retryDelaysMs:this.config.gatewayRetryDelaysMs});case "anthropic-api":return e.apiKey?new Y({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new q({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new j({baseUrl:e.baseUrl});default:return null}}};function Gt(n){if(!n)return 0;if(typeof n=="string")return Math.ceil(n.length/4);if(!Array.isArray(n))return 0;let e=0;for(let t of n){if(!t||typeof t!="object")continue;let r=t;if(r.type==="image"||r.type==="image_url"){e+=1500;continue}if(typeof r.text=="string"){e+=Math.ceil(r.text.length/4);continue}try{e+=Math.ceil(JSON.stringify(t).length/4);}catch{e+=50;}}return e}function Vt(n){return 8+Gt(n.content)}function Wt(n){let e=50;typeof n.system=="string"&&(e+=Math.ceil(n.system.length/4));for(let t of n.messages)e+=Vt(t);return e}ne();var $t="https://api.anthropic.com/v1/messages",Yt="2023-06-01";async function Je(n){try{let e=await fetch($t,{method:"POST",headers:{"content-type":"application/json","x-api-key":n,"anthropic-version":Yt},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 de=class{filePath;safeStorage=null;memoryFallback=new Map;constructor(e){let t=e?.storagePath||path.join(os.homedir(),".inference-relay");fs.existsSync(t)||fs.mkdirSync(t,{recursive:true}),this.filePath=path.join(t,"credentials.enc");try{let r=et("electron");r?.safeStorage?.isEncryptionAvailable?.()&&(this.safeStorage=r.safeStorage);}catch{}}readDisk(){if(!fs.existsSync(this.filePath))return {};try{let e=fs.readFileSync(this.filePath,"utf-8");return JSON.parse(e)}catch{return {}}}writeDisk(e){fs.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 Q="AES-GCM";var pe=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,Q,false,["encrypt","decrypt"]);}else {this.cryptoKey=await crypto.subtle.generateKey({name:Q,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:Q,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:Q,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:Q,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 me=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
|
-
exports.AnthropicAPIProvider=Y;exports.BaseProvider=C;exports.ElectronCredentialStore=de;exports.EngineEventEmitter=J;exports.FallbackEngine=X;exports.GatewayLoader=G;exports.GatewayLoaderError=b;exports.GatewayUnavailableError=x;exports.IndexedDBCredentialStore=pe;exports.InferenceRelay=we;exports.MODEL_ALIASES=$;exports.MODEL_REGISTRY=W;exports.ManifestDecryptor=D;exports.MemoryCredentialStore=me;exports.OllamaProvider=j;exports.OpenAIAPIProvider=q;exports.RelayCapExceededError=
|
|
23
|
+
-----END PUBLIC KEY-----`,M=new Map;async function Se(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||Ut)+Ft;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<Bt?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'),y=await u(Kt,"RS256"),{payload:m}=await p(o.jws,y);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?Ht:6e4}),l}var we=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new D;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new X,this.telemetryReporter=new U({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=le(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=Se(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 Se(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 V();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();}resetHealth(){this.fallbackEngine.resetHealth();}markHealthy(e){this.fallbackEngine.markHealthy(e);}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=ue(e),r=this.routingFn(e,t);return oe(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 se(this.config.licenseKey,{retryDelaysMs:this.config.gatewayRetryDelaysMs});case "anthropic-api":return e.apiKey?new Y({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new q({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new j({baseUrl:e.baseUrl});default:return null}}};function Gt(n){if(!n)return 0;if(typeof n=="string")return Math.ceil(n.length/4);if(!Array.isArray(n))return 0;let e=0;for(let t of n){if(!t||typeof t!="object")continue;let r=t;if(r.type==="image"||r.type==="image_url"){e+=1500;continue}if(typeof r.text=="string"){e+=Math.ceil(r.text.length/4);continue}try{e+=Math.ceil(JSON.stringify(t).length/4);}catch{e+=50;}}return e}function Vt(n){return 8+Gt(n.content)}function Wt(n){let e=50;typeof n.system=="string"&&(e+=Math.ceil(n.system.length/4));for(let t of n.messages)e+=Vt(t);return e}ne();var $t="https://api.anthropic.com/v1/messages",Yt="2023-06-01";async function Je(n){try{let e=await fetch($t,{method:"POST",headers:{"content-type":"application/json","x-api-key":n,"anthropic-version":Yt},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 de=class{filePath;safeStorage=null;memoryFallback=new Map;constructor(e){let t=e?.storagePath||path.join(os.homedir(),".inference-relay");fs.existsSync(t)||fs.mkdirSync(t,{recursive:true}),this.filePath=path.join(t,"credentials.enc");try{let r=et("electron");r?.safeStorage?.isEncryptionAvailable?.()&&(this.safeStorage=r.safeStorage);}catch{}}readDisk(){if(!fs.existsSync(this.filePath))return {};try{let e=fs.readFileSync(this.filePath,"utf-8");return JSON.parse(e)}catch{return {}}}writeDisk(e){fs.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 Q="AES-GCM";var pe=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,Q,false,["encrypt","decrypt"]);}else {this.cryptoKey=await crypto.subtle.generateKey({name:Q,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:Q,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:Q,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:Q,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 me=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
|
+
exports.AnthropicAPIProvider=Y;exports.BaseProvider=C;exports.ElectronCredentialStore=de;exports.EngineEventEmitter=J;exports.FallbackEngine=X;exports.GatewayLoader=G;exports.GatewayLoaderError=b;exports.GatewayUnavailableError=x;exports.IndexedDBCredentialStore=pe;exports.InferenceRelay=we;exports.MODEL_ALIASES=$;exports.MODEL_REGISTRY=W;exports.ManifestDecryptor=D;exports.MemoryCredentialStore=me;exports.OllamaProvider=j;exports.OpenAIAPIProvider=q;exports.RelayCapExceededError=B;exports.RelayError=N;exports.RequestTooLargeError=z;exports.TelemetryReporter=U;exports.applyRouting=oe;exports.createRelayStream=O;exports.createRoutingFunction=le;exports.detectCLI=V;exports.estimateCost=ue;exports.estimateInputTokens=Wt;exports.findModel=bt;exports.getLastKnownGoodManifest=st;exports.getModelPricing=ce;exports.getValue=it;exports.modelsForProvider=Et;exports.normalizeModel=Ee;exports.providerForModel=ie;exports.validateAnthropicKey=Je;exports.validateLicense=Se;
|
package/dist/index.d.cts
CHANGED
|
@@ -108,6 +108,30 @@ declare class InferenceRelay {
|
|
|
108
108
|
* Added in 1.6.2.
|
|
109
109
|
*/
|
|
110
110
|
warmup(): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Clear all provider-health state on this client's fallback engine.
|
|
113
|
+
*
|
|
114
|
+
* Use between bench tasks, between user sessions, or after handling a
|
|
115
|
+
* known-transient upstream incident (e.g., a subscription auth flap
|
|
116
|
+
* that's been resolved). Equivalent to calling `markHealthy` for every
|
|
117
|
+
* provider type — every provider's next call gets a fresh attempt.
|
|
118
|
+
*
|
|
119
|
+
* Added in 1.6.4. Replaces the deep-import workaround
|
|
120
|
+
* `client.fallbackEngine.resetHealth()` (which relied on TypeScript
|
|
121
|
+
* `private` being compile-time-only).
|
|
122
|
+
*/
|
|
123
|
+
resetHealth(): void;
|
|
124
|
+
/**
|
|
125
|
+
* Clear the unhealthy mark for a single provider type. Useful when you
|
|
126
|
+
* want to reset just (e.g.) `claude-cli` after a transient auth flap
|
|
127
|
+
* without disturbing other providers' degraded/rate-limited state.
|
|
128
|
+
*
|
|
129
|
+
* Provider type strings: `claude-cli`, `anthropic-api`, `openai-api`,
|
|
130
|
+
* `ollama`, plus any custom-provider type names you've registered.
|
|
131
|
+
*
|
|
132
|
+
* Added in 1.6.4.
|
|
133
|
+
*/
|
|
134
|
+
markHealthy(providerType: string): void;
|
|
111
135
|
dispose(): void;
|
|
112
136
|
private resolveProviders;
|
|
113
137
|
private executeMessage;
|
|
@@ -275,6 +299,13 @@ interface HealthRecord {
|
|
|
275
299
|
status: ProviderHealth['status'];
|
|
276
300
|
lastError?: string;
|
|
277
301
|
updatedAt: number;
|
|
302
|
+
/**
|
|
303
|
+
* TTL override in milliseconds. Optional — when omitted,
|
|
304
|
+
* `UNHEALTHY_TTL_DEFAULT_MS` is used. Set by `markUnhealthy` for
|
|
305
|
+
* classifications that auto-recover faster than the default (1.6.4
|
|
306
|
+
* adds 30s for `auth_failed`).
|
|
307
|
+
*/
|
|
308
|
+
ttlMs?: number;
|
|
278
309
|
}
|
|
279
310
|
declare class RelayError extends Error {
|
|
280
311
|
readonly code = "ALL_PROVIDERS_FAILED";
|
|
@@ -314,10 +345,24 @@ declare class FallbackEngine {
|
|
|
314
345
|
* stream_complete. Synchronous semantics — see telemetry/engine-events.ts.
|
|
315
346
|
*/
|
|
316
347
|
readonly engineEvents: EngineEventEmitter;
|
|
317
|
-
/**
|
|
318
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Default unhealthy TTL — appropriate for infrastructure outages
|
|
350
|
+
* (`gateway_unavailable`, `provider_incompatible`) that typically take
|
|
351
|
+
* minutes to resolve. Transient failure classes can override via the
|
|
352
|
+
* `ttlMs` arg to {@link markUnhealthy}.
|
|
353
|
+
*/
|
|
354
|
+
static readonly UNHEALTHY_TTL_DEFAULT_MS: number;
|
|
355
|
+
/**
|
|
356
|
+
* Shorter TTL for `auth_failed` (1.6.4). Token-rotation flaps and
|
|
357
|
+
* brief auth-backend hiccups are typically sub-second; 5 minutes was
|
|
358
|
+
* too aggressive a blast radius for what's usually transient. After
|
|
359
|
+
* 1.6.4's auth-retry in claude-cli provider, anything that survives
|
|
360
|
+
* the in-call retry is more likely to be a real auth problem — but
|
|
361
|
+
* still recoverable in seconds-to-tens-of-seconds, not minutes.
|
|
362
|
+
*/
|
|
363
|
+
static readonly UNHEALTHY_TTL_AUTH_MS: number;
|
|
319
364
|
getHealthStatus(providerType: string): HealthRecord['status'];
|
|
320
|
-
markUnhealthy(providerType: string, reason: string): void;
|
|
365
|
+
markUnhealthy(providerType: string, reason: string, ttlMs?: number): void;
|
|
321
366
|
markDegraded(providerType: string, reason: string): void;
|
|
322
367
|
markHealthy(providerType: string): void;
|
|
323
368
|
resetHealth(): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -108,6 +108,30 @@ declare class InferenceRelay {
|
|
|
108
108
|
* Added in 1.6.2.
|
|
109
109
|
*/
|
|
110
110
|
warmup(): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Clear all provider-health state on this client's fallback engine.
|
|
113
|
+
*
|
|
114
|
+
* Use between bench tasks, between user sessions, or after handling a
|
|
115
|
+
* known-transient upstream incident (e.g., a subscription auth flap
|
|
116
|
+
* that's been resolved). Equivalent to calling `markHealthy` for every
|
|
117
|
+
* provider type — every provider's next call gets a fresh attempt.
|
|
118
|
+
*
|
|
119
|
+
* Added in 1.6.4. Replaces the deep-import workaround
|
|
120
|
+
* `client.fallbackEngine.resetHealth()` (which relied on TypeScript
|
|
121
|
+
* `private` being compile-time-only).
|
|
122
|
+
*/
|
|
123
|
+
resetHealth(): void;
|
|
124
|
+
/**
|
|
125
|
+
* Clear the unhealthy mark for a single provider type. Useful when you
|
|
126
|
+
* want to reset just (e.g.) `claude-cli` after a transient auth flap
|
|
127
|
+
* without disturbing other providers' degraded/rate-limited state.
|
|
128
|
+
*
|
|
129
|
+
* Provider type strings: `claude-cli`, `anthropic-api`, `openai-api`,
|
|
130
|
+
* `ollama`, plus any custom-provider type names you've registered.
|
|
131
|
+
*
|
|
132
|
+
* Added in 1.6.4.
|
|
133
|
+
*/
|
|
134
|
+
markHealthy(providerType: string): void;
|
|
111
135
|
dispose(): void;
|
|
112
136
|
private resolveProviders;
|
|
113
137
|
private executeMessage;
|
|
@@ -275,6 +299,13 @@ interface HealthRecord {
|
|
|
275
299
|
status: ProviderHealth['status'];
|
|
276
300
|
lastError?: string;
|
|
277
301
|
updatedAt: number;
|
|
302
|
+
/**
|
|
303
|
+
* TTL override in milliseconds. Optional — when omitted,
|
|
304
|
+
* `UNHEALTHY_TTL_DEFAULT_MS` is used. Set by `markUnhealthy` for
|
|
305
|
+
* classifications that auto-recover faster than the default (1.6.4
|
|
306
|
+
* adds 30s for `auth_failed`).
|
|
307
|
+
*/
|
|
308
|
+
ttlMs?: number;
|
|
278
309
|
}
|
|
279
310
|
declare class RelayError extends Error {
|
|
280
311
|
readonly code = "ALL_PROVIDERS_FAILED";
|
|
@@ -314,10 +345,24 @@ declare class FallbackEngine {
|
|
|
314
345
|
* stream_complete. Synchronous semantics — see telemetry/engine-events.ts.
|
|
315
346
|
*/
|
|
316
347
|
readonly engineEvents: EngineEventEmitter;
|
|
317
|
-
/**
|
|
318
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Default unhealthy TTL — appropriate for infrastructure outages
|
|
350
|
+
* (`gateway_unavailable`, `provider_incompatible`) that typically take
|
|
351
|
+
* minutes to resolve. Transient failure classes can override via the
|
|
352
|
+
* `ttlMs` arg to {@link markUnhealthy}.
|
|
353
|
+
*/
|
|
354
|
+
static readonly UNHEALTHY_TTL_DEFAULT_MS: number;
|
|
355
|
+
/**
|
|
356
|
+
* Shorter TTL for `auth_failed` (1.6.4). Token-rotation flaps and
|
|
357
|
+
* brief auth-backend hiccups are typically sub-second; 5 minutes was
|
|
358
|
+
* too aggressive a blast radius for what's usually transient. After
|
|
359
|
+
* 1.6.4's auth-retry in claude-cli provider, anything that survives
|
|
360
|
+
* the in-call retry is more likely to be a real auth problem — but
|
|
361
|
+
* still recoverable in seconds-to-tens-of-seconds, not minutes.
|
|
362
|
+
*/
|
|
363
|
+
static readonly UNHEALTHY_TTL_AUTH_MS: number;
|
|
319
364
|
getHealthStatus(providerType: string): HealthRecord['status'];
|
|
320
|
-
markUnhealthy(providerType: string, reason: string): void;
|
|
365
|
+
markUnhealthy(providerType: string, reason: string, ttlMs?: number): void;
|
|
321
366
|
markDegraded(providerType: string, reason: string): void;
|
|
322
367
|
markHealthy(providerType: string): void;
|
|
323
368
|
resetHealth(): void;
|
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 Ze=Object.defineProperty;var et=(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 tt=(n,e)=>()=>(n&&(e=n(n=0)),e);var rt=(n,e)=>{for(var t in e)Ze(n,t,{get:e[t],enumerable:true});};var Ne={};rt(Ne,{detectCLI:()=>V});function ft(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 V(){if(!ft("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&&!yt.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 yt,ne=tt(()=>{yt=["2.1.87"];});var
|
|
2
|
+
var Ze=Object.defineProperty;var et=(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 tt=(n,e)=>()=>(n&&(e=n(n=0)),e);var rt=(n,e)=>{for(var t in e)Ze(n,t,{get:e[t],enumerable:true});};var Ne={};rt(Ne,{detectCLI:()=>V});function ft(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 V(){if(!ft("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&&!yt.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 yt,ne=tt(()=>{yt=["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 O(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(g=>g(...f));}async function*y(){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=y(),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,g)=>{d=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(d))}};return E}var C=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 O(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-----`,ge={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>"},D=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:ge,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:ge,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},nt=new D;function Ie(){nt.clearCache();}function st(){return ge}function it(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 ut=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function be(n){return join(homedir(),".inference-relay","gateway",n)}function Me(n){return join(be(n),"bundle.js")}function Oe(n){return join(be(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},x=class extends b{constructor(e,t){super(e,"GATEWAY_FETCH_FAILED",t);}},K=new Map,dt=[0,1e3,4e3];function pt(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 dt}var G=class{static async load(e,t,r=ut,s){let i=`${t}:${e.slice(-8)}`;if(K.has(i))return K.get(i);try{let m=await this.tryLoadFromDisk(t);if(m)return S("loader.cache-hit",{libraryVersion:t}),K.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 b("[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(Me(t),a),writeFileSync(Oe(t),JSON.stringify({sha256:o,signature:l,libraryVersion:p}));}catch{}let y=this.loadIntoVm(a.toString("utf-8"));return K.set(i,y),y}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=Me(e),r=Oe(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=pt(s?.retryDelaysMs),o;for(let y=0;y<a.length;y++){let m=a[y];m>0&&await new Promise(c=>setTimeout(c,m)),S("loader.fetch",{url:`${r}/v1/gateway/fetch`,libraryVersion:t,attempt:y+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:y+1}),c.status===401||c.status===403)throw new b("[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 b&&c.code==="LICENSE_REJECTED")throw c;o=c;}}if(o||!i)throw o instanceof b?o:new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)",o);let l;try{l=await fetch(i.bundleUrl);}catch(y){throw new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)",y)}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 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(){K.clear();}};var _t="1.6.3",se=class extends C{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,_t,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 b?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(()=>(ne(),Ne));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 W=[{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}}],$=Object.fromEntries(W.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));$["claude-sonnet-4"]="claude-sonnet-4-20250514";$["claude-opus-4"]="claude-opus-4-20250514";$["claude-haiku-4"]="claude-haiku-4-5-20251001";function Ee(n){return $[n]||n}function bt(n){return W.find(e=>e.canonical===n)}function ie(n){return W.find(e=>e.canonical===n)?.provider}function Et(n){return W.filter(e=>e.provider===n)}var vt="https://api.anthropic.com/v1/messages",Rt="2023-06-01",ve={"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 Ue(n){if(ve[n])return ve[n];for(let[e,t]of Object.entries(ve))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Y=class extends C{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(/\/$/,"")||vt,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]=Ue(a.model||e.model),u=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*p)/1e6,y={},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&&(y[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(y).length>0?y: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 y=o.split(`
|
|
11
|
-
`);o=y.pop()||"";let m=null;for(let c of y)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]=Ue(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":
|
|
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:y||{}},yield {type:"message_stop"},u=!0;return}try{let g=JSON.parse(h);g.usage&&(y={input_tokens:g.usage.prompt_tokens||0,output_tokens:g.usage.completion_tokens||0});let
|
|
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=Pt(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 je=200;function ae(n,e){if(e instanceof b)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,je)||"unknown"}`}function Ke(n){let e=n.filter(t=>t.includes(":failed:"));return e.length===0?false:e.every(t=>t.endsWith(":failed:request_too_large"))}var Ge=new Set(["anthropic-api","openai-api","ollama"]),N=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}},z=class extends N{constructor(e){super(e);}};function Ve(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 Ae(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.includes("prompt is too long")||t.includes("prompt too long")||t.includes("input length")||t.includes("input is too long")||t.includes("context_length_exceeded")||t.includes("context length exceeded")||t.includes("request too large")||t.includes("tokens exceed")||t.includes("exceeds the maximum")||t.includes("too many tokens")?"request_too_large":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 We(n){return [...n].sort((e,t)=>e.priority-t.priority)}var X=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=We(t),i=[],a=Ve(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=ie(e.model);if(m&&m!==u&&Ge.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(Ae(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(ae(u,c));break;case "request_too_large":i.push(`${u}:failed:request_too_large`);break;default:i.push(ae(u,c));break}}}throw S("engine.cascade-exhausted",{chain:i,mode:"execute"}),Ke(i)?new z(i):new N(i)}async stream(e,t,r){let s=randomUUID(),i=We(t),a=Ve(e),o=Date.now(),l=[],p=null,u=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 R=ie(e.model);if(R&&R!==g&&Ge.has(g)){l.push(`${g}:skipped:wrong_provider`);continue}try{u=await h.streamRaw(e,{signal:r?.signal}),p=h,l.push(`${g}:success`);break}catch(_){if(_?.name==="AbortError"||r?.signal?.aborted)throw _;switch(Ae(_)){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(ae(g,_));break;case "request_too_large":l.push(`${g}:failed:request_too_large`);break;default:l.push(ae(g,_));break}}}if(!p||!u)throw S("engine.cascade-exhausted",{chain:l,mode:"stream"}),Ke(l)?new z(l):new N(l);let m=this,c=r?.maxMidStreamFailovers??2,E=new Set([p]);async function*d(){let h=p,g=u[Symbol.asyncIterator](),R={role:"assistant",content:[]},_={segments:[]},I=$e(h.type);_.segments.push(I);let ke=0,Z=null,ee=false,he=c,F="",B="";for(m.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 L=A.value,P=Lt(L,ke,R,ee,Z);if(P.action==="suppress"){"coalesceMode"in P&&(Z=P.coalesceMode),P.clearedJustFailedOver&&(ee=!1);continue}P.coalesceModeCleared&&(Z=null),P.clearedJustFailedOver&&(ee=!1);let v=P.event;if(xt(R,v),v.type==="message_start"){if(_.segments.length>1)continue;F=v.message?.model||F,v.message?.usage?.input_tokens!=null&&(I.inputTokens=v.message.usage.input_tokens);}if(v.type==="message_delta"&&(v.delta?.stop_reason&&(B=v.delta.stop_reason),v.usage)){It(I,h.type,v.usage),yield {...v,usage:void 0};continue}if(v.type==="message_stop")break;yield v;}if(R.content.length===0&&I.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:{...I}});let w=Ye(_.segments);yield {type:"message_delta",delta:{stop_reason:B||"end_turn"},usage:w},yield {type:"message_stop"},m.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:F,inputTokens:w.input_tokens,outputTokens:w.output_tokens,costUsd:_.segments.reduce((A,L)=>A+L.costUsd,0),userCostUsd:_.segments.reduce((A,L)=>A+L.userCostUsd,0),durationMs:Date.now()-o,stopReason:B||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(w){if(w?.name==="AbortError"||r?.signal?.aborted)throw w;let A=Ae(w);try{await g.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:qe(R),errorClass:A,retriesLeft:he}),l.push(`${h.type}:partial(${qe(R)}b)`),he<=0)throw m.emitTerminalExhaustion(s,_,F,B,l,o,r?.licenseState),w;let L=Mt(R.content),P=[...e.messages,{role:"assistant",content:L}],v=null,te=null,Pe=h;for(;;){let T=m.nextHealthyProvider(i,Pe,a,E);if(!T)break;Pe=T,E.add(T);let Qe={...e,messages:P,...T.type!=="anthropic-api"&&T.type!=="claude-cli"?{system:Ot(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{te=await T.streamRaw(Qe,{signal:r?.signal}),v=T;break}catch(Te){m.markUnhealthy(T.type,String(Te)),l.push(`${T.type}:failed_connect:${String(Te).slice(0,je)}`);}}if(!v||!te)throw m.emitTerminalExhaustion(s,_,F,B,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}),ke=Dt(R)+1,he--,h=v,g=te[Symbol.asyncIterator](),ee=true,Z=null,I=$e(h.type),_.segments.push(I),m.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type});}}let f=d();return r?.licenseState==="SEC_DEGRADED"&&(f=Nt(f)),O(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=Ye(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 $e(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function It(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 Ye(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function xt(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 Lt(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 Mt(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 Ot(n,e){return n?`${n}
|
|
10
|
+
-----END PUBLIC KEY-----`,ge={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>"},D=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:ge,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:ge,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},nt=new D;function Ie(){nt.clearCache();}function st(){return ge}function it(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 ut=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";function be(n){return join(homedir(),".inference-relay","gateway",n)}function Me(n){return join(be(n),"bundle.js")}function Oe(n){return join(be(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},x=class extends b{constructor(e,t){super(e,"GATEWAY_FETCH_FAILED",t);}},K=new Map,dt=[0,1e3,4e3];function pt(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 dt}var G=class{static async load(e,t,r=ut,s){let i=`${t}:${e.slice(-8)}`;if(K.has(i))return K.get(i);try{let m=await this.tryLoadFromDisk(t);if(m)return S("loader.cache-hit",{libraryVersion:t}),K.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 b("[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(Me(t),a),writeFileSync(Oe(t),JSON.stringify({sha256:o,signature:l,libraryVersion:p}));}catch{}let y=this.loadIntoVm(a.toString("utf-8"));return K.set(i,y),y}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=Me(e),r=Oe(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=pt(s?.retryDelaysMs),o;for(let y=0;y<a.length;y++){let m=a[y];m>0&&await new Promise(c=>setTimeout(c,m)),S("loader.fetch",{url:`${r}/v1/gateway/fetch`,libraryVersion:t,attempt:y+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:y+1}),c.status===401||c.status===403)throw new b("[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 b&&c.code==="LICENSE_REJECTED")throw c;o=c;}}if(o||!i)throw o instanceof b?o:new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)",o);let l;try{l=await fetch(i.bundleUrl);}catch(y){throw new x("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)",y)}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 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(){K.clear();}};var _t="1.6.4",se=class extends C{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,_t,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 b?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(()=>(ne(),Ne));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 W=[{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}}],$=Object.fromEntries(W.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));$["claude-sonnet-4"]="claude-sonnet-4-20250514";$["claude-opus-4"]="claude-opus-4-20250514";$["claude-haiku-4"]="claude-haiku-4-5-20251001";function Ee(n){return $[n]||n}function bt(n){return W.find(e=>e.canonical===n)}function ie(n){return W.find(e=>e.canonical===n)?.provider}function Et(n){return W.filter(e=>e.provider===n)}var vt="https://api.anthropic.com/v1/messages",At="2023-06-01",ve={"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 Ue(n){if(ve[n])return ve[n];for(let[e,t]of Object.entries(ve))if(n.startsWith(e.split("-20")[0]))return t;return [3,15]}var Y=class extends C{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(/\/$/,"")||vt,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]=Ue(a.model||e.model),u=((a.usage?.input_tokens||0)*l+(a.usage?.output_tokens||0)*p)/1e6,y={},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&&(y[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(y).length>0?y: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 y=o.split(`
|
|
11
|
+
`);o=y.pop()||"";let m=null;for(let c of y)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]=Ue(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":At};return this.dangerousDirectBrowserAccess&&(e["anthropic-dangerous-direct-browser-access"]="true"),e}buildRequestBody(e,t){let r={model:Ee(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 Rt="https://api.openai.com/v1/chat/completions",Fe=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],Ae={"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 He(n){if(Ae[n])return Ae[n];for(let[e,t]of Object.entries(Ae))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 St(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 q=class extends C{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(/\/$/,"")||Rt;}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,y=a.usage?.completion_tokens||0,[m,c]=He(a.model||e.model),E=(u*m+y*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 g=i.headers.get(h);g&&(d[h]=g);}return {content:p,model:a.model||e.model,usage:{input_tokens:u,output_tokens:y},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,y,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:y||{}},yield {type:"message_stop"},u=!0;return}try{let g=JSON.parse(h);g.usage&&(y={input_tokens:g.usage.prompt_tokens||0,output_tokens:g.usage.completion_tokens||0});let A=g.choices?.[0];if(!A)continue;let _=A.delta;_?.content&&!p&&(p=!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}}),A.finish_reason&&(p&&(yield {type:"content_block_stop",index:0}),m=Be(A.finish_reason));}catch{}}}u||(yield {type:"message_delta",delta:{stop_reason:m||"end_turn"},usage:y||{}},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]=He(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(!Fe.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 (${Fe.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=St(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 wt="http://localhost:11434";function kt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Pt(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:kt(r.content)});return t}var j=class extends C{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(/\/$/,"")||wt;}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:y,value:m}=await i.read();if(y)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=Pt(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 je=200;function ae(n,e){if(e instanceof b)return `${n}:failed:${e.code}:${e.message}`;let t=e?.message;return `${n}:failed:${t?.slice(0,je)||"unknown"}`}function Ke(n){let e=n.filter(t=>t.includes(":failed:"));return e.length===0?false:e.every(t=>t.endsWith(":failed:request_too_large"))}var Ge=new Set(["anthropic-api","openai-api","ollama"]),N=class extends Error{code="ALL_PROVIDERS_FAILED";fallbackChain;constructor(e){super(`All providers failed. Chain: ${e.join(" \u2192 ")}`),this.name="RelayError",this.fallbackChain=e;}},z=class extends N{constructor(e){super(e);}};function Ve(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 Re(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.includes("prompt is too long")||t.includes("prompt too long")||t.includes("input length")||t.includes("input is too long")||t.includes("context_length_exceeded")||t.includes("context length exceeded")||t.includes("request too large")||t.includes("tokens exceed")||t.includes("exceeds the maximum")||t.includes("too many tokens")?"request_too_large":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 We(n){return [...n].sort((e,t)=>e.priority-t.priority)}var X=class n{healthMap=new Map;engineEvents=new J;static UNHEALTHY_TTL_DEFAULT_MS=300*1e3;static UNHEALTHY_TTL_AUTH_MS=30*1e3;getHealthStatus(e){let t=this.healthMap.get(e);if(!t)return "healthy";let r=t.ttlMs??n.UNHEALTHY_TTL_DEFAULT_MS;if(t.status==="unhealthy"&&Date.now()-t.updatedAt>=r){let s=Date.now()-t.updatedAt;return this.healthMap.delete(e),S("engine.recovered",{providerType:e,ageMs:s,ttlMs:r}),"healthy"}return t.status}markUnhealthy(e,t,r){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now(),ttlMs:r}),S("engine.unhealthy",{providerType:e,reason:t,ttlMs:r});}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=We(t),i=[],a=Ve(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=ie(e.model);if(m&&m!==u&&Ge.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(Re(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",n.UNHEALTHY_TTL_AUTH_MS),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(ae(u,c));break;case "request_too_large":i.push(`${u}:failed:request_too_large`);break;default:i.push(ae(u,c));break}}}throw S("engine.cascade-exhausted",{chain:i,mode:"execute"}),Ke(i)?new z(i):new N(i)}async stream(e,t,r){let s=randomUUID(),i=We(t),a=Ve(e),o=Date.now(),l=[],p=null,u=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 A=ie(e.model);if(A&&A!==g&&Ge.has(g)){l.push(`${g}:skipped:wrong_provider`);continue}try{u=await h.streamRaw(e,{signal:r?.signal}),p=h,l.push(`${g}:success`);break}catch(_){if(_?.name==="AbortError"||r?.signal?.aborted)throw _;switch(Re(_)){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",n.UNHEALTHY_TTL_AUTH_MS),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(ae(g,_));break;case "request_too_large":l.push(`${g}:failed:request_too_large`);break;default:l.push(ae(g,_));break}}}if(!p||!u)throw S("engine.cascade-exhausted",{chain:l,mode:"stream"}),Ke(l)?new z(l):new N(l);let m=this,c=r?.maxMidStreamFailovers??2,E=new Set([p]);async function*d(){let h=p,g=u[Symbol.asyncIterator](),A={role:"assistant",content:[]},_={segments:[]},I=$e(h.type);_.segments.push(I);let ke=0,Z=null,ee=false,he=c,F="",H="";for(m.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type});;)try{for(;;){let R=await g.next();if(R.done)break;let L=R.value,P=Lt(L,ke,A,ee,Z);if(P.action==="suppress"){"coalesceMode"in P&&(Z=P.coalesceMode),P.clearedJustFailedOver&&(ee=!1);continue}P.coalesceModeCleared&&(Z=null),P.clearedJustFailedOver&&(ee=!1);let v=P.event;if(xt(A,v),v.type==="message_start"){if(_.segments.length>1)continue;F=v.message?.model||F,v.message?.usage?.input_tokens!=null&&(I.inputTokens=v.message.usage.input_tokens);}if(v.type==="message_delta"&&(v.delta?.stop_reason&&(H=v.delta.stop_reason),v.usage)){It(I,h.type,v.usage),yield {...v,usage:void 0};continue}if(v.type==="message_stop")break;yield v;}if(A.content.length===0&&I.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:{...I}});let w=Ye(_.segments);yield {type:"message_delta",delta:{stop_reason:H||"end_turn"},usage:w},yield {type:"message_stop"},m.emitEngineEvent({kind:"stream_complete",callId:s,id:randomUUID(),ts:Date.now(),stitched:_.segments.length>1,segments:_.segments.map(R=>({...R})),provider:_.segments.map(R=>R.provider).join("+"),model:F,inputTokens:w.input_tokens,outputTokens:w.output_tokens,costUsd:_.segments.reduce((R,L)=>R+L.costUsd,0),userCostUsd:_.segments.reduce((R,L)=>R+L.userCostUsd,0),durationMs:Date.now()-o,stopReason:H||"end_turn",fallbackChain:l,rateLimitHit:!1,securityState:r?.licenseState});return}catch(w){if(w?.name==="AbortError"||r?.signal?.aborted)throw w;let R=Re(w);try{await g.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:qe(A),errorClass:R,retriesLeft:he}),l.push(`${h.type}:partial(${qe(A)}b)`),he<=0)throw m.emitTerminalExhaustion(s,_,F,H,l,o,r?.licenseState),w;let L=Mt(A.content),P=[...e.messages,{role:"assistant",content:L}],v=null,te=null,Pe=h;for(;;){let T=m.nextHealthyProvider(i,Pe,a,E);if(!T)break;Pe=T,E.add(T);let Qe={...e,messages:P,...T.type!=="anthropic-api"&&T.type!=="claude-cli"?{system:Ot(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{te=await T.streamRaw(Qe,{signal:r?.signal}),v=T;break}catch(Te){m.markUnhealthy(T.type,String(Te)),l.push(`${T.type}:failed_connect:${String(Te).slice(0,je)}`);}}if(!v||!te)throw m.emitTerminalExhaustion(s,_,F,H,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}),ke=Dt(A)+1,he--,h=v,g=te[Symbol.asyncIterator](),ee=true,Z=null,I=$e(h.type),_.segments.push(I),m.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:h.type});}}let f=d();return r?.licenseState==="SEC_DEGRADED"&&(f=Nt(f)),O(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=Ye(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 $e(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function It(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 Ye(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function xt(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 Lt(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 Mt(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 Ot(n,e){return n?`${n}
|
|
14
14
|
|
|
15
|
-
${e}`:e}function qe(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 Dt(n){return Math.max(0,n.content.length-1)}async function*Nt(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}ne();function oe(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 le(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var Ce={"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 ce(n){if(Ce[n])return Ce[n];for(let[e,t]of Object.entries(Ce))if(n.startsWith(e))return t;return [3,15]}function ue(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]=ce(n.model),a=(t*s+r*i)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(a*1e4)/1e4,model:n.model,provider:""}}var U=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 Ut="https://api.inference-relay.com",Ft="/v1/validate",
|
|
15
|
+
${e}`:e}function qe(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 Dt(n){return Math.max(0,n.content.length-1)}async function*Nt(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}ne();function oe(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 le(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var Ce={"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 ce(n){if(Ce[n])return Ce[n];for(let[e,t]of Object.entries(Ce))if(n.startsWith(e))return t;return [3,15]}function ue(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]=ce(n.model),a=(t*s+r*i)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(a*1e4)/1e4,model:n.model,provider:""}}var U=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 Ut="https://api.inference-relay.com",Ft="/v1/validate",Ht=1440*60*1e3,Bt=10080*60*1e3,Kt=`-----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-----`,M=new Map;async function Se(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||Ut)+Ft;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<Ht?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'),y=await u(Kt,"RS256"),{payload:m}=await p(o.jws,y);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?Bt:6e4}),l}var we=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new D;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new X,this.telemetryReporter=new U({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=le(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=Se(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 H({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 Se(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 V();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=ue(e),r=this.routingFn(e,t);return oe(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 se(this.config.licenseKey,{retryDelaysMs:this.config.gatewayRetryDelaysMs});case "anthropic-api":return e.apiKey?new Y({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new q({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new j({baseUrl:e.baseUrl});default:return null}}};function Gt(n){if(!n)return 0;if(typeof n=="string")return Math.ceil(n.length/4);if(!Array.isArray(n))return 0;let e=0;for(let t of n){if(!t||typeof t!="object")continue;let r=t;if(r.type==="image"||r.type==="image_url"){e+=1500;continue}if(typeof r.text=="string"){e+=Math.ceil(r.text.length/4);continue}try{e+=Math.ceil(JSON.stringify(t).length/4);}catch{e+=50;}}return e}function Vt(n){return 8+Gt(n.content)}function Wt(n){let e=50;typeof n.system=="string"&&(e+=Math.ceil(n.system.length/4));for(let t of n.messages)e+=Vt(t);return e}ne();var $t="https://api.anthropic.com/v1/messages",Yt="2023-06-01";async function Je(n){try{let e=await fetch($t,{method:"POST",headers:{"content-type":"application/json","x-api-key":n,"anthropic-version":Yt},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 de=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=et("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 Q="AES-GCM";var pe=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,Q,false,["encrypt","decrypt"]);}else {this.cryptoKey=await crypto.subtle.generateKey({name:Q,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:Q,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:Q,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:Q,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 me=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{Y as AnthropicAPIProvider,C as BaseProvider,de as ElectronCredentialStore,J as EngineEventEmitter,X as FallbackEngine,G as GatewayLoader,b as GatewayLoaderError,x as GatewayUnavailableError,pe as IndexedDBCredentialStore,we as InferenceRelay,$ as MODEL_ALIASES,W as MODEL_REGISTRY,D as ManifestDecryptor,me as MemoryCredentialStore,j as OllamaProvider,q as OpenAIAPIProvider,
|
|
23
|
+
-----END PUBLIC KEY-----`,M=new Map;async function Se(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||Ut)+Ft;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<Bt?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'),y=await u(Kt,"RS256"),{payload:m}=await p(o.jws,y);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?Ht:6e4}),l}var we=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new D;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new X,this.telemetryReporter=new U({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=le(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=Se(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 Se(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 V();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();}resetHealth(){this.fallbackEngine.resetHealth();}markHealthy(e){this.fallbackEngine.markHealthy(e);}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=ue(e),r=this.routingFn(e,t);return oe(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 se(this.config.licenseKey,{retryDelaysMs:this.config.gatewayRetryDelaysMs});case "anthropic-api":return e.apiKey?new Y({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new q({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new j({baseUrl:e.baseUrl});default:return null}}};function Gt(n){if(!n)return 0;if(typeof n=="string")return Math.ceil(n.length/4);if(!Array.isArray(n))return 0;let e=0;for(let t of n){if(!t||typeof t!="object")continue;let r=t;if(r.type==="image"||r.type==="image_url"){e+=1500;continue}if(typeof r.text=="string"){e+=Math.ceil(r.text.length/4);continue}try{e+=Math.ceil(JSON.stringify(t).length/4);}catch{e+=50;}}return e}function Vt(n){return 8+Gt(n.content)}function Wt(n){let e=50;typeof n.system=="string"&&(e+=Math.ceil(n.system.length/4));for(let t of n.messages)e+=Vt(t);return e}ne();var $t="https://api.anthropic.com/v1/messages",Yt="2023-06-01";async function Je(n){try{let e=await fetch($t,{method:"POST",headers:{"content-type":"application/json","x-api-key":n,"anthropic-version":Yt},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 de=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=et("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 Q="AES-GCM";var pe=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,Q,false,["encrypt","decrypt"]);}else {this.cryptoKey=await crypto.subtle.generateKey({name:Q,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:Q,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:Q,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:Q,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 me=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{Y as AnthropicAPIProvider,C as BaseProvider,de as ElectronCredentialStore,J as EngineEventEmitter,X as FallbackEngine,G as GatewayLoader,b as GatewayLoaderError,x as GatewayUnavailableError,pe as IndexedDBCredentialStore,we as InferenceRelay,$ as MODEL_ALIASES,W as MODEL_REGISTRY,D as ManifestDecryptor,me as MemoryCredentialStore,j as OllamaProvider,q as OpenAIAPIProvider,B as RelayCapExceededError,N as RelayError,z as RequestTooLargeError,U as TelemetryReporter,oe as applyRouting,O as createRelayStream,le as createRoutingFunction,V as detectCLI,ue as estimateCost,Wt as estimateInputTokens,bt as findModel,st as getLastKnownGoodManifest,ce as getModelPricing,it as getValue,Et as modelsForProvider,Ee as normalizeModel,ie as providerForModel,Je as validateAnthropicKey,Se as validateLicense};
|