inference-relay 1.4.0
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/LICENSE +9 -0
- package/README.md +94 -0
- package/dist/analytics/index.cjs +1 -0
- package/dist/analytics/index.d.cts +1 -0
- package/dist/analytics/index.d.ts +1 -0
- package/dist/analytics/index.js +0 -0
- package/dist/auto.js +2 -0
- package/dist/cli/main.js +24 -0
- package/dist/index-B20BqToz.d.cts +230 -0
- package/dist/index-B20BqToz.d.ts +230 -0
- package/dist/index.cjs +24 -0
- package/dist/index.d.cts +716 -0
- package/dist/index.d.ts +716 -0
- package/dist/index.js +24 -0
- package/dist/instruction/index.cjs +1 -0
- package/dist/instruction/index.d.cts +2 -0
- package/dist/instruction/index.d.ts +2 -0
- package/dist/instruction/index.js +0 -0
- package/dist/pool/index.cjs +1 -0
- package/dist/pool/index.d.cts +2 -0
- package/dist/pool/index.d.ts +2 -0
- package/dist/pool/index.js +0 -0
- package/dist/stream/index.cjs +2 -0
- package/dist/stream/index.d.cts +12 -0
- package/dist/stream/index.d.ts +12 -0
- package/dist/stream/index.js +2 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
inference-relay Commercial License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 L2B II LLC. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software is proprietary. You may not use, copy, modify, merge, publish,
|
|
6
|
+
distribute, sublicense, or sell copies of this software without a valid
|
|
7
|
+
license key purchased from inference-relay.dev.
|
|
8
|
+
|
|
9
|
+
For licensing inquiries: support@inference-relay.dev
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# inference-relay
|
|
2
|
+
|
|
3
|
+
Route AI inference through your users' existing subscriptions. 98.9% average cost reduction.
|
|
4
|
+
|
|
5
|
+
> **Patent Pending.** (c) 2026 L2B II LLC. Proprietary — see [LICENSE](./LICENSE).
|
|
6
|
+
|
|
7
|
+
## Quickstart
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm install inference-relay
|
|
11
|
+
export IR_LICENSE_KEY=ir_live_xxxx
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import 'inference-relay/auto';
|
|
16
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
17
|
+
|
|
18
|
+
// Your existing code works unchanged. Inference routes through user's subscription.
|
|
19
|
+
const msg = await client.messages.create({
|
|
20
|
+
model: 'claude-sonnet-4-20250514',
|
|
21
|
+
max_tokens: 1024,
|
|
22
|
+
messages: [{ role: 'user', content: 'Analyze this contract...' }],
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The library automatically bridges existing SDK instances to the native gateway.
|
|
27
|
+
|
|
28
|
+
## How It Works
|
|
29
|
+
|
|
30
|
+
The library performs an asymmetric handshake with the Protocol Authority to synchronize execution parameters. It then bridges your SDK instances to the Native Subscription Gateway, routing heavy inference through the user's own authorized execution environment. Your application pays only for lightweight orchestration calls.
|
|
31
|
+
|
|
32
|
+
## Cost Savings
|
|
33
|
+
|
|
34
|
+
| Workflow | Traditional | With Relay | Savings |
|
|
35
|
+
|----------|------------|------------|---------|
|
|
36
|
+
| Document Analysis (Sonnet) | $0.12/doc | $0.0003/doc | 99.7% |
|
|
37
|
+
| Code Review (Sonnet) | $0.08/review | $0.0002/review | 99.7% |
|
|
38
|
+
| Chat Agent (Haiku orchestration + Sonnet execution) | $0.15/session | $0.001/session | 99.3% |
|
|
39
|
+
|
|
40
|
+
Resource Utilization Efficiency averages 98.9% across production workloads.
|
|
41
|
+
|
|
42
|
+
## Provider Support
|
|
43
|
+
|
|
44
|
+
| Provider | Type | Cost to Developer | Platform |
|
|
45
|
+
|----------|------|-------------------|----------|
|
|
46
|
+
| Native Subscription Gateway (Claude CLI) | Subscription relay | $0.00 | Desktop |
|
|
47
|
+
| Anthropic API | Direct API | Standard pricing | Any |
|
|
48
|
+
| OpenAI API | Direct API | Standard pricing | Any |
|
|
49
|
+
| Ollama | Local inference | $0.00 (local) | Any |
|
|
50
|
+
|
|
51
|
+
## Privacy Guarantee
|
|
52
|
+
|
|
53
|
+
inference-relay is a dumb pipe. The `promptContent` field is typed as `false` -- a compile-time literal, not a runtime flag. Prompt and response content never touches relay infrastructure. Only metadata (model, token count, routing decision) transits the coordination layer.
|
|
54
|
+
|
|
55
|
+
See [Security Documentation](https://inference-relay.com/docs/security) for the full audit trail architecture.
|
|
56
|
+
|
|
57
|
+
## Integration Levels
|
|
58
|
+
|
|
59
|
+
1. **Auto-patch** -- `import 'inference-relay/auto'` -- Zero code changes. Patches SDK prototypes at import.
|
|
60
|
+
2. **Explicit** -- `import { relay } from 'inference-relay'` -- Wrap specific clients for granular control.
|
|
61
|
+
3. **Environment Variable** -- Set `IR_PROVIDER=claude-cli` -- Route without any code changes.
|
|
62
|
+
|
|
63
|
+
## Architecture (v1.3+)
|
|
64
|
+
|
|
65
|
+
Starting in v1.3, the Native Subscription Gateway implementation is distributed separately from the npm package. On first use of a subscription-routed call, the library downloads a signed implementation bundle from the Protocol Authority under your license key, verifies its RS256 signature against an embedded public key, and caches it locally at `~/.inference-relay/gateway/<version>/bundle.js`. Subsequent calls in the same process use the cached, in-memory module — zero extra latency.
|
|
66
|
+
|
|
67
|
+
The npm package contains the public SDK surface, the routing engine, the fallback cascade, the API providers (Anthropic, OpenAI, Ollama), and the gateway loader. It does **not** contain the gateway implementation itself.
|
|
68
|
+
|
|
69
|
+
**Cold start:** ~1-3s for the first call (download + verify + load). **Warm start:** ~50-200ms (cache hit + verify + load). **Subsequent calls:** zero overhead.
|
|
70
|
+
|
|
71
|
+
**Airgapped environments:** run `inference-relay gateway pre-fetch` from a connected machine to populate `~/.inference-relay/gateway/`, then transport the directory.
|
|
72
|
+
|
|
73
|
+
**License termination:** When a license is revoked, the next gateway probe fails closed. The relay returns a structured `LICENSE_REJECTED` error and falls back to API providers if configured.
|
|
74
|
+
|
|
75
|
+
## Pricing
|
|
76
|
+
|
|
77
|
+
| Plan | Price | Includes |
|
|
78
|
+
|------|-------|----------|
|
|
79
|
+
| Solo | $50/mo | 1 developer seat, all providers, email support |
|
|
80
|
+
| Pro | $100/mo | 5 developer seats, 5,000 calls/mo, priority routing, analytics dashboard |
|
|
81
|
+
| Enterprise | Custom | Dedicated support, on-prem relay option |
|
|
82
|
+
|
|
83
|
+
A valid license key is required to use the relay. [View pricing](https://inference-relay.com/pricing).
|
|
84
|
+
|
|
85
|
+
## Links
|
|
86
|
+
|
|
87
|
+
- [Documentation](https://inference-relay.com/docs)
|
|
88
|
+
- [Pricing](https://inference-relay.com/pricing)
|
|
89
|
+
- [Dashboard](https://inference-relay.com/dashboard)
|
|
90
|
+
- [Advisory Opinion](https://inference-relay.com/advisory-opinion)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
(c) 2026 L2B II LLC. Proprietary. All rights reserved.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { A as AuditEvent } from '../index-B20BqToz.cjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { A as AuditEvent } from '../index-B20BqToz.js';
|
|
File without changes
|
package/dist/auto.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! inference-relay/auto (c) 2026 L2B II LLC. Patent pending. */
|
|
2
|
+
import{InferenceRelay as h}from"inference-relay";const p={"claude-sonnet-4-6":"claude-sonnet-4-20250514","claude-opus-4-6":"claude-opus-4-20250514","claude-haiku-4-5":"claude-haiku-4-5-20251001"};function d(e){return p[e]||e}let i=null,c=null,y=0;const w=3e4;async function R(){return i||c||(Date.now()-y<w?null:(c=(async()=>{y=Date.now();try{return i=await h.autoDetect({licenseKey:process.env.IR_LICENSE_KEY||""}),i}catch(e){const a=e?.message||"unknown";return a.includes("License")?console.warn("[inference-relay] License invalid \u2014 falling through to original SDK."):console.warn("[inference-relay] Auto-detect failed:",a),c=null,null}})(),c))}let f=!1;async function I(){if(f)return;f=!0;let e;try{e=await import("@anthropic-ai/sdk")}catch{return}const a=e.default||e.Anthropic;if(!a)return;let l;try{l=new a({apiKey:"dummy-for-prototype-access"}).messages?.constructor}catch{try{l=e.Messages||e.default?.Messages||a?.Messages}catch{return}}if(!l?.prototype?.create)return;const o=l.prototype.create;l.prototype.create=async function(r,u){const s=await R();if(!s){const t={...r,model:d(r.model)};return o.call(this,t,u)}try{if(r.stream)return await s.messages.create({...r,stream:!0});const t=await s.messages.create(r),n={...t};return Object.defineProperty(n,"provider",{value:t.provider,enumerable:!0}),Object.defineProperty(n,"fallbackChain",{value:t.fallbackChain,enumerable:!0}),n}catch(t){const n=t?.message||"unknown",m=n.includes("License")||n.includes("license")?"license_error":n.includes("timeout")||n.includes("aborted")?"timeout":n.includes("rate limit")||n.includes("429")?"rate_limited":n.includes("cap exceeded")?"cap_exceeded":"relay_error";console.warn(`[inference-relay] Relay call failed (${m}): ${n.substring(0,80)}. Falling through to original SDK.`);const g={...r,model:d(r.model)};return o.call(this,g,u)}}}await I().catch(e=>{console.warn("[inference-relay] Auto-patch failed:",e?.message||"unknown error"),console.warn("[inference-relay] Falling through to original Anthropic SDK.")});
|
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {mkdirSync,writeFileSync,existsSync,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 Et=Object.defineProperty;var E=(n,e)=>()=>(n&&(e=n(n=0)),e);var Te=(n,e)=>{for(var t in e)Et(n,t,{get:e[t],enumerable:true});};var U,pe=E(()=>{U=class n extends Error{code="RELAY_CAP_EXCEEDED";tier;baseCap;topUps;effectiveCap;usedThisCycle;resolutionUrl;constructor(e){let t=e.resolutionUrl??"https://inference-relay.com/dashboard/billing?topup=1";super(`Cap reached (${e.usedThisCycle} / ${e.effectiveCap??"\u221E"} calls this cycle). Buy a top-up or upgrade at ${t}`),this.name="RelayCapExceededError",this.tier=e.tier,this.baseCap=e.baseCap,this.topUps=e.topUps,this.effectiveCap=e.effectiveCap,this.usedThisCycle=e.usedThisCycle,this.resolutionUrl=t,Object.setPrototypeOf(this,n.prototype);}};});function j(n,e){let t=new Map,r=null,s=null,a=new Promise((u,y)=>{r=u,s=y;});a.catch(()=>{});let i=[],l=null,o="",d="";function c(u,...y){let g=t.get(u);g&&g.forEach(f=>f(...y));}async function*m(){try{for await(let u of n)if(yield u,u.type==="content_block_start")i[u.index]=u.content_block;else if(u.type==="content_block_delta"){let y=i[u.index];y&&u.delta?.type==="text_delta"&&(y.text=(y.text||"")+u.delta.text,c("text",u.delta.text));}else if(u.type==="message_start")o=u.message?.model||"",l=u.message?.usage;else if(u.type==="message_delta")d=u.delta?.stop_reason||"",u.usage&&(l={...l,...u.usage});else if(u.type==="message_stop"){let y={role:"assistant",model:o,content:i.filter(Boolean),usage:l,stop_reason:d};c("message",y),r&&(r(y),r=null),e&&e(y);}if(r){let u={role:"assistant",model:o,content:i.filter(Boolean),usage:l,stop_reason:d||"end_turn"};c("message",u),r(u),r=null,e&&e(u);}}catch(u){throw c("error",u),s&&(s(u),s=null),u}}let h=m(),p=false,b={[Symbol.asyncIterator](){if(p)throw new Error("[inference-relay] RelayStream can only be iterated once");return p=true,h},on(u,y){return t.has(u)||t.set(u,[]),t.get(u).push(y),b},finalMessage(){let u,y=new Promise((g,f)=>{u=setTimeout(()=>f(new Error("[inference-relay] finalMessage() timed out \u2014 no message_stop received after 5 minutes")),3e5);});return Promise.race([a,y]).finally(()=>clearTimeout(u))}};return b}var me=E(()=>{});var w,V=E(()=>{me();w=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 j(await this.streamRaw(e,t))}};});function xe(){vt.clearCache();}var he,Pe,$,vt,ge=E(()=>{he=`-----BEGIN PUBLIC KEY-----
|
|
4
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzk88Bt9LZSmuSd8ulKqy
|
|
5
|
+
EGNiPB+r8u1ZinBvMM4qX8dp4kzJEC/47L1RYrrxCphD05HToREjljbj+upH6rZH
|
|
6
|
+
t6D/5funYPi2TO1IOSC6BRVRwMqqTmJGVJcLcG/WF3gTE+2UQ3q5EppWJCEKcz6x
|
|
7
|
+
kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
|
|
8
|
+
7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
|
|
9
|
+
Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
|
|
10
|
+
UQIDAQAB
|
|
11
|
+
-----END PUBLIC KEY-----`,Pe={version:"1.0.0",cliVersion:"2.1.87",eventTypes:{system:"system",streamEvent:"stream_event",assistant:"assistant",result:"result"},fieldMappings:{sessionId:"session_id",model:"model",cliVersion:"claude_code_version",content:"content",usage:"usage",inputTokens:"input_tokens",outputTokens:"output_tokens",stopReason:"stop_reason",isError:"is_error",totalCostUsd:"total_cost_usd",durationMs:"duration_ms",error:"error",event:"event"},syntheticModel:"<synthetic>"},$=class{verificationFailures=0;cachedManifest=null;currentSecurityState="SEC_NOMINAL";async verifyManifest(e){try{let{compactVerify:t,importSPKI:r}=await import('jose'),s=await r(he,"RS256"),{payload:a}=await t(e,s),i=JSON.parse(new TextDecoder().decode(a));return this.verificationFailures=0,this.cachedManifest=i,this.currentSecurityState="SEC_NOMINAL",{manifest:i,securityState:"SEC_NOMINAL"}}catch{if(this.verificationFailures++,this.verificationFailures>=3){this.currentSecurityState="SEC_DEGRADED";let t=2e3+Math.random()*3e3;return await new Promise(r=>setTimeout(r,t)),console.warn("[inference-relay] Logic synchronization mismatch. Routing via local recovery."),{manifest:Pe,securityState:"SEC_DEGRADED"}}return this.cachedManifest?(this.currentSecurityState="SEC_CACHE",{manifest:this.cachedManifest,securityState:"SEC_CACHE"}):(this.currentSecurityState="SEC_RECOVERY",{manifest:Pe,securityState:"SEC_RECOVERY"})}}getSecurityState(){return this.currentSecurityState}clearCache(){this.cachedManifest=null,this.verificationFailures=0,this.currentSecurityState="SEC_NOMINAL";}},vt=new $;});function be(n){return join(homedir(),".inference-relay","gateway",n)}function De(n){return join(be(n),"bundle.js")}function Oe(n){return join(be(n),"meta.json")}var It,v,W,J,Ne=E(()=>{ge();It=process.env.IR_GATEWAY_URL||"https://api.inference-relay.com";v=class extends Error{constructor(t,r,s){super(t);this.code=r;this.cause=s;this.name="GatewayLoaderError";}code;cause},W=new Map,J=class{static async load(e,t,r=It){let s=`${t}:${e.slice(-8)}`;if(W.has(s))return W.get(s);try{let m=await this.tryLoadFromDisk(t);if(m)return W.set(s,m),m}catch{}let{bytes:a,sha256:i,signature:l,libraryVersion:o}=await this.fetchFromAuthority(e,t,r);if(createHash("sha256").update(a).digest("hex")!==i)throw new v("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: HASH_MISMATCH)","GATEWAY_VERIFICATION_FAILED");await this.verifySignature(l,o,i);try{let m=be(t);mkdirSync(m,{recursive:!0}),writeFileSync(De(t),a),writeFileSync(Oe(t),JSON.stringify({sha256:i,signature:l,libraryVersion:o}));}catch{}let c=this.loadIntoVm(a.toString("utf-8"));return W.set(s,c),c}static async loadFromDisk(e){if(!existsSync(e))throw new v(`[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=De(e),r=Oe(e);if(!existsSync(t)||!existsSync(r))return null;let s=readFileSync(t),a=JSON.parse(readFileSync(r,"utf-8"));return createHash("sha256").update(s).digest("hex")!==a.sha256?null:(await this.verifySignature(a.signature,a.libraryVersion,a.sha256),this.loadIntoVm(s.toString("utf-8")))}static async fetchFromAuthority(e,t,r){let s;try{let o=await fetch(`${r}/v1/gateway/fetch`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({libraryVersion:t})});if(o.status===401||o.status===403)throw new v("[ir-system]: LICENSE_REJECTED (REASON: GATEWAY_FETCH_UNAUTHORIZED)","LICENSE_REJECTED");if(!o.ok)throw new v(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: HTTP_${o.status})`,"GATEWAY_FETCH_FAILED");s=await o.json();}catch(o){throw o instanceof v?o:new v("[ir-system]: GATEWAY_FETCH_FAILED (REASON: NETWORK_ERROR)","GATEWAY_FETCH_FAILED",o)}let a;try{a=await fetch(s.bundleUrl);}catch(o){throw new v("[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_DOWNLOAD_FAILED)","GATEWAY_FETCH_FAILED",o)}if(!a.ok)throw new v(`[ir-system]: GATEWAY_FETCH_FAILED (REASON: BUNDLE_HTTP_${a.status})`,"GATEWAY_FETCH_FAILED");let i=await a.arrayBuffer();return {bytes:Buffer.from(i),sha256:s.sha256,signature:s.signature,libraryVersion:s.libraryVersion,bundleVersion:s.bundleVersion}}static async verifySignature(e,t,r){try{let{compactVerify:s,importSPKI:a}=await import('jose'),i=await a(he,"RS256"),{payload:l}=await s(e,i),o=JSON.parse(new TextDecoder().decode(l));if(o.purpose!=="gateway-bundle")throw new v("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: PURPOSE_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(o.libraryVersion!==t)throw new v("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: LIBRARY_VERSION_MISMATCH)","GATEWAY_VERIFICATION_FAILED");if(o.sha256!==r)throw new v("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SHA256_MISMATCH)","GATEWAY_VERIFICATION_FAILED")}catch(s){throw s instanceof v?s:new v("[ir-system]: GATEWAY_VERIFICATION_FAILED (REASON: SIGNATURE_INVALID)","GATEWAY_VERIFICATION_FAILED",s)}}static loadIntoVm(e){try{let t=join(homedir(),".inference-relay","gateway","runtime.cjs"),r=dirname(t),s=createRequire(t),a={exports:{}};compileFunction(e,["exports","require","module","__filename","__dirname"],{filename:"<gateway-bundle>"})(a.exports,s,a,t,r);let l=a.exports;if(!l.ClaudeCLIProvider)throw new v("[ir-system]: GATEWAY_LOAD_FAILED (REASON: MISSING_CLAUDE_CLI_EXPORT)","GATEWAY_LOAD_FAILED");return l}catch(t){throw t instanceof v?t:new v("[ir-system]: GATEWAY_LOAD_FAILED (REASON: VM_EXECUTION_ERROR)","GATEWAY_LOAD_FAILED",t)}}static clearCache(){W.clear();}};});var Be={};Te(Be,{detectCLI:()=>N});async function N(){let n=null;try{n=execSync("which claude",{encoding:"utf-8",timeout:5e3}).trim();}catch{return {available:false,authenticated:false}}if(!n)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&&!wt.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 wt,X=E(()=>{wt=["2.1.87"];});var St,Q,He=E(()=>{V();Ne();St="1.4.0",Q=class extends w{type="claude-cli";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";licenseKey;loadedProvider=null;loadingPromise=null;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.licenseKey=e;}async ensureLoaded(){return this.loadedProvider?this.loadedProvider:this.loadingPromise?this.loadingPromise:(this.loadingPromise=(async()=>{try{let t=(await J.load(this.licenseKey,St)).ClaudeCLIProvider,r=new t;return this.loadedProvider=r,r}catch(e){throw this.loadingPromise=null,this.health.status="unhealthy",this.health.errorCount++,e instanceof v?this.health.lastError=e.message:e instanceof Error&&(this.health.lastError=e.message),e}})(),this.loadingPromise)}async probe(){let{detectCLI:e}=await Promise.resolve().then(()=>(X(),Be));return e()}async execute(e,t){return (await this.ensureLoaded()).execute(e,t)}async streamRaw(e,t){return (await this.ensureLoaded()).streamRaw(e,t)}estimateCost(e){if(this.loadedProvider)return this.loadedProvider.estimateCost(e);let r=JSON.stringify(e.messages).length/4+5e3,s=(r*3+1e3*15)/1e6;return {estimatedInputTokens:Math.round(r),estimatedCost:Math.round(s*1e4)/1e4,model:e.model,provider:"claude-cli"}}getHealth(){return this.loadedProvider?this.loadedProvider.getHealth():{...this.health}}reportRateLimit(e){this.loadedProvider?this.loadedProvider.reportRateLimit(e):(this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now());}};});function $e(n){return Z[n]||n}function _e(n){return Ve.find(e=>e.canonical===n)?.provider}var Ve,Z,Ee=E(()=>{Ve=[{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}}],Z=Object.fromEntries(Ve.filter(n=>n.canonical!==n.apiId).map(n=>[n.canonical,n.apiId]));Z["claude-sonnet-4"]="claude-sonnet-4-20250514";Z["claude-opus-4"]="claude-opus-4-20250514";Z["claude-haiku-4"]="claude-haiku-4-5-20251001";});function We(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 Tt,Pt,ve,ee,Ge=E(()=>{V();Ee();Tt="https://api.anthropic.com/v1/messages",Pt="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]};ee=class extends w{type="anthropic-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;dangerousDirectBrowserAccess;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||Tt,this.dangerousDirectBrowserAccess=e.dangerousDirectBrowserAccess??false;}async probe(){try{let e=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({model:"claude-haiku-4-5-20250414",max_tokens:1,messages:[{role:"user",content:"hi"}]})});return e.status===401?{available:!0,authenticated:!1}:e.ok||e.status===429?{available:!0,authenticated:!0,rateLimitTier:e.headers.get("anthropic-ratelimit-tier")??void 0}:e.status===529?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),a=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!a.ok)throw this.handleErrorResponse(a),new Error("unreachable");let i=await a.json(),l=Date.now()-r;this.recordSuccess();let[o,d]=We(i.model||e.model),c=((i.usage?.input_tokens||0)*o+(i.usage?.output_tokens||0)*d)/1e6,m={},h=["request-id","x-request-id","anthropic-ratelimit-requests-limit","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-reset","anthropic-ratelimit-tokens-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-reset","anthropic-ratelimit-tier"];for(let p of h){let b=a.headers.get(p);b&&(m[p]=b);}return {content:i.content||[],model:i.model||e.model,usage:{input_tokens:i.usage?.input_tokens||0,output_tokens:i.usage?.output_tokens||0},stop_reason:i.stop_reason||"end_turn",provider:"anthropic-api",costUsd:Math.round(c*1e6)/1e6,durationMs:l,fallbackChain:["anthropic-api:success"],headers:Object.keys(m).length>0?m:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("ANTHROPIC_API_ERROR: Response body is null \u2014 streaming unavailable");let a=s.body.getReader(),i=new TextDecoder;return (async function*(){let l="",o=false;try{for(;;){let{done:d,value:c}=await a.read();if(d)break;l+=i.decode(c,{stream:!0});let m=l.split(`
|
|
12
|
+
`);l=m.pop()||"";let h=null;for(let p of m)if(p.startsWith("event: "))h=p.slice(7).trim();else if(p.startsWith("data: ")){let b=p.slice(6);if(h&&b)try{let u=JSON.parse(b);u.type==="message_stop"&&(o=!0),yield u;}catch{console.warn("[inference-relay] Skipped malformed SSE data:",b.substring(0,100));}h=null;}else p.trim()===""&&(h=null);}o||(yield {type:"message_stop"});}finally{try{a.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[a,i]=We(e.model),l=(s*a+1e3*i)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(l*1e4)/1e4,model:e.model,provider:"anthropic-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){let e={"content-type":"application/json","x-api-key":this.apiKey,"anthropic-version":Pt};return this.dangerousDirectBrowserAccess&&(e["anthropic-dangerous-direct-browser-access"]="true"),e}buildRequestBody(e,t){let r={model:$e(e.model),max_tokens:e.max_tokens,messages:e.messages};return t&&(r.stream=true),e.system&&(r.system=e.system),e.temperature!==void 0&&(r.temperature=e.temperature),e.tools&&e.tools.length>0&&(r.tools=e.tools),e.metadata&&(r.metadata=e.metadata),r}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let a=new Error(`ANTHROPIC_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw a.retryAfterMs=s,a}throw t===529?(this.health.status="degraded",this.health.lastError="API overloaded",this.health.lastCheckAt=Date.now(),new Error("ANTHROPIC_OVERLOADED: API is temporarily overloaded (529)")):(this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`ANTHROPIC_API_ERROR: Request failed with status ${t}`))}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};});function Ke(n){if(Ce[n])return Ce[n];for(let[e,t]of Object.entries(Ce))if(n.startsWith(e))return t;return [2.5,10]}function Lt(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Mt(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n){let s=Lt(r.content);if(r.role==="assistant"&&Array.isArray(r.content)){let a=r.content.filter(i=>i.type==="tool_use");if(a.length>0){t.push({role:"assistant",content:s||"",tool_calls:a.map(i=>({id:i.id||`call_${Math.random().toString(36).slice(2)}`,type:"function",function:{name:i.name,arguments:typeof i.input=="string"?i.input:JSON.stringify(i.input)}}))});continue}}t.push({role:r.role,content:s});}return t}function qe(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 xt,Ye,Ce,te,je=E(()=>{V();xt="https://api.openai.com/v1/chat/completions",Ye=["gpt-","o1","o3","o4","chatgpt-","text-","davinci","babbage","ft:"],Ce={"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]};te=class extends w{type="openai-api";supportsStreaming=true;supportsMultimodal=true;platformRequirement="any";apiKey;baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.apiKey=e.apiKey,this.baseUrl=e.baseUrl?.replace(/\/$/,"")||xt;}async probe(){try{let e=this.baseUrl.replace(/\/chat\/completions$/,"/models"),t=await fetch(e,{method:"GET",headers:this.buildHeaders()});return t.status===401?{available:!0,authenticated:!1}:t.ok||t.status===429?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),a=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(s),signal:t?.signal});if(!a.ok)throw this.handleErrorResponse(a),new Error("unreachable");let i=await a.json(),l=Date.now()-r;this.recordSuccess();let o=i.choices?.[0],d=[];if(o?.message?.content&&d.push({type:"text",text:o.message.content}),o?.message?.tool_calls)for(let g of o.message.tool_calls)d.push({type:"tool_use",id:g.id,name:g.function?.name,input:g.function?.arguments?JSON.parse(g.function.arguments):{}});let c=i.usage?.prompt_tokens||0,m=i.usage?.completion_tokens||0,[h,p]=Ke(i.model||e.model),b=(c*h+m*p)/1e6,u={},y=["x-request-id","x-ratelimit-limit-requests","x-ratelimit-remaining-requests","x-ratelimit-limit-tokens","x-ratelimit-remaining-tokens","x-ratelimit-reset-requests","x-ratelimit-reset-tokens"];for(let g of y){let f=a.headers.get(g);f&&(u[g]=f);}return {content:d,model:i.model||e.model,usage:{input_tokens:c,output_tokens:m},stop_reason:qe(o?.finish_reason),provider:"openai-api",costUsd:Math.round(b*1e6)/1e6,durationMs:l,fallbackChain:["openai-api:success"],headers:Object.keys(u).length>0?u:void 0}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(this.baseUrl,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OPENAI_API_ERROR: Response body is null \u2014 streaming unavailable");let a=s.body.getReader(),i=new TextDecoder,l=e.model;return (async function*(){let o="",d=false,c=false,m,h;yield {type:"message_start",message:{model:l,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:p,value:b}=await a.read();if(p)break;o+=i.decode(b,{stream:!0});let u=o.split(`
|
|
13
|
+
`);o=u.pop()||"";for(let y of u){if(!y.startsWith("data: "))continue;let g=y.slice(6).trim();if(g==="[DONE]"){yield {type:"message_delta",delta:{stop_reason:h||"end_turn"},usage:m||{}},yield {type:"message_stop"},c=!0;return}try{let f=JSON.parse(g);f.usage&&(m={input_tokens:f.usage.prompt_tokens||0,output_tokens:f.usage.completion_tokens||0});let A=f.choices?.[0];if(!A)continue;let _=A.delta;_?.content&&!d&&(d=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),_?.content&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:_.content}}),A.finish_reason&&(d&&(yield {type:"content_block_stop",index:0}),h=qe(A.finish_reason));}catch{}}}c||(yield {type:"message_delta",delta:{stop_reason:h||"end_turn"},usage:m||{}},yield {type:"message_stop"});}finally{try{a.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0,s=t+r,[a,i]=Ke(e.model),l=(s*a+1e3*i)/1e6;return {estimatedInputTokens:s,estimatedCost:Math.round(l*1e4)/1e4,model:e.model,provider:"openai-api"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildHeaders(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}}buildRequestBody(e,t){let r=e.model.toLowerCase();if(!Ye.some(l=>r.startsWith(l)))throw new Error(`OPENAI_MODEL_TRANSLATION_REQUIRED: The OpenAI provider received the model name '${e.model}', which does not match any known OpenAI model prefix (${Ye.join(", ")}). The relay does NOT auto-translate model names across providers in v1.3.x. Either (a) pass an OpenAI model name like 'gpt-4o-mini' when routing to this provider, or (b) route non-OpenAI models through a provider that understands them (e.g. 'anthropic-api' for Claude models).`);let a=Mt(e.messages,e.system),i={model:e.model,max_tokens:e.max_tokens,messages:a};return t&&(i.stream=true,i.stream_options={include_usage:true}),e.temperature!==void 0&&(i.temperature=e.temperature),e.tools&&e.tools.length>0&&(i.tools=e.tools),i}handleErrorResponse(e){let t=e.status;if(t===401)throw this.health.status="unhealthy",this.health.lastError="Authentication failed",this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error("OPENAI_AUTH_ERROR: Invalid API key (401)");if(t===429){let r=e.headers.get("retry-after"),s=r?parseInt(r,10)*1e3:6e4;this.health.status="degraded",this.health.lastError=`Rate limited \u2014 retry after ${s}ms`,this.health.lastCheckAt=Date.now();let a=new Error(`OPENAI_RATE_LIMIT: Too many requests (429). Retry after ${s}ms`);throw a.retryAfterMs=s,a}throw this.health.errorCount++,this.health.lastCheckAt=Date.now(),new Error(`OPENAI_API_ERROR: Request failed with status ${t}`)}recordSuccess(){this.health.status="healthy",this.health.lastCheckAt=Date.now(),this.health.errorCount=0,this.health.lastError=void 0;}};});function Ot(n){return typeof n=="string"?n:n.filter(e=>e.type==="text"&&e.text).map(e=>e.text).join("")}function Ut(n,e){let t=[];e&&t.push({role:"system",content:e});for(let r of n)t.push({role:r.role,content:Ot(r.content)});return t}var Dt,ne,Je=E(()=>{V();Dt="http://localhost:11434";ne=class extends w{type="ollama";supportsStreaming=true;supportsMultimodal=false;platformRequirement="desktop";baseUrl;health={status:"healthy",lastCheckAt:Date.now(),errorCount:0};constructor(e){super(),this.baseUrl=e?.baseUrl?.replace(/\/$/,"")||Dt;}async probe(){try{return (await fetch(`${this.baseUrl}/api/tags`,{method:"GET"})).ok?{available:!0,authenticated:!0}:{available:!1,authenticated:!1}}catch{return {available:false,authenticated:false}}}async execute(e,t){let r=Date.now(),s=this.buildRequestBody(e,false),a=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),signal:t?.signal});if(!a.ok)throw this.handleErrorResponse(a),new Error("unreachable");let i=await a.json(),l=Date.now()-r;this.recordSuccess();let o=[];i.message?.content&&o.push({type:"text",text:i.message.content});let d=i.prompt_eval_count||0,c=i.eval_count||0;return {content:o,model:i.model||e.model,usage:{input_tokens:d,output_tokens:c},stop_reason:(i.done,"end_turn"),provider:"ollama",costUsd:0,durationMs:l,fallbackChain:["ollama:success"]}}async streamRaw(e,t){let r=this.buildRequestBody(e,true),s=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),signal:t?.signal});if(s.ok||this.handleErrorResponse(s),!s.body)throw new Error("OLLAMA_ERROR: Response body is null \u2014 streaming unavailable");let a=s.body.getReader(),i=new TextDecoder,l=e.model;return (async function*(){let o="",d=false,c=false;yield {type:"message_start",message:{model:l,usage:{input_tokens:0,output_tokens:0}}};try{for(;;){let{done:m,value:h}=await a.read();if(m)break;o+=i.decode(h,{stream:!0});let p=o.split(`
|
|
14
|
+
`);o=p.pop()||"";for(let b of p){let u=b.trim();if(u)try{let y=JSON.parse(u);if(y.message?.content&&(d||(d=!0,yield {type:"content_block_start",index:0,content_block:{type:"text",text:""}}),yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:y.message.content}}),y.done){d&&(yield {type:"content_block_stop",index:0}),yield {type:"message_delta",delta:{stop_reason:"end_turn"},usage:{input_tokens:y.prompt_eval_count||0,output_tokens:y.eval_count||0}},yield {type:"message_stop"},c=!0;return}}catch{}}}c||(yield {type:"message_stop"});}finally{try{a.releaseLock();}catch{}}})()}estimateCost(e){let t=Math.round(JSON.stringify(e.messages).length/4),r=e.system?Math.round(e.system.length/4):0;return {estimatedInputTokens:t+r,estimatedCost:0,model:e.model,provider:"ollama"}}getHealth(){return {...this.health}}reportRateLimit(e){this.health.status="degraded",this.health.lastError=`Rate limited: ${e.utilization*100}% utilization`,this.health.lastCheckAt=Date.now();}buildRequestBody(e,t){if(e.tools&&e.tools.length>0)throw new Error(`OLLAMA_TOOLS_NOT_SUPPORTED: The Ollama provider received ${e.tools.length} tool definition(s) in params.tools, but this provider does not implement function calling in v1.3.x. For tool-use workflows route to 'anthropic-api' or 'openai-api' instead. Tracking issue: 1.4.0 ships an Ollama tool-use shim for models that support native function calling (llama3.1, mistral-nemo, etc.).`);let r=Ut(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 re,ze=E(()=>{re=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 Qe(n){return n.messages.some(e=>typeof e.content=="string"?false:Array.isArray(e.content)&&e.content.some(t=>t.type==="image"||t.type==="image_url"))}function Re(n){if(!(n instanceof Error))return "unknown";let e=n.message.toLowerCase(),t=n.name.toLowerCase();return e.startsWith("openai_model_translation_required:")||e.startsWith("ollama_tools_not_supported:")?"provider_incompatible":e.includes("rate limit")||e.includes("429")||t.includes("ratelimit")?"rate_limited":e.includes("auth")||e.includes("401")||e.includes("403")||e.includes("unauthorized")||e.includes("forbidden")?"auth_failed":e.includes("timeout")||e.includes("timed out")||e.includes("aborted")||t==="aborterror"||t==="timeouterror"?"timeout":"unknown"}function Ze(n){return [...n].sort((e,t)=>e.priority-t.priority)}function et(n){return {provider:n,inputTokens:0,outputTokens:0,costUsd:0,userCostUsd:0}}function Ft(n,e,t){typeof t.input_tokens=="number"&&(n.inputTokens=t.input_tokens),typeof t.output_tokens=="number"&&(e==="anthropic-api"||e==="claude-cli"?n.outputTokens+=t.output_tokens:n.outputTokens=t.output_tokens);}function tt(n){return {input_tokens:n[n.length-1]?.inputTokens??0,output_tokens:n.reduce((e,t)=>e+t.outputTokens,0)}}function Bt(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 Ht(n,e,t,r,s){if(s&&n.type==="content_block_delta"&&n.index===s.fromIndex)return {action:"yield",event:{...n,index:s.toIndex}};if(s&&n.type==="content_block_stop"&&n.index===s.fromIndex)return {action:"suppress",coalesceMode:null,coalesceModeCleared:true};if(r&&n.type==="content_block_start"&&n.content_block?.type==="text"){let i=t.content[t.content.length-1];if(i?.type==="text"&&i.open===true)return {action:"suppress",coalesceMode:{fromIndex:n.index+e,toIndex:t.content.length-1},clearedJustFailedOver:true}}let a=r&&n.type==="content_block_start";return typeof n.index=="number"&&e>0?{action:"yield",event:{...n,index:n.index+e},clearedJustFailedOver:a}:{action:"yield",event:n,clearedJustFailedOver:a}}function Vt(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 $t(n,e){return n?`${n}
|
|
15
|
+
|
|
16
|
+
${e}`:e}function nt(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 Wt(n){return Math.max(0,n.content.length-1)}async function*Gt(n){for await(let e of n)await new Promise(t=>setTimeout(t,50+Math.random()*50)),yield e;}var Xe,F,se,Ae=E(()=>{me();ze();Ee();Xe=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;}};se=class n{healthMap=new Map;engineEvents=new re;static UNHEALTHY_TTL_MS=300*1e3;getHealthStatus(e){let t=this.healthMap.get(e);return t?t.status==="unhealthy"&&Date.now()-t.updatedAt>=n.UNHEALTHY_TTL_MS?(this.healthMap.delete(e),"healthy"):t.status:"healthy"}markUnhealthy(e,t){this.healthMap.set(e,{status:"unhealthy",lastError:t,updatedAt:Date.now()});}markDegraded(e,t){this.healthMap.set(e,{status:"degraded",lastError:t,updatedAt:Date.now()});}markHealthy(e){this.healthMap.set(e,{status:"healthy",updatedAt:Date.now()});}resetHealth(){this.healthMap.clear();}async execute(e,t,r){let s=Ze(t),a=[],i=Qe(e),l=randomUUID(),o=Date.now();for(let d of s){let c=d.type;if(this.getHealthStatus(c)==="unhealthy"){a.push(`${c}:skipped:unhealthy`);continue}if(i&&!d.supportsMultimodal){a.push(`${c}:skipped:no_multimodal`);continue}let h=_e(e.model);if(h&&h!==c&&Xe.has(c)){a.push(`${c}:skipped:wrong_provider`);continue}try{let p=await d.execute(e,{signal:r?.signal});return this.markHealthy(c),a.push(`${c}:success`),this.emitEngineEvent({kind:"stream_complete",callId:l,id:randomUUID(),ts:Date.now(),stitched:!1,segments:[{provider:c,inputTokens:p.usage.input_tokens,outputTokens:p.usage.output_tokens,costUsd:p.costUsd,userCostUsd:p.userCostUsd??0}],provider:c,model:p.model,inputTokens:p.usage.input_tokens,outputTokens:p.usage.output_tokens,costUsd:p.costUsd,userCostUsd:p.userCostUsd,durationMs:p.durationMs??Date.now()-o,stopReason:p.stop_reason,fallbackChain:a,rateLimitHit:!1,securityState:r?.licenseState}),{...p,fallbackChain:a}}catch(p){if(p?.name==="AbortError"||r?.signal?.aborted)throw p;switch(Re(p)){case "rate_limited":d.reportRateLimit({provider:c,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(c,"rate_limited"),a.push(`${c}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(c,"auth_failed"),a.push(`${c}:failed:auth_failed`);break;case "timeout":a.push(`${c}:failed:timeout`);break;case "provider_incompatible":a.push(`${c}:incompatible`);break;default:a.push(`${c}:failed:${p.message?.slice(0,40)||"unknown"}`);break}}}throw new F(a)}async stream(e,t,r){let s=randomUUID(),a=Ze(t),i=Qe(e),l=Date.now(),o=[],d=null,c=null;for(let g of a){let f=g.type;if(this.getHealthStatus(f)==="unhealthy"){o.push(`${f}:skipped:unhealthy`);continue}if(i&&!g.supportsMultimodal){o.push(`${f}:skipped:no_multimodal`);continue}if(!g.supportsStreaming){o.push(`${f}:skipped:no_streaming`);continue}let A=_e(e.model);if(A&&A!==f&&Xe.has(f)){o.push(`${f}:skipped:wrong_provider`);continue}try{c=await g.streamRaw(e,{signal:r?.signal}),d=g,o.push(`${f}:success`);break}catch(_){if(_?.name==="AbortError"||r?.signal?.aborted)throw _;switch(Re(_)){case "rate_limited":g.reportRateLimit({provider:f,utilization:1,resetsAt:Date.now()+6e4}),this.markDegraded(f,"rate_limited"),o.push(`${f}:failed:rate_limited`);break;case "auth_failed":this.markUnhealthy(f,"auth_failed"),o.push(`${f}:failed:auth_failed`);break;case "timeout":o.push(`${f}:failed:timeout`);break;case "provider_incompatible":o.push(`${f}:incompatible`);break;default:o.push(`${f}:failed:${_.message?.slice(0,40)||"unknown"}`);break}}}if(!d||!c)throw new F(o);let h=this,p=r?.maxMidStreamFailovers??2,b=new Set([d]);async function*u(){let g=d,f=c[Symbol.asyncIterator](),A={role:"assistant",content:[]},_={segments:[]},L=et(g.type);_.segments.push(L);let Ie=0,Y=null,K=false,de=p,B="",H="";for(h.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:g.type});;)try{for(;;){let k=await f.next();if(k.done)break;let D=k.value,P=Ht(D,Ie,A,K,Y);if(P.action==="suppress"){"coalesceMode"in P&&(Y=P.coalesceMode),P.clearedJustFailedOver&&(K=!1);continue}P.coalesceModeCleared&&(Y=null),P.clearedJustFailedOver&&(K=!1);let R=P.event;if(Bt(A,R),R.type==="message_start"){if(_.segments.length>1)continue;B=R.message?.model||B,R.message?.usage?.input_tokens!=null&&(L.inputTokens=R.message.usage.input_tokens);}if(R.type==="message_delta"&&(R.delta?.stop_reason&&(H=R.delta.stop_reason),R.usage)){Ft(L,g.type,R.usage),yield {...R,usage:void 0};continue}if(R.type==="message_stop")break;yield R;}if(A.content.length===0&&L.outputTokens===0)throw new Error("stream ended without producing any content");h.markHealthy(g.type),h.emitEngineEvent({kind:"segment_complete",callId:s,id:randomUUID(),ts:Date.now(),provider:g.type,usage:{...L}});let I=tt(_.segments);yield {type:"message_delta",delta:{stop_reason:H||"end_turn"},usage:I},yield {type:"message_stop"},h.emitEngineEvent({kind:"stream_complete",callId:s,id:randomUUID(),ts:Date.now(),stitched:_.segments.length>1,segments:_.segments.map(k=>({...k})),provider:_.segments.map(k=>k.provider).join("+"),model:B,inputTokens:I.input_tokens,outputTokens:I.output_tokens,costUsd:_.segments.reduce((k,D)=>k+D.costUsd,0),userCostUsd:_.segments.reduce((k,D)=>k+D.userCostUsd,0),durationMs:Date.now()-l,stopReason:H||"end_turn",fallbackChain:o,rateLimitHit:!1,securityState:r?.licenseState});return}catch(I){if(I?.name==="AbortError"||r?.signal?.aborted)throw I;let k=Re(I);try{await f.return?.();}catch{}if(h.markUnhealthy(g.type,String(I)),h.emitEngineEvent({kind:"mid_stream_failover_attempt",callId:s,id:randomUUID(),ts:Date.now(),from:g.type,bytesBuffered:nt(A),errorClass:k,retriesLeft:de}),o.push(`${g.type}:partial(${nt(A)}b)`),de<=0)throw h.emitTerminalExhaustion(s,_,B,H,o,l,r?.licenseState),I;let D=Vt(A.content),P=[...e.messages,{role:"assistant",content:D}],R=null,q=null,we=g;for(;;){let x=h.nextHealthyProvider(a,we,i,b);if(!x)break;we=x,b.add(x);let _t={...e,messages:P,...x.type!=="anthropic-api"&&x.type!=="claude-cli"?{system:$t(e.system,"[SYSTEM]: CONTINUE_LAST_RESPONSE_WITHOUT_REPEATING")}:{}};try{q=await x.streamRaw(_t,{signal:r?.signal}),R=x;break}catch(Se){h.markUnhealthy(x.type,String(Se)),o.push(`${x.type}:failed_connect:${String(Se).slice(0,40)}`);}}if(!R||!q)throw h.emitTerminalExhaustion(s,_,B,H,o,l,r?.licenseState),I;o.push(`${R.type}:stitched`),h.emitEngineEvent({kind:"mid_stream_failover_success",callId:s,id:randomUUID(),ts:Date.now(),from:g.type,to:R.type}),Ie=Wt(A)+1,de--,g=R,f=q[Symbol.asyncIterator](),K=true,Y=null,L=et(g.type),_.segments.push(L),h.emitEngineEvent({kind:"segment_start",callId:s,id:randomUUID(),ts:Date.now(),provider:g.type});}}let y=u();return r?.licenseState==="SEC_DEGRADED"&&(y=Gt(y)),j(y)}nextHealthyProvider(e,t,r,s){let a=e.indexOf(t);if(a===-1)return null;for(let i=a+1;i<e.length;i++){let l=e[i];if(!s.has(l)&&!(r&&!l.supportsMultimodal)&&l.supportsStreaming)return l}return null}emitEngineEvent(e){this.engineEvents.emitTyped(e);}emitTerminalExhaustion(e,t,r,s,a,i,l){let o=tt(t.segments);this.emitEngineEvent({kind:"stream_complete",callId:e,id:randomUUID(),ts:Date.now(),stitched:t.segments.length>1,segments:t.segments.map(d=>({...d})),provider:t.segments.map(d=>d.provider).join("+"),model:r,inputTokens:o.input_tokens,outputTokens:o.output_tokens,costUsd:t.segments.reduce((d,c)=>d+c.costUsd,0),userCostUsd:t.segments.reduce((d,c)=>d+c.userCostUsd,0),durationMs:Date.now()-i,stopReason:s||"error",fallbackChain:a,rateLimitHit:false,securityState:l});}};});function rt(n,e){if(e==="prefer-user"){let s=n.filter(i=>i.type==="claude-cli"),a=n.filter(i=>i.type!=="claude-cli");return [...s,...a]}if(e==="prefer-app"){let s=n.filter(i=>i.type==="claude-cli");return [...n.filter(i=>i.type!=="claude-cli"),...s]}let t=n.filter(s=>s.type===e),r=n.filter(s=>s.type!==e);return [...t,...r]}function st(n){return (e,t)=>n.maxCostPerCall!==void 0&&t.estimatedCost>n.maxCostPerCall?"prefer-user":n.preferLocal?"ollama":"prefer-user"}var it=E(()=>{});function at(n){if(ke[n])return ke[n];for(let[e,t]of Object.entries(ke))if(n.startsWith(e))return t;return [3,15]}var ke,ot=E(()=>{ke={"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 lt(n){let e=0;for(let l of n.messages)if(typeof l.content=="string")e+=l.content.length;else if(Array.isArray(l.content))for(let o of l.content)o.type==="text"&&o.text&&(e+=o.text.length);n.system&&(e+=n.system.length);let t=Math.ceil(e/4),r=Math.min(n.max_tokens||1024,4096),[s,a]=at(n.model),i=(t*s+r*a)/1e6;return {estimatedInputTokens:t,estimatedCost:Math.round(i*1e4)/1e4,model:n.model,provider:""}}var ct=E(()=>{ot();});var ie,ut=E(()=>{ie=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(()=>{});}};});async function ae(n,e){if(!n)return {valid:false,error:"License key required. Get one at inference-relay.com"};let t=O.get(n);if(t&&Date.now()-t.cachedAt<t.ttl)return t.result;let r=new AbortController,a=!O.has(n)?3e3:1e3,i=setTimeout(()=>r.abort(),a),l;try{let d=(e||Yt)+Kt;l=await(await fetch(d,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:n}),signal:r.signal})).json();}catch{return clearTimeout(i),t&&Date.now()-t.cachedAt<jt?t.result:{valid:false,error:"License validation failed (network error). Visit inference-relay.com"}}clearTimeout(i);let o;if(l.jws)try{let{compactVerify:d,importSPKI:c}=await import('jose'),m=await c(Jt,"RS256"),{payload:h}=await d(l.jws,m);o=JSON.parse(new TextDecoder().decode(h));}catch{return O.delete(n),{valid:false,error:"License validation signature invalid. Possible MITM \u2014 refusing to start."}}else if(o=l,o.valid)return O.delete(n),{valid:false,error:"License validation response not signed. Possible MITM."};return O.set(n,{result:o,cachedAt:Date.now(),ttl:o.valid?qt:6e4}),o}var Yt,Kt,qt,jt,Jt,O,oe,dt=E(()=>{pe();He();Ge();je();Je();Ae();X();it();ct();ge();ut();Yt="https://api.inference-relay.com",Kt="/v1/validate",qt=1440*60*1e3,jt=10080*60*1e3,Jt=`-----BEGIN PUBLIC KEY-----
|
|
17
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzk88Bt9LZSmuSd8ulKqy
|
|
18
|
+
EGNiPB+r8u1ZinBvMM4qX8dp4kzJEC/47L1RYrrxCphD05HToREjljbj+upH6rZH
|
|
19
|
+
t6D/5funYPi2TO1IOSC6BRVRwMqqTmJGVJcLcG/WF3gTE+2UQ3q5EppWJCEKcz6x
|
|
20
|
+
kfynZEzOcLikoQALIxEjxRfi6g83wNJS+WBwAJQ68s7N9FHE3rkLzEqv3FJRP+ZR
|
|
21
|
+
7lqwqIyuCLr9j9yc4XqF6VY9yooD2hyw/n1EVFejzjDgntWTqIkaCIXwh8lDzRrK
|
|
22
|
+
Rxn07gcI6ea2Eym9sXh4xZLFudXfAT2DFsH/XboDUuMKAV1YHc1NsIGApesWe2M+
|
|
23
|
+
UQIDAQAB
|
|
24
|
+
-----END PUBLIC KEY-----`,O=new Map;oe=class n{providers=[];config;fallbackEngine;telemetryReporter;routingFn=null;license=null;licensePromise=null;licenseValidatedAt=0;callsSinceValidation=0;manifestDecryptor=new $;capProbeTimer=null;capProbeTicksRemaining=0;messages;constructor(e){if(this.config=e,this.fallbackEngine=new se,this.telemetryReporter=new ie({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=st(e.routing)),e.providers)for(let s of e.providers){let a=typeof s=="string"?{type:s}:s,i=this.createProvider(a);i&&(a.priority!==void 0&&(i.priority=a.priority),this.providers.push(i));}let t=100,r=3600*1e3;this.messages={create:async(s,a)=>{let i=this.license&&(this.callsSinceValidation>=t||Date.now()-this.licenseValidatedAt>=r);if(i&&(this.license=null),!this.license){this.licensePromise||(this.licensePromise=ae(this.config.licenseKey,this.config.endpoint));try{this.license=await this.licensePromise;}finally{this.licensePromise=null;}if(this.licenseValidatedAt=Date.now(),this.callsSinceValidation=0,this.license.valid){if(this.license.capExceeded)throw this.startCapProbe(),new U({tier:this.license.tier||"solo",baseCap:this.license.baseCap??this.license.usageCap??null,topUps:this.license.topUpGrants??0,effectiveCap:this.license.usageCap??null,usedThisCycle:this.license.usageThisMonth??0});i||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,a):this.executeMessage(s,a)}};}startCapProbe(){if(this.capProbeTimer!==null)return;let e=15e3,t=20,r=4;this.capProbeTicksRemaining=t;let s=async()=>{this.capProbeTicksRemaining-=1;let a=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 (${a}m remaining)`),this.config.licenseKey&&O.delete(this.config.licenseKey);try{let i=await this.probeValidate();if(i.valid&&i.capExceeded===!1){console.log("[inference-relay] cap cleared \u2014 probe exiting, inference resuming"),this.license=i,this.licenseValidatedAt=Date.now(),this.callsSinceValidation=0,this.stopCapProbe();return}}catch{}this.capProbeTicksRemaining<=0&&(console.log("[inference-relay] cap probe exhausted (5 min) \u2014 stopping"),this.stopCapProbe());};this.capProbeTimer=setInterval(s,e),typeof this.capProbeTimer.unref=="function"&&this.capProbeTimer.unref();}async probeValidate(){return ae(this.config.licenseKey,this.config.endpoint)}stopCapProbe(){this.capProbeTimer!==null&&(clearInterval(this.capProbeTimer),this.capProbeTimer=null),this.capProbeTicksRemaining=0;}static async autoDetect(e){let t=[],r=await N();return r.available&&r.authenticated&&t.push({type:"claude-cli",priority:1}),process.env.ANTHROPIC_API_KEY&&t.push({type:"anthropic-api",priority:2,apiKey:process.env.ANTHROPIC_API_KEY}),new n({licenseKey:e?.licenseKey||process.env.IR_LICENSE_KEY||"",providers:t,fallback:e?.fallback??true,...e})}dispose(){this.providers=[],this.config.licenseKey&&O.delete(this.config.licenseKey),this.license=null,this.licensePromise=null,this.callsSinceValidation=0,this.stopCapProbe(),this.telemetryReporter.unsubscribe(),this.manifestDecryptor.clearCache(),xe();}resolveProviders(e){if(!this.routingFn)return this.providers;let t=lt(e),r=this.routingFn(e,t);return rt(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 Q(this.config.licenseKey);case "anthropic-api":return e.apiKey?new ee({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "openai-api":return e.apiKey?new te({apiKey:e.apiKey,baseUrl:e.baseUrl}):null;case "ollama":return new ne({baseUrl:e.baseUrl});default:return null}}};});var pt=E(()=>{X();});var gt={};Te(gt,{runVerify:()=>Zt});function T(n,e){let t=n.padEnd(13);console.log(`${C("[ir]")} ${t}${e}`);}function Qt(n){if(n instanceof U)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 ${ht/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 mt(n){if(n.usageCap!==null&&n.usageCap!==void 0){let e=n.usageThisMonth??0,t=n.usageCap;if(t===0)console.log(C(` Usage: ${e.toLocaleString()} (unmetered)`));else {let r=Math.round(e/t*1e3)/10;console.log(C(` Usage: ${e.toLocaleString()} / ${t.toLocaleString()} (${r}%)`));}}}async function Zt(n=process.argv.slice(2),e=process.env){let t=n.includes("--credentials-only"),r=e.IR_LICENSE_KEY;if(!r)return console.error(G("[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(G("[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 s;try{s=await ae(r);}catch(b){return T("IDENTITY:",G("FAILED")),console.error(` ${b.message||"unknown error"}`),1}if(!s.valid)return T("IDENTITY:",G("REJECTED")),s.error&&console.error(` ${s.error}`),1;T("IDENTITY:",le("VALIDATED"));let a=(s.tier??"unknown").toUpperCase();T("TIER:",le(a));let i;try{i=await N();}catch{i=null;}if(!i||!i.available)return T("RELAY:",ce("INACTIVE")),console.log(C(" Claude CLI not detected. The relay will fall back")),console.log(C(" to direct API providers using your API keys.")),console.log(C(" For zero-cost routing, install Claude Code:")),console.log(C(" npm install -g @anthropic-ai/claude-code")),1;if(!i.authenticated)return T("RELAY:",ce("CLI_UNAUTHED")),console.log(C(" Claude CLI is installed but not authenticated.")),console.log(C(" Run `claude` once to sign in, then re-run verify.")),1;if(i.versionWarning&&console.log(ce(` Warning: ${i.versionWarning}`)),t)return T("RELAY:",le("READY")),console.log(C(" Credentials present. Round-trip skipped (--credentials-only).")),i.cliVersion&&console.log(C(` Claude CLI: v${i.cliVersion}`)),i.subscriptionType&&i.subscriptionType!=="unknown"&&console.log(C(` Tier: ${i.subscriptionType}`)),mt(s),0;let l=new oe({licenseKey:r,providers:[{type:"claude-cli",priority:1}],fallback:false,telemetry:false}),o=new AbortController,d=setTimeout(()=>o.abort(),ht),c=Date.now(),m;try{m=await l.messages.create(Xt,{signal:o.signal});}catch(b){clearTimeout(d),l.dispose();let{label:u,hint:y}=Qt(b);return T("RELAY:",G(`DEGRADED \u2014 ${u}`)),console.log(C(` ${y}`)),i.cliVersion&&console.log(C(` Claude CLI: v${i.cliVersion}`)),1}clearTimeout(d),l.dispose();let h=Date.now()-c;return m.fallbackChain?.[0]?.startsWith("claude-cli:success")?(T("RELAY:",le("ACTIVE")),console.log(C(` Round-trip: ${h}ms via ${m.provider}`)),console.log(C(` Model echo: ${m.model}`)),console.log(C(` Tokens: ${m.usage.input_tokens} in / ${m.usage.output_tokens} out`)),i.cliVersion&&console.log(C(` Claude CLI: v${i.cliVersion}`)),i.subscriptionType&&i.subscriptionType!=="unknown"&&console.log(C(` Tier: ${i.subscriptionType}`)),mt(s),0):(T("RELAY:",ce("UNEXPECTED")),console.log(C(` Native Gateway did not handle the call. Chain: ${m.fallbackChain?.join(" \u2192 ")}`)),1)}var zt,ue,le,G,ce,C,ht,Xt,yt=E(()=>{dt();Ae();pe();pt();zt=process.stdout.isTTY===true,ue=(n,e)=>zt?`\x1B[${n}m${e}\x1B[0m`:e,le=n=>ue("32",n),G=n=>ue("31",n),ce=n=>ue("33",n),C=n=>ue("2",n);ht=15e3,Xt={model:"claude-haiku-4-5",max_tokens:1,messages:[{role:"user",content:"Reply with exactly the single character k and nothing else."}]};});var ft={verify:async()=>{let{runVerify:n}=await Promise.resolve().then(()=>(yt(),gt));return n()}};function bt(){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 M=process.argv[2];(!M||M==="--help"||M==="-h")&&(bt(),process.exit(M?0:2));M in ft||(console.error(`Unknown command: ${M}`),console.error(""),bt(),process.exit(1));ft[M]().then(n=>process.exit(n)).catch(n=>{console.error(`[ir] failed to run command "${M}":`),console.error(n),process.exit(99);});
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
interface InferenceRelayConfig {
|
|
2
|
+
licenseKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
providers?: ProviderConfig[];
|
|
5
|
+
fallback?: boolean;
|
|
6
|
+
routing?: RoutingConfig;
|
|
7
|
+
concurrency?: ConcurrencyConfig;
|
|
8
|
+
warmPool?: number;
|
|
9
|
+
secureEnclave?: SecureEnclaveConfig;
|
|
10
|
+
telemetry?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Maximum number of mid-stream failovers per call. After exhaustion, the
|
|
13
|
+
* original error is rethrown to the consumer. Default: 2.
|
|
14
|
+
*/
|
|
15
|
+
maxMidStreamFailovers?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Security state of the licence validation chain. Mirrors the state machine
|
|
19
|
+
* documented in patent §5.3.4. SEC_DEGRADED enables Asynchronous Timing
|
|
20
|
+
* Decorrelation (jitter) on outbound stream events.
|
|
21
|
+
*/
|
|
22
|
+
type SecurityState = 'SEC_NOMINAL' | 'SEC_CACHE' | 'SEC_RECOVERY' | 'SEC_DEGRADED';
|
|
23
|
+
interface ProviderConfig {
|
|
24
|
+
type: 'claude-cli' | 'anthropic-api' | 'openai-api' | 'ollama' | 'custom';
|
|
25
|
+
priority?: number;
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
options?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
interface RelayResult {
|
|
31
|
+
content: ContentBlock[];
|
|
32
|
+
model: string;
|
|
33
|
+
usage: {
|
|
34
|
+
input_tokens: number;
|
|
35
|
+
output_tokens: number;
|
|
36
|
+
};
|
|
37
|
+
stop_reason: string;
|
|
38
|
+
provider: string;
|
|
39
|
+
costUsd: number;
|
|
40
|
+
userCostUsd?: number;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
fallbackChain: string[];
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
}
|
|
45
|
+
interface CreateParams {
|
|
46
|
+
model: string;
|
|
47
|
+
max_tokens: number;
|
|
48
|
+
messages: Message[];
|
|
49
|
+
system?: string;
|
|
50
|
+
temperature?: number;
|
|
51
|
+
tools?: unknown[];
|
|
52
|
+
stream?: boolean;
|
|
53
|
+
metadata?: Record<string, string>;
|
|
54
|
+
}
|
|
55
|
+
interface SegmentUsage {
|
|
56
|
+
provider: string;
|
|
57
|
+
inputTokens: number;
|
|
58
|
+
outputTokens: number;
|
|
59
|
+
costUsd: number;
|
|
60
|
+
userCostUsd: number;
|
|
61
|
+
}
|
|
62
|
+
interface AuditEvent {
|
|
63
|
+
timestamp: number;
|
|
64
|
+
provider: string;
|
|
65
|
+
model: string;
|
|
66
|
+
inputTokens: number;
|
|
67
|
+
outputTokens: number;
|
|
68
|
+
costUsd: number;
|
|
69
|
+
userCostUsd?: number;
|
|
70
|
+
durationMs: number;
|
|
71
|
+
stopReason: string;
|
|
72
|
+
fallbackChain: string[];
|
|
73
|
+
rateLimitHit: boolean;
|
|
74
|
+
securityState?: SecurityState;
|
|
75
|
+
metadata?: Record<string, string>;
|
|
76
|
+
promptContent: false;
|
|
77
|
+
completionContent: false;
|
|
78
|
+
/** True when the response was stitched across multiple providers. */
|
|
79
|
+
stitched?: boolean;
|
|
80
|
+
/** Per-segment usage when stitched; absent for single-segment calls. */
|
|
81
|
+
segments?: SegmentUsage[];
|
|
82
|
+
/** EngineEvent IDs correlated to this call (cryptographic lineage). */
|
|
83
|
+
lineage?: string[];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Engine-internal event union. Emitted by FallbackEngine on a synchronous
|
|
87
|
+
* Node EventEmitter so the TelemetryReporter can buffer them per-call and
|
|
88
|
+
* flush a coherent AuditEvent at terminal stream_complete.
|
|
89
|
+
*
|
|
90
|
+
* Every variant carries id/callId/ts via EngineEventBase intersection so the
|
|
91
|
+
* compiler enforces correlation fields on every emit.
|
|
92
|
+
*/
|
|
93
|
+
interface EngineEventBase {
|
|
94
|
+
/** Unique per-event UUID. */
|
|
95
|
+
id: string;
|
|
96
|
+
/** Stable per-engine.stream() invocation UUID for correlation. */
|
|
97
|
+
callId: string;
|
|
98
|
+
/** Date.now() at emit time. */
|
|
99
|
+
ts: number;
|
|
100
|
+
}
|
|
101
|
+
type EngineEvent = (EngineEventBase & {
|
|
102
|
+
kind: 'segment_start';
|
|
103
|
+
provider: string;
|
|
104
|
+
}) | (EngineEventBase & {
|
|
105
|
+
kind: 'segment_complete';
|
|
106
|
+
provider: string;
|
|
107
|
+
usage: SegmentUsage;
|
|
108
|
+
}) | (EngineEventBase & {
|
|
109
|
+
kind: 'mid_stream_failover_attempt';
|
|
110
|
+
from: string;
|
|
111
|
+
bytesBuffered: number;
|
|
112
|
+
errorClass: string;
|
|
113
|
+
retriesLeft: number;
|
|
114
|
+
}) | (EngineEventBase & {
|
|
115
|
+
kind: 'mid_stream_failover_success';
|
|
116
|
+
from: string;
|
|
117
|
+
to: string;
|
|
118
|
+
}) | (EngineEventBase & {
|
|
119
|
+
kind: 'stream_complete';
|
|
120
|
+
stitched: boolean;
|
|
121
|
+
segments: SegmentUsage[];
|
|
122
|
+
provider: string;
|
|
123
|
+
model: string;
|
|
124
|
+
inputTokens: number;
|
|
125
|
+
outputTokens: number;
|
|
126
|
+
costUsd: number;
|
|
127
|
+
userCostUsd?: number;
|
|
128
|
+
durationMs: number;
|
|
129
|
+
stopReason: string;
|
|
130
|
+
fallbackChain: string[];
|
|
131
|
+
rateLimitHit: boolean;
|
|
132
|
+
securityState?: SecurityState;
|
|
133
|
+
});
|
|
134
|
+
interface ContentBlock {
|
|
135
|
+
type: 'text' | 'tool_use';
|
|
136
|
+
text?: string;
|
|
137
|
+
id?: string;
|
|
138
|
+
name?: string;
|
|
139
|
+
input?: unknown;
|
|
140
|
+
}
|
|
141
|
+
interface Message {
|
|
142
|
+
role: 'user' | 'assistant';
|
|
143
|
+
content: string | ContentBlock[];
|
|
144
|
+
}
|
|
145
|
+
interface RoutingConfig {
|
|
146
|
+
maxCostPerCall?: number;
|
|
147
|
+
preferLocal?: boolean;
|
|
148
|
+
}
|
|
149
|
+
interface ConcurrencyConfig {
|
|
150
|
+
maxParallel?: number;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Configuration for the Hardware-Authorized Secure Enclave credential resolver.
|
|
154
|
+
* Controls how the relay reads credentials from the platform's secure enclave.
|
|
155
|
+
*/
|
|
156
|
+
interface SecureEnclaveConfig {
|
|
157
|
+
enabled?: boolean;
|
|
158
|
+
refreshTokens?: boolean;
|
|
159
|
+
allowPopup?: boolean;
|
|
160
|
+
fallbackToEnv?: boolean;
|
|
161
|
+
}
|
|
162
|
+
interface CostEstimate {
|
|
163
|
+
estimatedInputTokens: number;
|
|
164
|
+
estimatedCost: number;
|
|
165
|
+
model: string;
|
|
166
|
+
provider: string;
|
|
167
|
+
}
|
|
168
|
+
interface ProbeResult {
|
|
169
|
+
available: boolean;
|
|
170
|
+
authenticated: boolean;
|
|
171
|
+
subscriptionType?: string;
|
|
172
|
+
rateLimitTier?: string;
|
|
173
|
+
cliVersion?: string;
|
|
174
|
+
versionWarning?: string;
|
|
175
|
+
}
|
|
176
|
+
interface ProviderHealth {
|
|
177
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
178
|
+
lastError?: string;
|
|
179
|
+
lastCheckAt: number;
|
|
180
|
+
errorCount: number;
|
|
181
|
+
}
|
|
182
|
+
interface RateLimitEvent {
|
|
183
|
+
provider: string;
|
|
184
|
+
utilization: number;
|
|
185
|
+
resetsAt: number;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Credentials resolved from the Hardware-Authorized Secure Enclave.
|
|
189
|
+
* Used by the Native Subscription Gateway provider.
|
|
190
|
+
*/
|
|
191
|
+
interface SecureEnclaveCredentials {
|
|
192
|
+
accessToken: string;
|
|
193
|
+
refreshToken: string;
|
|
194
|
+
expiresAt: number;
|
|
195
|
+
subscriptionType: string;
|
|
196
|
+
rateLimitTier: string;
|
|
197
|
+
organizationUuid?: string;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Structured error thrown when the license's effective cap (base cap plus
|
|
201
|
+
* active top-up grants) has been exceeded for the current billing cycle.
|
|
202
|
+
*
|
|
203
|
+
* The library enters a "High-Frequency Probe" state on the first occurrence
|
|
204
|
+
* of this error per instance: it re-validates against /v1/validate every
|
|
205
|
+
* 15 seconds for up to 5 minutes, so a top-up purchased through the
|
|
206
|
+
* dashboard resumes inference within seconds — not after the next normal
|
|
207
|
+
* cache refresh.
|
|
208
|
+
*
|
|
209
|
+
* Consumers can catch this error and surface an in-app CTA to their end
|
|
210
|
+
* users by inspecting the `resolutionUrl` and pack fields.
|
|
211
|
+
*/
|
|
212
|
+
declare class RelayCapExceededError extends Error {
|
|
213
|
+
readonly code: "RELAY_CAP_EXCEEDED";
|
|
214
|
+
readonly tier: string;
|
|
215
|
+
readonly baseCap: number | null;
|
|
216
|
+
readonly topUps: number;
|
|
217
|
+
readonly effectiveCap: number | null;
|
|
218
|
+
readonly usedThisCycle: number;
|
|
219
|
+
readonly resolutionUrl: string;
|
|
220
|
+
constructor(opts: {
|
|
221
|
+
tier: string;
|
|
222
|
+
baseCap: number | null;
|
|
223
|
+
topUps: number;
|
|
224
|
+
effectiveCap: number | null;
|
|
225
|
+
usedThisCycle: number;
|
|
226
|
+
resolutionUrl?: string;
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export { type AuditEvent as A, type CreateParams as C, type EngineEvent as E, type InferenceRelayConfig as I, type Message as M, type ProbeResult as P, type RelayResult as R, type SecurityState as S, type CostEstimate as a, type ProviderHealth as b, type RateLimitEvent as c, type RoutingConfig as d, type ConcurrencyConfig as e, type ContentBlock as f, type ProviderConfig as g, RelayCapExceededError as h, type SecureEnclaveConfig as i, type SecureEnclaveCredentials as j, type SegmentUsage as k };
|