@wengine-ai/llms 2.3.2393 → 2.3.2395
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cjs/server.cjs +30 -30
- package/dist/cjs/server.cjs.map +3 -3
- package/dist/esm/server.mjs +5 -5
- package/dist/esm/server.mjs.map +3 -3
- package/dist/index.html +22 -22
- package/package.json +2 -2
package/dist/esm/server.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; import { fileURLToPath as __fileURLToPath } from "node:url"; import { dirname as __pathDirname } from "node:path"; const require = __createRequire(import.meta.url); const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename);
|
|
2
2
|
var $n=Object.defineProperty;var Xi=Object.getOwnPropertyDescriptor;var qi=Object.getOwnPropertyNames;var Zi=Object.prototype.hasOwnProperty;var Be=(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 w=(n,e)=>()=>(n&&(e=n(n=0)),e);var Nn=(n,e)=>{for(var t in e)$n(n,t,{get:e[t],enumerable:!0})},ea=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of qi(e))!Zi.call(n,r)&&r!==t&&$n(n,r,{get:()=>e[r],enumerable:!(o=Xi(e,r))||o.enumerable});return n};var ta=n=>ea($n({},"__esModule",{value:!0}),n);import{ProxyAgent as na}from"undici";function ra(n){if(n==null)return{ok:!0};let e=String(n).trim();if(!e)return{ok:!0};if(oa.test(e))return{ok:!0};try{let t=new URL(e);return t.protocol!=="http:"&&t.protocol!=="https:"?{ok:!1,error:`Unsupported proxy protocol: ${t.protocol}. Only http:// and https:// are allowed.`}:{ok:!0}}catch{return{ok:!1,error:`Invalid proxy URL: ${e}`}}}function pr(n){let e=[];for(let t of dr){let o=n[t];if(o==null)continue;let r=ra(o);r.ok||e.push({key:t,error:r.error})}return e}function yt(n){for(let e of dr){let t=n.get(e);if(t==null)continue;let o=String(t).trim();if(o)return o}}function fr(n){if(n==null||n==="")return!0;if(typeof n=="string"){let e=n.trim().toLowerCase();return e==="false"||e==="0"?!1:e==="true"||e==="1"?!0:!!e}return n===!1||n===0?!1:n===!0||n===1?!0:!!n}function se(n,e){let t=yt(n);if(t)return fr(n.get("PROXY_GLOBAL_ENABLED"))||e?.proxyEnabled===!0||e?.proxy_enabled===!0?t:void 0}function W(n){let e=sa(n),t=ht.get(e);if(t)return t;let o=new na(e);return ht.set(e,o),o}async function Ln(){let n=Array.from(ht.values());ht.clear(),await Promise.allSettled(n.map(e=>e.close()))}function sa(n){let e=n.trim();if(!e)throw new TypeError("Proxy URL must not be empty");let t=new URL(e);if(t.protocol!=="http:"&&t.protocol!=="https:")throw new TypeError(`Unsupported proxy protocol: ${t.protocol}`);return t.toString()}var dr,oa,ht,Z=w(()=>{"use strict";dr=["HTTPS_PROXY","https_proxy","httpsProxy","PROXY_URL"],oa=/\$\{[^}]+\}|\$[A-Z_][A-Z0-9_]*/;ht=new Map});import{readFileSync as ia,existsSync as mr}from"fs";import{join as gr}from"path";import{config as aa}from"dotenv";import ca from"json5";var ke,Dn=w(()=>{"use strict";Z();ke=class{config={};options;constructor(e={jsonPath:"./config.json"}){this.options={envPath:e.envPath||".env",jsonPath:e.jsonPath,useEnvFile:!1,useJsonFile:e.useJsonFile!==!1,useEnvironmentVariables:e.useEnvironmentVariables!==!1,...e},this.loadConfig()}loadConfig(){this.options.useJsonFile&&this.options.jsonPath&&this.loadJsonConfig(),this.options.initialConfig&&(this.config={...this.config,...this.options.initialConfig}),this.options.useEnvFile&&this.loadEnvConfig(),this.config.LOG_FILE&&(process.env.LOG_FILE=this.config.LOG_FILE),this.config.LOG&&(process.env.LOG=this.config.LOG)}loadJsonConfig(){if(!this.options.jsonPath)return;let e=this.isAbsolutePath(this.options.jsonPath)?this.options.jsonPath:gr(process.cwd(),this.options.jsonPath);if(mr(e))try{let t=ia(e,"utf-8"),o=ca.parse(t);this.config={...this.config,...o},console.log(`Loaded JSON config from: ${e}`)}catch(t){console.warn(`Failed to load JSON config from ${e}:`,t)}else console.warn(`JSON config file not found: ${e}`)}loadEnvConfig(){let e=this.isAbsolutePath(this.options.envPath)?this.options.envPath:gr(process.cwd(),this.options.envPath);if(mr(e))try{let t=aa({path:e});t.parsed&&(this.config={...this.config,...this.parseEnvConfig(t.parsed)})}catch(t){console.warn(`Failed to load .env config from ${e}:`,t)}}loadEnvironmentVariables(){let e=this.parseEnvConfig(process.env);this.config={...this.config,...e}}parseEnvConfig(e){let t={};return Object.assign(t,e),t}isAbsolutePath(e){return e.startsWith("/")||e.includes(":")}get(e,t){let o=this.config[e];return o!==void 0?o:t}getAll(){return{...this.config}}getHttpsProxy(){return yt(this)}has(e){return this.config[e]!==void 0}set(e,t){this.config[e]=t}reload(){this.config={},this.loadConfig()}getConfigSummary(){let e=[];return this.options.initialConfig&&e.push("Initial Config"),this.options.useJsonFile&&this.options.jsonPath&&e.push(`JSON: ${this.options.jsonPath}`),this.options.useEnvFile&&e.push(`ENV: ${this.options.envPath}`),this.options.useEnvironmentVariables&&e.push("Environment Variables"),`Config sources: ${e.join(", ")}`}}});function B(n,e=500,t="internal_error",o="api_error"){let r=new Error(n);return r.statusCode=e,r.code=t,r.type=o,r}async function hr(n,e,t){e.log.error(n);let o=n.statusCode||500;if(n.rawBody)try{let s=JSON.parse(n.rawBody);return t.code(o).send(s)}catch{return t.code(o).send(n.rawBody)}let r={error:{message:n.message||"Internal Server Error",type:n.type||"api_error",code:n.code||"internal_error"}};return t.code(o).send(r)}var _t=w(()=>{"use strict"});function Un(n){Fn=n}function kt(){return Fn}function bt(n){return Fn||n.get("DEBUG_LOG")===!0}function kr(n){let e=n.get("DEBUG_LOG_OPTIONS");return!e||typeof e!="object"?be:{maxBodyLength:e.maxBodyLength??be.maxBodyLength,maxStreamChunks:e.maxStreamChunks??be.maxStreamChunks}}function Tt(n){let e={};for(let[t,o]of Object.entries(n))la.has(t.toLowerCase())?e[t]="***MASKED***":e[t]=o;return e}function Ct(n,e){return n.length<=e?n:n.slice(0,e)+`...[truncated, total ${n.length} bytes]`}function br(n,e,t){let o=typeof t.body=="string"?t.body:JSON.stringify(t.body);n.info({debug_log:!0,reqId:e,phase:"provider_request",url:t.url,headers:Tt(t.headers),body:Ct(o,be.maxBodyLength)})}function Tr(n,e,t){n.info({debug_log:!0,reqId:e,phase:"provider_response",status:t.status,headers:Tt(t.headers),...t.body!==void 0?{body:Ct(t.body,be.maxBodyLength)}:{}})}function yr(n,e,t,o){let r=ua(o);n.info({debug_log:!0,reqId:e,phase:"provider_stream_chunk",chunkIndex:t,...r?{usage_monitor:r}:{},data:Ct(o,be.maxBodyLength)})}function ua(n){let e=[];for(let t of n.split(/\r?\n/)){if(!t.startsWith("data:"))continue;let o=t.slice(5).trim();if(!(!o||o==="[DONE]"))try{let r=JSON.parse(o),s=r?.usage||r?.response?.usage;s&&e.push({path:r?.usage?"usage":"response.usage",usage:s,choicesLength:Array.isArray(r?.choices)?r.choices.length:void 0,finishReason:r?.choices?.[0]?.finish_reason})}catch{e.push({parseError:!0,data:Ct(o,512)})}}if(e.length)return e.length===1?e[0]:e}function _r(n,e,t){n.info({debug_log:!0,reqId:e,phase:"provider_stream_end",totalChunks:t})}function Cr(n,e,t,o){(async()=>{let r=n.pipeThrough(new TextDecoderStream).getReader(),s=0;try{let i="";for(;;){let{done:l,value:a}=await r.read();if(l)break;i+=a;let c=i.split(`
|
|
3
3
|
|
|
4
|
-
`);i=c.pop()||"";for(let u of c)u.trim()&&(s<o.maxStreamChunks?yr(e,t,s,u):s===o.maxStreamChunks&&e.info({debug_log:!0,reqId:t,phase:"provider_stream_chunk_omitted",message:`[chunks after #${s} omitted, maxStreamChunks=${o.maxStreamChunks}]`}),s++)}i.trim()&&(s<o.maxStreamChunks&&yr(e,t,s,i.trim()),s++),_r(e,t,s)}catch(i){console.error(`[debug_log] Error reading debug stream for reqId=${t}:`,i),_r(e,t,s)}finally{r.releaseLock()}})()}var la,be,Fn,Je=w(()=>{"use strict";la=new Set(["authorization","x-api-key","x-goog-api-key","cookie","set-cookie"]),be={maxBodyLength:4096,maxStreamChunks:100},Fn=!1});function vr(n,e,t,o,r){let s=new Headers({"Content-Type":"application/json"});t.headers&&Object.entries(t.headers).forEach(([c,u])=>{u&&s.set(c,u)});let i,l=AbortSignal.timeout(t.TIMEOUT??60*1e3*60);if(t.signal){let c=new AbortController,u=()=>c.abort();t.signal.addEventListener("abort",u),l.addEventListener("abort",u),i=c.signal}else i=l;let a={method:"POST",headers:s,body:JSON.stringify(e),signal:i};return t.httpsProxy&&(a.dispatcher=W(t.httpsProxy)),r?.debug({reqId:o.req.id,method:"POST",headers:Tt(Object.fromEntries(s.entries())),requestUrl:typeof n=="string"?n:n.toString(),useProxy:da(t.httpsProxy)},"final request"),fetch(typeof n=="string"?n:n.toString(),a)}function da(n){if(!(typeof n!="string"||!n.trim()))try{let e=new URL(n);return e.username||e.password?(e.username="",e.password="",`${e.toString()} (credentials redacted)`):e.toString()}catch{return"[invalid proxy URL]"}}var xr=w(()=>{Z();Je()});var vt,jn=w(()=>{vt="2.3.2393"});var Sr={};Nn(Sr,{getFallbackPromotionStore:()=>Te,resetFallbackPromotionStore:()=>ma});function Te(n){return me||(me=new Hn,n&&me.configure(n)),me}function ma(){me&&(me.clearAll(),me=null)}var fa,Hn,me,xt=w(()=>{"use strict";ee();fa=600*1e3,Hn=class{promotions=new Map;enabled=!0;ttlMs=fa;configure(e){e?.enabled!==void 0&&(this.enabled=e.enabled),e?.ttlMinutes!==void 0&&(this.ttlMs=e.ttlMinutes*60*1e3)}getKey(e,t,o){return`${e},${t}:${o}`}promote(e,t,o,r,s,i){if(!this.enabled)return;let l=this.getKey(e,t,o),a=`${r},${s}`;this.promotions.set(l,{promotedModel:a,timestamp:Date.now(),ttlMs:i??this.ttlMs})}getPromotion(e,t,o,r){if(!this.enabled)return null;let s=this.getKey(e,t,o),i=this.promotions.get(s);if(!i)return null;if(Date.now()-i.timestamp>=i.ttlMs)return this.promotions.delete(s),null;let[a,...c]=i.promotedModel.split(","),u=c.join(",");if(!F().isAvailable(a,u))return this.promotions.delete(s),null;let g=r.find(y=>y.name.toLowerCase()===a.toLowerCase()),m=g?.models?.find(y=>String(y).toLowerCase()===u.toLowerCase());return!g||!m||g.enabled===!1?(this.promotions.delete(s),null):`${g.name},${m}`}clear(e,t,o){let r=this.getKey(e,t,o);this.promotions.delete(r)}clearByPrimary(e,t){let o=`${e},${t}:`,r=0;for(let s of this.promotions.keys())s.startsWith(o)&&(this.promotions.delete(s),r++);return r}clearAll(){this.promotions.clear()}clearExpired(){let e=Date.now();for(let[t,o]of this.promotions)e-o.timestamp>=o.ttlMs&&this.promotions.delete(t)}getAllPromotions(){let e=Date.now(),t=[];for(let[o,r]of this.promotions){let s=r.ttlMs-(e-r.timestamp);s>0&&t.push({key:o,promotedModel:r.promotedModel,remainingMs:s})}return t}},me=null});import{existsSync as Pr,mkdirSync as ga,readFileSync as ha,writeFileSync as ya}from"fs";import{join as Er}from"path";import{HOME_DIR as _a}from"@wengine-ai/claude-code-router-shared";function Ca(n){try{if(!Pr(Jn))return;let e=JSON.parse(ha(Jn,"utf-8"));if(!Array.isArray(e))return;let t=Date.now();for(let o of e){if(!o||!o.provider||!o.model)continue;let r=o.updatedAt||o.lastFailureTime||0;r&&t-r>1440*60*1e3||n.restore({provider:o.provider,model:o.model,status:o.status,failureCount:o.failureCount??0,successCount:o.successCount??0,lastFailureTime:o.lastFailureTime??0,lastProbeTime:o.lastProbeTime??0,lastError:o.lastError,rateLimitUntil:o.rateLimitUntil})}}catch{}}function wr(n){try{let e=n.getAllStates();if(e.length===0)return;Pr(Bn)||ga(Bn,{recursive:!0});let t=e.map(o=>({...o,updatedAt:Date.now()}));ya(Jn,JSON.stringify(t,null,2),"utf-8")}catch{}}function Wn(){if(Rr)return;Rr=!0;let n=F();Ca(n),Ta=setInterval(()=>wr(n),6e4),process.on("exit",()=>wr(n))}function F(n){return zn||(zn=new St(n)),zn}var ka,ba,St,Bn,Jn,Rr,Ta,zn,ee=w(()=>{"use strict";ka=120,ba={enabled:!0,failureThreshold:3,probeIntervalMinutes:5,halfOpenSuccessThreshold:2},St=class{states=new Map;config;probeTimer;constructor(e){this.config={...ba,...e}}getKey(e,t){return!e||!t?null:`${e},${t}`}recordSuccess(e,t){if(!this.config.enabled)return;let o=this.getKey(e,t);if(!o)return;let r=this.states.get(o);r&&(r.successCount++,!r.rateLimitUntil&&(r.status==="half-open"?r.successCount>=this.config.halfOpenSuccessThreshold&&(this.clearPromotionsForPrimary(e,t),this.states.delete(o)):r.status==="open"&&(r.status="half-open",r.successCount=1,r.failureCount=0)))}clearPromotionsForPrimary(e,t){try{let{getFallbackPromotionStore:o}=(xt(),ta(Sr));o().clearByPrimary(e,t)}catch{}}recordFailure(e,t,o){if(!this.config.enabled)return;let r=this.getKey(e,t);if(!r)return;let s=this.states.get(r);s||(s={provider:e,model:t,status:"closed",failureCount:0,successCount:0,lastFailureTime:0,lastProbeTime:0},this.states.set(r,s)),s.failureCount++,s.lastFailureTime=Date.now(),s.lastError=o,s.status==="half-open"?(s.status="open",s.successCount=0,s.lastProbeTime=0):s.status==="closed"&&s.failureCount>=this.config.failureThreshold&&(s.status="open",s.lastProbeTime=0)}getState(e,t){let o=this.getKey(e,t);if(o)return this.states.get(o)}isAvailable(e,t){if(!this.config.enabled)return!0;if(!this.getKey(e,t))return!1;let r=this.getState(e,t);return r?r.status==="open"&&r.rateLimitUntil?!(Date.now()<r.rateLimitUntil):r.status!=="open":!0}getPriority(e,t){if(!this.config.enabled)return 0;if(!this.getKey(e,t))return 2;let r=this.getState(e,t);if(!r)return 0;switch(r.status){case"closed":return 0;case"half-open":return 1;case"open":return 2}}getHealthyModels(){return[]}getFailPoolModels(){let e=[];for(let[t,o]of this.states)o.status==="open"&&e.push(t);return e}getHalfOpenModels(){let e=[];for(let[t,o]of this.states)o.status==="half-open"&&e.push(t);return e}forceOpen(e,t,o){if(!this.config.enabled)return;let r=this.getKey(e,t);if(!r)return;let s=this.states.get(r);s?(s.status="open",s.failureCount=Math.max(s.failureCount,this.config.failureThreshold),s.lastFailureTime=Date.now(),s.lastError=o,s.lastProbeTime=0):(s={provider:e,model:t,status:"open",failureCount:this.config.failureThreshold,successCount:0,lastFailureTime:Date.now(),lastProbeTime:0,lastError:o},this.states.set(r,s))}markRateLimited(e,t,o,r){if(!this.config.enabled)return;let s=this.getKey(e,t);if(!s)return;let i=this.states.get(s);i?(i.status="open",i.lastFailureTime=Date.now(),i.lastError=r||"rate-limited",i.lastProbeTime=0):(i={provider:e,model:t,status:"open",failureCount:0,successCount:0,lastFailureTime:Date.now(),lastProbeTime:0,lastError:r||"rate-limited"},this.states.set(s,i));let l=(o??ka)*1e3;i.rateLimitUntil=Date.now()+l}getRateLimitedModels(){let e=[];for(let[t,o]of this.states)o.status==="open"&&o.rateLimitUntil&&e.push(t);return e}needsProbe(e){return Date.now()-e.lastProbeTime>=this.config.probeIntervalMinutes*60*1e3}markProbeAttempt(e,t){let o=this.getKey(e,t);if(!o)return;let r=this.states.get(o);r&&r.status==="open"&&(r.lastProbeTime=Date.now())}clear(){this.states.clear()}recover(e,t){let o=this.getKey(e,t);o&&this.states.delete(o)}getAllStates(){return Array.from(this.states.values())}restore(e){let t=this.getKey(e.provider,e.model);t&&this.states.set(t,{...e})}stopProbeTimer(){this.probeTimer&&(clearInterval(this.probeTimer),this.probeTimer=void 0)}},Bn=Er(_a,"runtime"),Jn=Er(Bn,"provider-health.json"),Rr=!1,Ta=null;zn=null});import{existsSync as $r,mkdirSync as va,readFileSync as xa,writeFileSync as Sa}from"fs";import{join as Nr}from"path";import{HOME_DIR as Ra}from"@wengine-ai/claude-code-router-shared";function We(n,e,t){let o=l=>{if(t instanceof Headers)return t.get(l);let a=Object.keys(t).find(c=>c.toLowerCase()===l);return a?t[a]:null},r=Gn(o,wa),s=Gn(o,Pa),i=Gn(o,Ea);(r||s||i)&&Ce.set(n,{provider:n,remaining:Ir(r),limit:Ir(s),reset:Aa(i),capturedAt:Date.now()})}function Oa(n){return Ce.get(n)}function Vn(){return Array.from(Ce.values())}function Gn(n,e){for(let t of e){let o=n(t);if(o)return o}return null}function Ir(n){if(!n)return null;let e=Number(n.trim().replace(/,/g,""));return Number.isFinite(e)?e:null}function Aa(n){if(!n)return null;let e=n.trim();if(!e)return null;let t=Number(e);if(Number.isFinite(t))return t>1e12?Math.floor(t/1e3):t>1e9?Math.floor(t):Math.floor(Date.now()/1e3+t);let o=Date.parse(e);if(Number.isFinite(o))return Math.floor(o/1e3);let r=Ia(e);return r===null?null:Math.floor((Date.now()+r)/1e3)}function Ia(n){let e=/(\d+(?:\.\d+)?)(ms|s|m|h|d)/gi,t=0,o=!1;for(let r of n.matchAll(e)){o=!0;let s=Number(r[1]),i=r[2].toLowerCase();if(Number.isFinite(s))switch(i){case"ms":t+=s;break;case"s":t+=s*1e3;break;case"m":t+=s*60*1e3;break;case"h":t+=s*60*60*1e3;break;case"d":t+=s*24*60*60*1e3;break}}return o?t:null}function Ma(){try{if(!$r(Qn))return;let n=JSON.parse(xa(Qn,"utf-8"));if(!Array.isArray(n))return;let e=Date.now();for(let t of n)if(t&&t.provider){if(t.capturedAt&&e-t.capturedAt>3600*1e3)continue;Ce.set(t.provider,t)}}catch{}}function Mr(){try{if(Ce.size===0)return;$r(Kn)||va(Kn,{recursive:!0}),Sa(Qn,JSON.stringify(Array.from(Ce.values()),null,2),"utf-8")}catch{}}function Ge(){Or||(Or=!0,Ma(),Ar=setInterval(Mr,6e4),Ar.unref?.(),process.on("exit",Mr))}var Kn,Qn,Ce,Or,Ar,wa,Pa,Ea,ve=w(()=>{"use strict";Kn=Nr(Ra,"runtime"),Qn=Nr(Kn,"rate-limit.json"),Ce=new Map,Or=!1,Ar=null,wa=["x-ratelimit-remaining-tokens","x-ratelimit-remaining-requests","x-ratelimit-remaining"],Pa=["x-ratelimit-limit-tokens","x-ratelimit-limit-requests","x-ratelimit-limit"],Ea=["x-ratelimit-reset-tokens","x-ratelimit-reset-requests","x-ratelimit-reset"]});var xe,Yn=w(()=>{"use strict";xe=class{name="openai-responses";endPoint="/v1/responses";getCacheReadInputTokens(e){return e?.cache_read_input_tokens??e?.input_tokens_details?.cached_tokens??e?.prompt_tokens_details?.cached_tokens??0}getCacheCreationInputTokens(e){return e?.cache_creation_input_tokens??e?.input_tokens_details?.cache_creation_tokens??e?.input_tokens_details?.cache_write_tokens??e?.prompt_tokens_details?.cache_creation_tokens??e?.prompt_tokens_details?.cache_write_tokens??0}buildResponsesUsage(e){let t=e?.input_tokens??e?.prompt_tokens??0,o=e?.output_tokens??e?.completion_tokens??0,r=this.getCacheReadInputTokens(e),s=this.getCacheCreationInputTokens(e);return{input_tokens:t,output_tokens:o,total_tokens:e?.total_tokens??t+o,input_tokens_details:{cached_tokens:r,cache_creation_tokens:s},output_tokens_details:{reasoning_tokens:e?.output_tokens_details?.reasoning_tokens??0},cache_read_input_tokens:r,cache_creation_input_tokens:s}}async transformRequestIn(e){delete e.temperature,delete e.max_tokens,e.reasoning&&(e.reasoning={effort:e.reasoning.effort,summary:e.reasoning.summary||"auto"});let t=[],o=e.messages.filter(r=>r.role==="system");if(o.length>0){let r=o[0];Array.isArray(r.content)?r.content.forEach(s=>{let i="";typeof s=="string"?i=s:s&&typeof s=="object"&&"text"in s&&(i=s.text),t.push({role:"system",content:i})}):e.instructions=r.content}if(e.messages.forEach(r=>{if(r.role!=="system"){if(Array.isArray(r.content)){let s=r.content.map(i=>this.normalizeRequestContent(i,r.role)).filter(i=>i!==null);s.length>0?r.content=s:delete r.content}if(r.role==="tool"){let s={...r};s.type="function_call_output",s.call_id=r.tool_call_id,s.output=r.content,delete s.cache_control,delete s.role,delete s.tool_call_id,delete s.content,t.push(s);return}if(r.role==="assistant"&&Array.isArray(r.tool_calls)){r.tool_calls.forEach(s=>{t.push({type:"function_call",arguments:s.function.arguments,name:s.function.name,call_id:s.id})});return}t.push(r)}}),e.input=t,delete e.messages,Array.isArray(e.tools)){let r=e.tools.find(s=>s.function.name==="web_search");e.tools=e.tools.filter(s=>s.function.name!=="web_search").map(s=>(s.function.name==="WebSearch"&&delete s.function.parameters.properties.allowed_domains,s.function.name==="Edit"?{type:s.type,name:s.function.name,description:s.function.description,parameters:{...s.function.parameters,required:["file_path","old_string","new_string","replace_all"]},strict:!0}:{type:s.type,name:s.function.name,description:s.function.description,parameters:s.function.parameters})),r&&e.tools.push({type:"web_search"})}return e.parallel_tool_calls=!1,e}async transformResponseOut(e){let t=e.headers.get("Content-Type")||"";if(t.includes("application/json")){let o=await e.json();if(o.object==="response"&&o.output){let r=this.convertResponseToChat(o);return new Response(JSON.stringify(r),{status:e.status,statusText:e.statusText,headers:e.headers})}return o.type==="message"&&Array.isArray(o.content)?new Response(JSON.stringify(o),{status:e.status,statusText:e.statusText,headers:e.headers}):new Response(JSON.stringify(o),{status:e.status,statusText:e.statusText,headers:e.headers})}else if(t.includes("text/event-stream")){if(!e.body)return e;let[o,r]=e.body.tee(),s=o.getReader(),i="";try{let{value:f,done:_}=await s.read();!_&&f&&(i=new TextDecoder().decode(f))}finally{s.releaseLock()}if(o.cancel().catch(()=>{}),i.includes("message_start")||i.includes("content_block_start")){let f=this.prependToStream(i,r);return new Response(f,{status:e.status,statusText:e.statusText,headers:e.headers})}if(i.includes("response.created")||i.includes("response.output_text.delta")||i.includes("response.in_progress")||i.includes("response.output_item.added")){let f=this.prependToStream(i,r);return new Response(f,{status:e.status,statusText:e.statusText,headers:e.headers})}let c=this.prependToStream(i,r),u=new TextDecoder,d=new TextEncoder,g="",m=!1,y=this,p=new ReadableStream({async start(f){let _=c.getReader(),k=-1,h="",b=T=>(T!==h&&(k++,h=T),k);try{for(;;){let{done:T,value:x}=await _.read();if(T){m||f.enqueue(d.encode(`data: [DONE]
|
|
4
|
+
`);i=c.pop()||"";for(let u of c)u.trim()&&(s<o.maxStreamChunks?yr(e,t,s,u):s===o.maxStreamChunks&&e.info({debug_log:!0,reqId:t,phase:"provider_stream_chunk_omitted",message:`[chunks after #${s} omitted, maxStreamChunks=${o.maxStreamChunks}]`}),s++)}i.trim()&&(s<o.maxStreamChunks&&yr(e,t,s,i.trim()),s++),_r(e,t,s)}catch(i){console.error(`[debug_log] Error reading debug stream for reqId=${t}:`,i),_r(e,t,s)}finally{r.releaseLock()}})()}var la,be,Fn,Je=w(()=>{"use strict";la=new Set(["authorization","x-api-key","x-goog-api-key","cookie","set-cookie"]),be={maxBodyLength:4096,maxStreamChunks:100},Fn=!1});function vr(n,e,t,o,r){let s=new Headers({"Content-Type":"application/json"});t.headers&&Object.entries(t.headers).forEach(([c,u])=>{u&&s.set(c,u)});let i,l=AbortSignal.timeout(t.TIMEOUT??60*1e3*60);if(t.signal){let c=new AbortController,u=()=>c.abort();t.signal.addEventListener("abort",u),l.addEventListener("abort",u),i=c.signal}else i=l;let a={method:"POST",headers:s,body:JSON.stringify(e),signal:i};return t.httpsProxy&&(a.dispatcher=W(t.httpsProxy)),r?.debug({reqId:o.req.id,method:"POST",headers:Tt(Object.fromEntries(s.entries())),requestUrl:typeof n=="string"?n:n.toString(),useProxy:da(t.httpsProxy)},"final request"),fetch(typeof n=="string"?n:n.toString(),a)}function da(n){if(!(typeof n!="string"||!n.trim()))try{let e=new URL(n);return e.username||e.password?(e.username="",e.password="",`${e.toString()} (credentials redacted)`):e.toString()}catch{return"[invalid proxy URL]"}}var xr=w(()=>{Z();Je()});var vt,jn=w(()=>{vt="2.3.2395"});var Sr={};Nn(Sr,{getFallbackPromotionStore:()=>Te,resetFallbackPromotionStore:()=>ma});function Te(n){return me||(me=new Hn,n&&me.configure(n)),me}function ma(){me&&(me.clearAll(),me=null)}var fa,Hn,me,xt=w(()=>{"use strict";ee();fa=600*1e3,Hn=class{promotions=new Map;enabled=!0;ttlMs=fa;configure(e){e?.enabled!==void 0&&(this.enabled=e.enabled),e?.ttlMinutes!==void 0&&(this.ttlMs=e.ttlMinutes*60*1e3)}getKey(e,t,o){return`${e},${t}:${o}`}promote(e,t,o,r,s,i){if(!this.enabled)return;let l=this.getKey(e,t,o),a=`${r},${s}`;this.promotions.set(l,{promotedModel:a,timestamp:Date.now(),ttlMs:i??this.ttlMs})}getPromotion(e,t,o,r){if(!this.enabled)return null;let s=this.getKey(e,t,o),i=this.promotions.get(s);if(!i)return null;if(Date.now()-i.timestamp>=i.ttlMs)return this.promotions.delete(s),null;let[a,...c]=i.promotedModel.split(","),u=c.join(",");if(!F().isAvailable(a,u))return this.promotions.delete(s),null;let g=r.find(y=>y.name.toLowerCase()===a.toLowerCase()),m=g?.models?.find(y=>String(y).toLowerCase()===u.toLowerCase());return!g||!m||g.enabled===!1?(this.promotions.delete(s),null):`${g.name},${m}`}clear(e,t,o){let r=this.getKey(e,t,o);this.promotions.delete(r)}clearByPrimary(e,t){let o=`${e},${t}:`,r=0;for(let s of this.promotions.keys())s.startsWith(o)&&(this.promotions.delete(s),r++);return r}clearAll(){this.promotions.clear()}clearExpired(){let e=Date.now();for(let[t,o]of this.promotions)e-o.timestamp>=o.ttlMs&&this.promotions.delete(t)}getAllPromotions(){let e=Date.now(),t=[];for(let[o,r]of this.promotions){let s=r.ttlMs-(e-r.timestamp);s>0&&t.push({key:o,promotedModel:r.promotedModel,remainingMs:s})}return t}},me=null});import{existsSync as Pr,mkdirSync as ga,readFileSync as ha,writeFileSync as ya}from"fs";import{join as Er}from"path";import{HOME_DIR as _a}from"@wengine-ai/claude-code-router-shared";function Ca(n){try{if(!Pr(Jn))return;let e=JSON.parse(ha(Jn,"utf-8"));if(!Array.isArray(e))return;let t=Date.now();for(let o of e){if(!o||!o.provider||!o.model)continue;let r=o.updatedAt||o.lastFailureTime||0;r&&t-r>1440*60*1e3||n.restore({provider:o.provider,model:o.model,status:o.status,failureCount:o.failureCount??0,successCount:o.successCount??0,lastFailureTime:o.lastFailureTime??0,lastProbeTime:o.lastProbeTime??0,lastError:o.lastError,rateLimitUntil:o.rateLimitUntil})}}catch{}}function wr(n){try{let e=n.getAllStates();if(e.length===0)return;Pr(Bn)||ga(Bn,{recursive:!0});let t=e.map(o=>({...o,updatedAt:Date.now()}));ya(Jn,JSON.stringify(t,null,2),"utf-8")}catch{}}function Wn(){if(Rr)return;Rr=!0;let n=F();Ca(n),Ta=setInterval(()=>wr(n),6e4),process.on("exit",()=>wr(n))}function F(n){return zn||(zn=new St(n)),zn}var ka,ba,St,Bn,Jn,Rr,Ta,zn,ee=w(()=>{"use strict";ka=120,ba={enabled:!0,failureThreshold:3,probeIntervalMinutes:5,halfOpenSuccessThreshold:2},St=class{states=new Map;config;probeTimer;constructor(e){this.config={...ba,...e}}getKey(e,t){return!e||!t?null:`${e},${t}`}recordSuccess(e,t){if(!this.config.enabled)return;let o=this.getKey(e,t);if(!o)return;let r=this.states.get(o);r&&(r.successCount++,!r.rateLimitUntil&&(r.status==="half-open"?r.successCount>=this.config.halfOpenSuccessThreshold&&(this.clearPromotionsForPrimary(e,t),this.states.delete(o)):r.status==="open"&&(r.status="half-open",r.successCount=1,r.failureCount=0)))}clearPromotionsForPrimary(e,t){try{let{getFallbackPromotionStore:o}=(xt(),ta(Sr));o().clearByPrimary(e,t)}catch{}}recordFailure(e,t,o){if(!this.config.enabled)return;let r=this.getKey(e,t);if(!r)return;let s=this.states.get(r);s||(s={provider:e,model:t,status:"closed",failureCount:0,successCount:0,lastFailureTime:0,lastProbeTime:0},this.states.set(r,s)),s.failureCount++,s.lastFailureTime=Date.now(),s.lastError=o,s.status==="half-open"?(s.status="open",s.successCount=0,s.lastProbeTime=0):s.status==="closed"&&s.failureCount>=this.config.failureThreshold&&(s.status="open",s.lastProbeTime=0)}getState(e,t){let o=this.getKey(e,t);if(o)return this.states.get(o)}isAvailable(e,t){if(!this.config.enabled)return!0;if(!this.getKey(e,t))return!1;let r=this.getState(e,t);return r?r.status==="open"&&r.rateLimitUntil?!(Date.now()<r.rateLimitUntil):r.status!=="open":!0}getPriority(e,t){if(!this.config.enabled)return 0;if(!this.getKey(e,t))return 2;let r=this.getState(e,t);if(!r)return 0;switch(r.status){case"closed":return 0;case"half-open":return 1;case"open":return 2}}getHealthyModels(){return[]}getFailPoolModels(){let e=[];for(let[t,o]of this.states)o.status==="open"&&e.push(t);return e}getHalfOpenModels(){let e=[];for(let[t,o]of this.states)o.status==="half-open"&&e.push(t);return e}forceOpen(e,t,o){if(!this.config.enabled)return;let r=this.getKey(e,t);if(!r)return;let s=this.states.get(r);s?(s.status="open",s.failureCount=Math.max(s.failureCount,this.config.failureThreshold),s.lastFailureTime=Date.now(),s.lastError=o,s.lastProbeTime=0):(s={provider:e,model:t,status:"open",failureCount:this.config.failureThreshold,successCount:0,lastFailureTime:Date.now(),lastProbeTime:0,lastError:o},this.states.set(r,s))}markRateLimited(e,t,o,r){if(!this.config.enabled)return;let s=this.getKey(e,t);if(!s)return;let i=this.states.get(s);i?(i.status="open",i.lastFailureTime=Date.now(),i.lastError=r||"rate-limited",i.lastProbeTime=0):(i={provider:e,model:t,status:"open",failureCount:0,successCount:0,lastFailureTime:Date.now(),lastProbeTime:0,lastError:r||"rate-limited"},this.states.set(s,i));let l=(o??ka)*1e3;i.rateLimitUntil=Date.now()+l}getRateLimitedModels(){let e=[];for(let[t,o]of this.states)o.status==="open"&&o.rateLimitUntil&&e.push(t);return e}needsProbe(e){return Date.now()-e.lastProbeTime>=this.config.probeIntervalMinutes*60*1e3}markProbeAttempt(e,t){let o=this.getKey(e,t);if(!o)return;let r=this.states.get(o);r&&r.status==="open"&&(r.lastProbeTime=Date.now())}clear(){this.states.clear()}recover(e,t){let o=this.getKey(e,t);o&&this.states.delete(o)}getAllStates(){return Array.from(this.states.values())}restore(e){let t=this.getKey(e.provider,e.model);t&&this.states.set(t,{...e})}stopProbeTimer(){this.probeTimer&&(clearInterval(this.probeTimer),this.probeTimer=void 0)}},Bn=Er(_a,"runtime"),Jn=Er(Bn,"provider-health.json"),Rr=!1,Ta=null;zn=null});import{existsSync as $r,mkdirSync as va,readFileSync as xa,writeFileSync as Sa}from"fs";import{join as Nr}from"path";import{HOME_DIR as Ra}from"@wengine-ai/claude-code-router-shared";function We(n,e,t){let o=l=>{if(t instanceof Headers)return t.get(l);let a=Object.keys(t).find(c=>c.toLowerCase()===l);return a?t[a]:null},r=Gn(o,wa),s=Gn(o,Pa),i=Gn(o,Ea);(r||s||i)&&Ce.set(n,{provider:n,remaining:Ir(r),limit:Ir(s),reset:Aa(i),capturedAt:Date.now()})}function Oa(n){return Ce.get(n)}function Vn(){return Array.from(Ce.values())}function Gn(n,e){for(let t of e){let o=n(t);if(o)return o}return null}function Ir(n){if(!n)return null;let e=Number(n.trim().replace(/,/g,""));return Number.isFinite(e)?e:null}function Aa(n){if(!n)return null;let e=n.trim();if(!e)return null;let t=Number(e);if(Number.isFinite(t))return t>1e12?Math.floor(t/1e3):t>1e9?Math.floor(t):Math.floor(Date.now()/1e3+t);let o=Date.parse(e);if(Number.isFinite(o))return Math.floor(o/1e3);let r=Ia(e);return r===null?null:Math.floor((Date.now()+r)/1e3)}function Ia(n){let e=/(\d+(?:\.\d+)?)(ms|s|m|h|d)/gi,t=0,o=!1;for(let r of n.matchAll(e)){o=!0;let s=Number(r[1]),i=r[2].toLowerCase();if(Number.isFinite(s))switch(i){case"ms":t+=s;break;case"s":t+=s*1e3;break;case"m":t+=s*60*1e3;break;case"h":t+=s*60*60*1e3;break;case"d":t+=s*24*60*60*1e3;break}}return o?t:null}function Ma(){try{if(!$r(Qn))return;let n=JSON.parse(xa(Qn,"utf-8"));if(!Array.isArray(n))return;let e=Date.now();for(let t of n)if(t&&t.provider){if(t.capturedAt&&e-t.capturedAt>3600*1e3)continue;Ce.set(t.provider,t)}}catch{}}function Mr(){try{if(Ce.size===0)return;$r(Kn)||va(Kn,{recursive:!0}),Sa(Qn,JSON.stringify(Array.from(Ce.values()),null,2),"utf-8")}catch{}}function Ge(){Or||(Or=!0,Ma(),Ar=setInterval(Mr,6e4),Ar.unref?.(),process.on("exit",Mr))}var Kn,Qn,Ce,Or,Ar,wa,Pa,Ea,ve=w(()=>{"use strict";Kn=Nr(Ra,"runtime"),Qn=Nr(Kn,"rate-limit.json"),Ce=new Map,Or=!1,Ar=null,wa=["x-ratelimit-remaining-tokens","x-ratelimit-remaining-requests","x-ratelimit-remaining"],Pa=["x-ratelimit-limit-tokens","x-ratelimit-limit-requests","x-ratelimit-limit"],Ea=["x-ratelimit-reset-tokens","x-ratelimit-reset-requests","x-ratelimit-reset"]});var xe,Yn=w(()=>{"use strict";xe=class{name="openai-responses";endPoint="/v1/responses";getCacheReadInputTokens(e){return e?.cache_read_input_tokens??e?.input_tokens_details?.cached_tokens??e?.prompt_tokens_details?.cached_tokens??0}getCacheCreationInputTokens(e){return e?.cache_creation_input_tokens??e?.input_tokens_details?.cache_creation_tokens??e?.input_tokens_details?.cache_write_tokens??e?.prompt_tokens_details?.cache_creation_tokens??e?.prompt_tokens_details?.cache_write_tokens??0}buildResponsesUsage(e){let t=e?.input_tokens??e?.prompt_tokens??0,o=e?.output_tokens??e?.completion_tokens??0,r=this.getCacheReadInputTokens(e),s=this.getCacheCreationInputTokens(e);return{input_tokens:t,output_tokens:o,total_tokens:e?.total_tokens??t+o,input_tokens_details:{cached_tokens:r,cache_creation_tokens:s},output_tokens_details:{reasoning_tokens:e?.output_tokens_details?.reasoning_tokens??0},cache_read_input_tokens:r,cache_creation_input_tokens:s}}async transformRequestIn(e){delete e.temperature,delete e.max_tokens,e.reasoning&&(e.reasoning={effort:e.reasoning.effort,summary:e.reasoning.summary||"auto"});let t=[],o=e.messages.filter(r=>r.role==="system");if(o.length>0){let r=o[0];Array.isArray(r.content)?r.content.forEach(s=>{let i="";typeof s=="string"?i=s:s&&typeof s=="object"&&"text"in s&&(i=s.text),t.push({role:"system",content:i})}):e.instructions=r.content}if(e.messages.forEach(r=>{if(r.role!=="system"){if(Array.isArray(r.content)){let s=r.content.map(i=>this.normalizeRequestContent(i,r.role)).filter(i=>i!==null);s.length>0?r.content=s:delete r.content}if(r.role==="tool"){let s={...r};s.type="function_call_output",s.call_id=r.tool_call_id,s.output=r.content,delete s.cache_control,delete s.role,delete s.tool_call_id,delete s.content,t.push(s);return}if(r.role==="assistant"&&Array.isArray(r.tool_calls)){r.tool_calls.forEach(s=>{t.push({type:"function_call",arguments:s.function.arguments,name:s.function.name,call_id:s.id})});return}t.push(r)}}),e.input=t,delete e.messages,Array.isArray(e.tools)){let r=e.tools.find(s=>s.function.name==="web_search");e.tools=e.tools.filter(s=>s.function.name!=="web_search").map(s=>(s.function.name==="WebSearch"&&delete s.function.parameters.properties.allowed_domains,s.function.name==="Edit"?{type:s.type,name:s.function.name,description:s.function.description,parameters:{...s.function.parameters,required:["file_path","old_string","new_string","replace_all"]},strict:!0}:{type:s.type,name:s.function.name,description:s.function.description,parameters:s.function.parameters})),r&&e.tools.push({type:"web_search"})}return e.parallel_tool_calls=!1,e}async transformResponseOut(e){let t=e.headers.get("Content-Type")||"";if(t.includes("application/json")){let o=await e.json();if(o.object==="response"&&o.output){let r=this.convertResponseToChat(o);return new Response(JSON.stringify(r),{status:e.status,statusText:e.statusText,headers:e.headers})}return o.type==="message"&&Array.isArray(o.content)?new Response(JSON.stringify(o),{status:e.status,statusText:e.statusText,headers:e.headers}):new Response(JSON.stringify(o),{status:e.status,statusText:e.statusText,headers:e.headers})}else if(t.includes("text/event-stream")){if(!e.body)return e;let[o,r]=e.body.tee(),s=o.getReader(),i="";try{let{value:f,done:_}=await s.read();!_&&f&&(i=new TextDecoder().decode(f))}finally{s.releaseLock()}if(o.cancel().catch(()=>{}),i.includes("message_start")||i.includes("content_block_start")){let f=this.prependToStream(i,r);return new Response(f,{status:e.status,statusText:e.statusText,headers:e.headers})}if(i.includes("response.created")||i.includes("response.output_text.delta")||i.includes("response.in_progress")||i.includes("response.output_item.added")){let f=this.prependToStream(i,r);return new Response(f,{status:e.status,statusText:e.statusText,headers:e.headers})}let c=this.prependToStream(i,r),u=new TextDecoder,d=new TextEncoder,g="",m=!1,y=this,p=new ReadableStream({async start(f){let _=c.getReader(),k=-1,h="",b=T=>(T!==h&&(k++,h=T),k);try{for(;;){let{done:T,value:x}=await _.read();if(T){m||f.enqueue(d.encode(`data: [DONE]
|
|
5
5
|
|
|
6
6
|
`));break}let v=u.decode(x,{stream:!0});g+=v;let S=g.split(/\r?\n/);g=S.pop()||"";for(let C of S)if(C.trim())try{if(C.startsWith("event: "))continue;if(C.startsWith("data: ")){let P=C.slice(5).trim();if(P==="[DONE]"){m=!0,f.enqueue(d.encode(`data: [DONE]
|
|
7
7
|
|
|
@@ -39,7 +39,7 @@ data: ${JSON.stringify(N)}
|
|
|
39
39
|
`),C=(A,N=[])=>({id:i,object:"response",created_at:Math.floor(Date.now()/1e3),status:A,model:s,output:N,usage:this.buildResponsesUsage()}),P=()=>{k||(k=!0,E.enqueue(S("response.created",{type:"response.created",response:C("in_progress")})),E.enqueue(S("response.in_progress",{type:"response.in_progress",response:C("in_progress")})))},R=(A,N)=>{E.enqueue(S("response.output_item.done",{type:"response.output_item.done",output_index:A,item:{...N,status:"completed"}}))},O=A=>{if(!T){if(T=!0,h){let N=v.find(D=>D.type==="message");N&&(N.content=[{type:"output_text",text:l}],N.status="completed")}for(let N of v)N.type==="function_call"&&(N.status="completed");return S("response.completed",{type:"response.completed",response:{id:i,object:"response",created_at:Math.floor(Date.now()/1e3),status:"completed",model:s,output:v,usage:A?{...this.buildResponsesUsage(A)}:this.buildResponsesUsage()}})}},E;return new ReadableStream({async start(A){E=A;try{let N=e.getReader(),D="";for(;;){let{done:$,value:L}=await N.read();if($)break;D+=o.decode(L,{stream:!0});let J=D.split(`
|
|
40
40
|
`);D=J.pop()||"";for(let fe of J){let U=fe.trim();if(!U||U.startsWith("event:")||!U.startsWith("data:"))continue;let Q=U.slice(5).trim();if(Q==="[DONE]")continue;let H;try{H=JSON.parse(Q)}catch{continue}if(H.type==="message_start"&&(i=H.message?.id||i,P()),H.type==="content_block_start"){let I=H.content_block;if(x=I?.type||null,I?.type==="tool_use"){u=I.id||"",d=I.name||"",g="",m=_++;let z={id:u,type:"function_call",status:"in_progress",call_id:u,name:d,arguments:""};v.push(z),E.enqueue(S("response.output_item.added",{type:"response.output_item.added",output_index:m,item:z}))}if(I?.type==="thinking"&&(y=I.thinking||"",!b)){b=!0,f=_++,p=`rs_${i}`;let z={id:p,type:"reasoning",status:"in_progress",summary:[]};v.push(z),E.enqueue(S("response.output_item.added",{type:"response.output_item.added",output_index:f,item:z}))}if(I?.type==="text"&&(l=I?.text||"",!h)){h=!0,c=_++,a=`${i}_msg`;let z={id:a,type:"message",status:"in_progress",role:"assistant",content:[]};v.push(z),E.enqueue(S("response.output_item.added",{type:"response.output_item.added",output_index:c,item:z}))}}if(H.type==="content_block_delta"){let I=H.delta;if(I?.type==="text_delta"){if(!h){h=!0,c=_++,a=`${i}_msg`;let z={id:a,type:"message",status:"in_progress",role:"assistant",content:[]};v.push(z),E.enqueue(S("response.output_item.added",{type:"response.output_item.added",output_index:c,item:z}))}l+=I.text||"",E.enqueue(S("response.output_text.delta",{type:"response.output_text.delta",item_id:a,output_index:c,content_index:0,delta:I.text||""}))}I?.type==="thinking_delta"&&(y+=I.thinking||"",E.enqueue(S("response.reasoning_summary_text.delta",{type:"response.reasoning_summary_text.delta",item_id:p||`rs_${i}`,output_index:f>=0?f:0,summary_index:0,delta:I.thinking||""}))),I?.type==="input_json_delta"&&(g+=I.partial_json||"",E.enqueue(S("response.function_call_arguments.delta",{type:"response.function_call_arguments.delta",item_id:u||"call_0",output_index:m>=0?m:0,delta:I.partial_json||""})))}if(H.type==="content_block_stop"){if(x==="tool_use"&&u){E.enqueue(S("response.function_call_arguments.done",{type:"response.function_call_arguments.done",item_id:u,output_index:m,arguments:g}));let I=v.find(z=>z.call_id===u);I&&(I.arguments=g,I.status="completed"),I&&R(m,I)}if(x==="text"&&h){E.enqueue(S("response.output_text.done",{type:"response.output_text.done",item_id:a,output_index:c,content_index:0,text:l}));let I=v.find(z=>z.type==="message");I&&(I.content=[{type:"output_text",text:l}],R(c,I))}if(x==="thinking"&&b){let I=v.find(z=>z.type==="reasoning");I&&(I.summary=[{type:"summary_text",text:y}],R(f,I))}x=null}if(H.type==="message_delta"){let I=O(H.usage);I&&E.enqueue(I)}if(H.type==="message_stop"){let I=O();I&&E.enqueue(I),E.enqueue(r.encode(`data: [DONE]
|
|
41
41
|
|
|
42
|
-
`))}}}P();let j=O();j&&E.enqueue(j),D="",E.close()}catch(N){E.error(N)}}})}wrapChatInResponses(e){let t=e?.choices?.[0],o=[],r=[];if(t?.message?.content&&r.push({type:"output_text",text:t.message.content}),o.push({type:"message",role:"assistant",content:r}),Array.isArray(t?.message?.tool_calls))for(let s of t.message.tool_calls)o.push({type:"function_call",id:s.id,call_id:s.id,name:s.function?.name||"",arguments:s.function?.arguments||"{}"});return{id:e.id||`resp_${Date.now()}`,object:"response",model:e.model,output:o,usage:e.usage?{...this.buildResponsesUsage(e.usage)}:void 0}}convertResponseToChat(e){let t=e.output?.find(c=>c.type==="message"),o=e.output?.find(c=>c.type==="function_call"),r;t?.content?.length&&t?.content[0].annotations&&(r=t.content[0].annotations.map(c=>({type:"url_citation",url_citation:{url:c.url||"",title:c.title||"",content:"",start_index:c.start_index||0,end_index:c.end_index||0}}))),this.logger.debug({data:r,type:"url_citation"});let s=null,i=null,l=null;if(t&&t.reasoning&&(l={content:t.reasoning}),t&&t.content){let c=[],u=[];if(t.content.forEach(d=>{if(d.type==="output_text")c.push(d.text||"");else if(d.type==="output_image"){let g=this.buildImageContent({url:d.image_url,mime_type:d.mime_type});g&&u.push(g)}else if(d.type==="output_image_base64"){let g=this.buildImageContent({b64_json:d.image_base64,mime_type:d.mime_type});g&&u.push(g)}}),u.length>0){let d=[];c.length>0&&d.push({type:"text",text:c.join("")}),d.push(...u),s=d}else s=c.join("")}return o&&(i=[{id:o.call_id||o.id,function:{name:o.name,arguments:o.arguments},type:"function"}]),{id:e.id||"chatcmpl-"+Date.now(),object:"chat.completion",created:e.created_at,model:e.model,choices:[{index:0,message:{role:"assistant",content:s||null,tool_calls:i,thinking:l,annotations:r},logprobs:null,finish_reason:i?"tool_calls":"stop"}],usage:e.usage?{prompt_tokens:e.usage.input_tokens||0,completion_tokens:e.usage.output_tokens||0,total_tokens:e.usage.total_tokens||0,prompt_tokens_details:{cached_tokens:this.getCacheReadInputTokens(e.usage),cache_creation_tokens:this.getCacheCreationInputTokens(e.usage)},cache_read_input_tokens:this.getCacheReadInputTokens(e.usage),cache_creation_input_tokens:this.getCacheCreationInputTokens(e.usage)}:null}}buildImageContent(e){return e&&(e.url||e.b64_json)?{type:"image_url",image_url:{url:e.url||"",b64_json:e.b64_json},media_type:e.mime_type}:null}}});var Xn,V,Rt=w(()=>{"use strict";Xn=class{capacity;cache;constructor(e){this.capacity=e,this.cache=new Map}get(e){if(!this.cache.has(e))return;let t=this.cache.get(e);return this.cache.delete(e),this.cache.set(e,t),t}put(e,t){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.capacity){let o=this.cache.keys().next().value;o!==void 0&&this.cache.delete(o)}this.cache.set(e,t)}values(){return Array.from(this.cache.values())}delete(e){return this.cache.delete(e)}},V=new Xn(100)});import{existsSync as Ur,mkdirSync as $a,readFileSync as Na,writeFileSync as La}from"fs";import{join as jr}from"path";import{HOME_DIR as Da}from"@wengine-ai/claude-code-router-shared";function eo(n,e){n&&Se.set(n,{...e,provider:n,capturedAt:Date.now()})}function wt(n){let e=Se.get(n);return e?{...e}:void 0}function to(){return Array.from(Se.values()).map(n=>({...n}))}function Fa(){try{if(!Ur(Zn))return;let n=JSON.parse(Na(Zn,"utf-8"));if(!Array.isArray(n))return;let e=Date.now();for(let t of n)if(t&&t.provider){if(t.capturedAt&&e-t.capturedAt>1440*60*1e3)continue;Se.set(t.provider,t)}}catch{}}function Fr(){try{if(Se.size===0)return;Ur(qn)||$a(qn,{recursive:!0}),La(Zn,JSON.stringify(Array.from(Se.values()),null,2),"utf-8")}catch{}}function Ke(){Lr||(Lr=!0,Fa(),Dr=setInterval(Fr,6e4),Dr.unref?.(),process.on("exit",Fr))}var qn,Zn,Se,Lr,Dr,Re=w(()=>{"use strict";qn=jr(Da,"runtime"),Zn=jr(qn,"quota-store.json"),Se=new Map,Lr=!1,Dr=null});function we(n){if(typeof n!="string")return;let e=n.trim();if(!(!e||!Ua.test(e)))return e}function Qe(n){if(!n)return;if(typeof n=="object")return we(n.session_id??n.sessionId);if(typeof n!="string")return;let e=n.trim();if(!e)return;try{let r=JSON.parse(e),s=we(r?.session_id??r?.sessionId);if(s)return s}catch{}let t="_session_",o=e.lastIndexOf(t);if(o!==-1)return we(e.slice(o+t.length))}var Ua,Ve=w(()=>{"use strict";Ua=/^[A-Za-z0-9_-]+$/});import{randomUUID as ja}from"node:crypto";function za(n){if(typeof n=="string")return n.slice(0,1e3);if(Array.isArray(n)){let e=n.find(t=>t&&typeof t.text=="string");return e?String(e.text).slice(0,1e3):""}return""}function Ba(n){if(typeof n?.pathname=="string")return n.pathname;if(typeof n?.url!="string")return"";try{return new URL(n.url,"http://127.0.0.1").pathname}catch{return n.url}}function Ye(n,e=!0){return{clientType:n,usageScope:"request",supportsExplicitExtendedContext:e}}function Hr(n,e,t=!0){let o=Qe(n?.body?.metadata?.user_id);return{clientType:e,usageScope:o?"session":"request",stableSessionId:o,supportsExplicitExtendedContext:t}}function Br(n){return typeof n=="string"&&Ha.includes(n)}function Pe(n){if(Br(n?.clientType))return n.clientType;let e=Ba(n),t=n?.headers||{},o=typeof t["user-agent"]=="string"?t["user-agent"]:"",r=n?.body||{},s=za(r.system);if(/\bYou are Qwen Code\b/i.test(s)||/Qwen Code, an interactive CLI agent/i.test(s))return"qwen-code";if(/operating inside pi\b/i.test(s)||/a coding agent harness/i.test(s))return"pi";if(/\bYou are opencode\b/i.test(s))return"opencode";let i=t["x-anthropic-billing-header"];if(typeof i=="string"&&i.includes("cc_version="))return"claude-code";if(o.includes("codex")||o.includes("Codex")||e.endsWith("/v1/responses"))return"codex";if(r.metadata&&typeof r.metadata=="object"&&typeof r.metadata.user_id=="string")return"claude-code";if(o.includes("opencode"))return"opencode";if(o.includes("pi-coding-agent"))return"pi";if(o.includes("QwenCode"))return"qwen-code";let l=n?.originalModel||r.model||"";return/^ccr-(opus|sonnet|haiku)(\[1m\])?$/i.test(l)?o.includes("Anthropic/")?"pi":o.includes("claude-cli")||o.includes("Claude-CLI")?"qwen-code":typeof t["x-stainless-package-version"]=="string"?"pi":"claude-code":o.includes("claude-cli")||o.includes("Claude-CLI")?"claude-code":String(l).toLowerCase()==="ccr-codex"?"codex":e.endsWith("/v1/messages")?"api":"unknown"}function Jr(n){return zr[n]}function Xa(n){if(typeof n?.__ccrRequestScopeId=="string"&&n.__ccrRequestScopeId)return n.__ccrRequestScopeId;let e=typeof n?.id=="string"&&n.id||ja();return n.__ccrRequestScopeId=e,e}function ge(n,e={}){let t=Pe(n),o=Jr(t).createContext(n,e),r=o.stableSessionId||Xa(n),s=o.usageScope==="session"?"session":"request";return n.clientType=t,n.clientContext=o,o.stableSessionId?n.sessionId=o.stableSessionId:delete n.sessionId,n.usageSessionId=r,n.usageCacheKey=`${t}:${s}:${r}`,o}function qa(){}var Ha,Ja,Wa,Ga,Ka,Qa,Va,Ya,zr,Ee=w(()=>{"use strict";Ve();Ha=["claude-code","pi","qwen-code","opencode","codex","api","unknown"];Ja={type:"claude-code",createContext(n){return Hr(n,"claude-code")}},Wa={type:"pi",createContext(){return Ye("pi",!1)}},Ga={type:"qwen-code",createContext(n){return Hr(n,"qwen-code")}},Ka={type:"opencode",createContext(){return Ye("opencode")}},Qa={type:"codex",createContext(){return Ye("codex")}},Va={type:"api",createContext(){return Ye("api")}},Ya={type:"unknown",createContext(){return Ye("unknown")}},zr={"claude-code":Ja,pi:Wa,"qwen-code":Ga,opencode:Ka,codex:Qa,api:Va,unknown:Ya}});import{get_encoding as Za}from"tiktoken";import{readFile as no}from"fs/promises";import{opendir as ec,stat as tc}from"fs/promises";import{join as oo}from"path";import{CLAUDE_PROJECTS_DIR as Wr,HOME_DIR as Gr}from"@wengine-ai/claude-code-router-shared";function Y(n,e,t,o){let r=Xr(e,t),s=n.sessionId||n.clientContext?.stableSessionId,i=Yr[r.code]||502;throw new ae(`Project routing error (${o}): ${r.reason}. Project-level Router target: "${e}". Session: "${s||"unknown"}".`,{sessionId:s,configuredTarget:e,code:r.code,statusCode:i})}function Et(n){let e=n||"";return e.includes(",")&&(e=e.split(",").pop()||e),e.includes("/")&&(e=e.split("/").pop()||e),e.includes(":")&&(e=e.split(":")[0]),e.trim().toLowerCase()}function qe(n){let e=Et(n),t=e.includes("[1m]")||e.endsWith("[1m"),o=e.replace(/\[1m\]|\[1m$/g,""),r=o.match(/^ccr-(opus|sonnet|haiku)$/i);if(r)return{family:r[1].toLowerCase(),extended:t,isCcrAlias:!0};let s=o.match(/claude-(?:\d+-\d+-|\d+-)?(sonnet|opus|haiku)(?:-|$)/i)||o.match(/claude-(sonnet|opus|haiku)(?:-|$)/i);return s?{family:s[1].toLowerCase(),extended:t,isCcrAlias:!1}:{family:null,extended:t,isCcrAlias:!1}}function oc(n,e){if(!e||!n)return null;let t=Et(n);if(e[n])return e[n];if(e[t])return e[t];let{family:o}=qe(n);if(o&&e[o])return e[o];for(let[r,s]of Object.entries(e)){let i=Et(r);if(i&&t.includes(i))return s}return null}function rc(n){return n?(n.input_tokens||0)+(n.cache_read_input_tokens||0)+(n.cache_creation_input_tokens||0):0}function Pt(n){if(!n?.includes(","))return null;let[e,...t]=n.split(","),o=e.trim(),r=t.join(",").trim();return!o||!r?null:{providerName:o,routeModel:r}}function Xe(n,e,t){let o=n.find(s=>s.name.toLowerCase()===e.toLowerCase());if(!o||o.enabled===!1)return null;let r=o.models?.find(s=>String(s).toLowerCase()===t.toLowerCase());return r?{provider:o,model:String(r)}:null}function Xr(n,e){let t=Pt(n);if(!t)return{reason:`invalid model format "${n}" (expected "provider,model")`,code:"invalid_model_format"};let{providerName:o,routeModel:r}=t,s=e.find(c=>c.name?.toLowerCase()===o.toLowerCase());if(!s)return{reason:`provider "${o}" not found`,code:"provider_not_found"};if(s.enabled===!1)return{reason:`provider "${o}" is disabled`,code:"provider_disabled"};let i=s.models?.find(c=>String(c).toLowerCase()===r.toLowerCase());if(!i)return{reason:`model "${r}" not found in provider "${o}"`,code:"model_not_found"};if(!F().isAvailable(s.name,String(i)))return{reason:`model "${r}" in provider "${o}" is temporarily unavailable (health fail-pool)`,code:"model_unhealthy"};let a=wt(s.name);if(a){let c=a.limitDaily!==void 0&&a.usedDailyBalance!==void 0&&a.usedDailyBalance>=a.limitDaily,u=a.totalBalance!==void 0&&a.usedBalance!==void 0&&a.usedBalance>=a.totalBalance;if(c||u)return{reason:`provider "${o}" quota is exhausted`,code:"quota_exhausted"}}return{reason:`unable to resolve model "${n}"`,code:"resolution_failed"}}function G(n,e,t,o,r,s,i){let l=Pt(n);if(!l)return i?null:n;let{providerName:a,routeModel:c}=l,u=Xe(e,a,c);if(!u){if(r===!0&&o&&!t&&s!==!1){let g=Te(),m=g.getPromotion(a,c,o,e);if(m){let y=Pt(m);if(y){let p=Xe(e,y.providerName,y.routeModel);if(p)return`${p.provider.name},${p.model}`}g.clear(a,c,o)}}return null}if(r===!0&&o&&!t&&s!==!1){let g=Te(),m=g.getPromotion(a,c,o,e);if(m){let y=Pt(m);if(y){let p=Xe(e,y.providerName,y.routeModel);if(p)return`${p.provider.name},${p.model}`}g.clear(a,c,o)}}if(!t&&!F().isAvailable(u.provider.name,u.model))return null;let d=wt(u.provider.name);if(d){let g=d.limitDaily!==void 0&&d.usedDailyBalance!==void 0&&d.usedDailyBalance>=d.limitDaily,m=d.totalBalance!==void 0&&d.usedBalance!==void 0&&d.usedBalance>=d.totalBalance;if(g||m)return null}return`${u.provider.name},${u.model}`}function K(n,e,t,o,r,s){let i=F(),l=[t?.[n],o?.[n]];for(let a of l)if(!(!Array.isArray(a)||a.length===0))for(let c of a){let u=G(c,e,!1,n,void 0,void 0,s);if(u)return u}return null}function sc(n){return n.body.messages?.some(e=>e.role==="user"&&Array.isArray(e.content)&&e.content.some(t=>t.type==="image"||t.type==="image_url"||Array.isArray(t?.content)&&t.content.some(o=>o.type==="image"||o.type==="image_url")))}function ro(n){let e=Et(n);return[/claude/i,/gemini/i,/gpt-4o/i,/gpt-4\.1/i,/gpt-4-vision/i,/qwen.*vl/i,/glm-4v/i,/grok.*vision/i,/pixtral/i,/llava/i].some(o=>o.test(e))}function qr(n,e,t){return t?.usageScope!=="session"?n:Math.max(n,rc(e))}function Zr(n,e,t){return n?.extendedContextThreshold??e?.extendedContextThreshold??t??2e5}function ic(n,e,t,o,r,s,i,l,a,c,u,d){let g=n.clientContext,m=g?.longContextThreshold??t.longContextThreshold??a??6e4,y=qr(e,r,g),p=n.modelFamily,f=Zr(g,t,c),_=g?.supportsExplicitExtendedContext!==!1&&s===!0;if((_||y>f)&&t.extendedContext){let b=G(t.extendedContext,o,!1,"extendedContext",l,d,u);if(b)return n.log.info(`Family: using extended context model (1M+), tokens: ${y}, estimated: ${e}, explicit: ${_}, threshold: ${f}`),{model:b,scenarioType:"extendedContext",isFallback:!1};let T=l?K("extendedContext",o,t.fallback,i,p,u):null;if(T)return n.log.info(`Family: using extended context fallback model (1M+), tokens: ${y}, estimated: ${e}, explicit: ${_}, threshold: ${f}`),{model:T,scenarioType:"extendedContext",isFallback:!0};u&&Y(n,t.extendedContext,o,"extendedContext"),n.log.warn("Family: extendedContext model unavailable (fail pool), skipping")}if(y>m&&(t.longContext||t.fallback?.longContext?.length||i?.longContext?.length)){let b=t.longContext?G(t.longContext,o,!1,"longContext",l,d,u):null;if(b)return n.log.info(`Family: using long context model, tokens: ${y}, estimated: ${e}`),{model:b,scenarioType:"longContext",isFallback:!1};let T=l?K("longContext",o,t.fallback,i,p,u):null;if(T)return n.log.info(`Family: using long context fallback model, tokens: ${y}, estimated: ${e}`),{model:T,scenarioType:"longContext",isFallback:!0};u&&t.longContext&&Y(n,t.longContext,o,"longContext"),n.log.warn("Family: no healthy longContext model available, falling through to other scenarios")}if(Array.isArray(n.body.tools)&&n.body.tools.some(b=>b.type?.startsWith("web_search"))&&t.webSearch){let b=G(t.webSearch,o,!1,"webSearch",l,d,u);if(b)return{model:b,scenarioType:"webSearch",isFallback:!1};let T=l?K("webSearch",o,t.fallback,i,p,u):null;if(T)return n.log.info("Family: using webSearch fallback model"),{model:T,scenarioType:"webSearch",isFallback:!0};u&&Y(n,t.webSearch,o,"webSearch"),n.log.warn("Family: webSearch model unavailable (fail pool), skipping")}if(n.body.thinking?.type==="enabled"&&t.think){let b=G(t.think,o,!1,"think",l,d,u);if(b)return{model:b,scenarioType:"think",isFallback:!1};let T=l?K("think",o,t.fallback,i,p,u):null;if(T)return n.log.info("Family: using think fallback model"),{model:T,scenarioType:"think",isFallback:!0};u&&Y(n,t.think,o,"think"),n.log.warn("Family: think model unavailable (fail pool), skipping")}if(t.default){let b=G(t.default,o,!1,"default",l,d,u);if(b)return{model:b,scenarioType:"default",isFallback:!1};let T=l?K("default",o,t.fallback,i,p,u):null;if(T)return n.log.info("Family: using default fallback model"),{model:T,scenarioType:"default",isFallback:!0};u&&Y(n,t.default,o,"default"),n.log.warn("Family: default model unavailable (fail pool), skipping")}return null}function dc(){if(he.size<=Kr)return;let n=[...he.keys()].slice(0,he.size-Kr);for(let e of n)he.delete(e)}function pc(){if(Oe.size<=Qr)return;let n=[...Oe].slice(0,Oe.size-Qr);for(let e of n)Oe.delete(e)}var Yr,ae,ie,Ot,nc,ac,At,he,Kr,Oe,Qr,cc,lc,uc,Vr,es,Ae=w(()=>{"use strict";Rt();ee();Re();xt();Ve();Ee();Yr={provider_not_found:404,model_not_found:404,invalid_model_format:400,provider_disabled:503,model_unhealthy:503,quota_exhausted:503,resolution_failed:502,project_config_error:500},ae=class extends Error{statusCode;code;type;sessionId;configuredTarget;constructor(e,t){super(e),this.name="ProjectRoutingError",this.statusCode=t?.statusCode||Yr[t?.code||""]||502,this.code=t?.code||"project_routing_error",this.type="api_error",this.sessionId=t?.sessionId,this.configuredTarget=t?.configuredTarget}};ie=Za("cl100k_base"),Ot=(n,e,t)=>{let o=0;return Array.isArray(n)&&n.forEach(r=>{typeof r.content=="string"?o+=ie.encode(r.content).length:Array.isArray(r.content)&&r.content.forEach(s=>{s.type==="text"?o+=ie.encode(s.text).length:s.type==="tool_use"?o+=ie.encode(JSON.stringify(s.input)).length:s.type==="tool_result"&&(o+=ie.encode(typeof s.content=="string"?s.content:JSON.stringify(s.content)).length)})}),typeof e=="string"?o+=ie.encode(e).length:Array.isArray(e)&&e.forEach(r=>{r.type==="text"&&(typeof r.text=="string"?o+=ie.encode(r.text).length:Array.isArray(r.text)&&r.text.forEach(s=>{o+=ie.encode(s||"").length}))}),t&&t.forEach(r=>{r.description&&(o+=ie.encode(r.name+r.description).length),r.input_schema&&(o+=ie.encode(JSON.stringify(r.input_schema)).length)}),o},nc=async(n,e)=>{if(n.sessionId){let t=await es(n.sessionId);if(t){let o=oo(Gr,t,"config.json"),r=oo(Gr,t,`${n.sessionId}.json`);try{let s=JSON.parse(await no(r,"utf8"));if(s&&s.Router&&Object.keys(s.Router).length>0)return s.Router}catch{}try{let s=JSON.parse(await no(o,"utf8"));if(s&&s.Router&&Object.keys(s.Router).length>0)return s.Router}catch(s){if(s&&s.code!=="ENOENT"){let i=n.sessionId||n.clientContext?.stableSessionId;throw new ae(`Project routing error: project config.json is malformed or unreadable in project "${t}". ${s.message}. Session: "${i||"unknown"}".`,{sessionId:i,configuredTarget:o,code:"project_config_error",statusCode:500})}}}}};ac=async(n,e,t,o,r,s)=>{let i=t.get("providers")||[],l=r||t.get("Router"),a=l?.enableFallback===!0,c=a?l?.fallback:void 0,u=a&&!s?c||t.get("fallback"):c,d=!s,g=null;if(n.body?.system?.length>1&&n.body?.system[1]?.text?.includes("<CCR-SUBAGENT-MODEL>")){let v=n.body?.system[1].text.match(/<CCR-SUBAGENT-MODEL>(.*?)<\/CCR-SUBAGENT-MODEL>/s);v&&(n.body.system[1].text=n.body.system[1].text.replace(`<CCR-SUBAGENT-MODEL>${v[1]}</CCR-SUBAGENT-MODEL>`,""),g=v[1])}let{family:m,extended:y,isCcrAlias:p}=qe(n.body.model),f=l?.families?.[m||""];if(f&&l?.enableFamilyRouting){n.log.info(`Using model family routing for: ${m}${y?" (1M)":""}`),n.modelFamily=m,n.familyFallback=f.fallback;let v=ic(n,e,f,i,o,y,u,a,l?.longContextThreshold,l?.extendedContextThreshold,s,d);if(v)return{model:v.model,scenarioType:v.scenarioType}}if(n.body.model.includes(",")&&!s){let v=G(n.body.model,i,!1,"default",a,d,s);if(v)return{model:v,scenarioType:"default"};n.log.warn(`Explicit model ${n.body.model} unavailable (fail pool), trying fallback`);let S=a?K("default",i,void 0,u,void 0,s):null;if(S)return n.log.info(`Using fallback for explicit model: ${S}`),{model:S,scenarioType:"default"};n.log.warn(`No fallback available for explicit model ${n.body.model}, continuing through routing logic`)}let _=p&&!l?.enableFamilyRouting?null:oc(n.body.model,l?.models);if(_){let v=G(_,i,!1,"modelMapping",a,d,s);if(v)return n.log.info(`Using mapped model for ${n.body.model}: ${_}`),{model:v,scenarioType:"modelMapping"};let S=a?K("modelMapping",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"modelMapping"};s&&Y(n,_,i,"modelMapping"),n.log.warn(`Mapped model ${_} unavailable (fail pool), skipping`)}let k=n.clientContext,h=qr(e,o,k),b=Zr(k,void 0,l?.extendedContextThreshold);if(h>b&&l?.extendedContext){n.log.info(`Using extended context (1M) model due to token count: ${h}, estimated: ${e}, threshold: ${b}`);let v=G(l.extendedContext,i,!1,"extendedContext",a,d,s);if(v)return{model:v,scenarioType:"extendedContext"};n.log.warn(`Extended context model ${l.extendedContext} unavailable (fail pool), trying fallback`);let S=a?K("extendedContext",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"extendedContext"};s&&Y(n,l.extendedContext,i,"extendedContext")}let T=k?.longContextThreshold??l?.longContextThreshold??6e4;if(h>T&&l?.longContext){n.log.info(`Using long context model due to token count: ${h}, estimated: ${e}, threshold: ${T}`);let v=G(l.longContext,i,!1,"longContext",a,d,s);if(v)return{model:v,scenarioType:"longContext"};n.log.warn(`Long context model ${l.longContext} unavailable (fail pool), trying fallback`);let S=a?K("longContext",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"longContext"};s&&Y(n,l.longContext,i,"longContext")}if(!s&&g)return{model:g,scenarioType:"default"};if(n.body.model?.includes("claude")&&n.body.model?.includes("haiku")&&l?.background){n.log.info(`Using background model for ${n.body.model}`);let v=G(l.background,i,!1,"background",a,d,s);if(v)return{model:v,scenarioType:"background"};let S=a?K("background",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"background"};s&&Y(n,l.background,i,"background"),n.log.warn(`Background model ${l.background} unavailable (fail pool), falling through`)}if(Array.isArray(n.body.tools)&&n.body.tools.some(v=>v.type?.startsWith("web_search"))&&l?.webSearch){let v=G(l.webSearch,i,!1,"webSearch",a,d,s);if(v)return{model:v,scenarioType:"webSearch"};n.log.warn(`WebSearch model ${l.webSearch} unavailable (fail pool), trying fallback`);let S=a?K("webSearch",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"webSearch"};s&&Y(n,l.webSearch,i,"webSearch")}if(n.body.thinking?.type==="enabled"&&l?.think){n.log.info(`Using think model for ${n.body.thinking}`);let v=G(l.think,i,!1,"think",a,d,s);if(v)return{model:v,scenarioType:"think"};n.log.warn(`Think model ${l.think} unavailable (fail pool), trying fallback`);let S=a?K("think",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"think"};s&&Y(n,l.think,i,"think")}if(l?.default){let v=G(l.default,i,!1,"default",a,d,s);if(v)return{model:v,scenarioType:"default"};n.log.warn(`Default model ${l.default} unavailable (fail pool), trying fallback`);let S=a?K("default",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"default"};if(!s){let C=G(l.default,i,!0,"default",a,d,s);if(C)return n.log.warn(`No fallback available; retrying default model ${l.default} despite fail-pool state`),{model:C,scenarioType:"default"}}}return s&&Y(n,l?.default||n.body.model,i,"default"),{model:void 0,scenarioType:"default"}},At=async(n,e,t)=>{let{configService:o,event:r}=t;!n.originalModel&&n.body.model&&(n.originalModel=n.body.model),ge(n,o.getAll());let s=await nc(n,o),i=s||o.get("Router"),l=i?.enableFallback===!0,a=o.get("providers")||[],c=!!s;n.enableFallback=l,n.strictProjectRouting=c,n.fallbackConfig=c?i?.fallback:i?.fallback||o.get("fallback");let u=n.clientContext?.usageScope==="session"?n.previousUsage??V.get(n.usageCacheKey):void 0,{messages:d,system:g=[],tools:m}=n.body,y=o.get("REWRITE_SYSTEM_PROMPT");if(y&&g.length>1&&g[1]?.text?.includes("<env>")){let p=await no(y,"utf-8");g[1].text=`${p}<env>${g[1].text.split("<env>").pop()}`}try{let[p,f]=n.body.model.split(","),_=t.tokenizerService?.getTokenizerConfigForModel(p,f),k;t.tokenizerService?k=(await t.tokenizerService.countTokens({messages:d,system:g,tools:m},_,p)).tokenCount:k=Ot(d,g,m),n.tokenCount=k;let h,b=c?void 0:o.get("CUSTOM_ROUTER_PATH");if(b)try{h=await Be(b)(n,o.getAll(),{event:r})}catch(S){n.log.error(`failed to load custom router: ${S.message}`)}if(h)n.scenarioType="default";else{let S=await ac(n,k,o,u,s,!!s);h=S.model,n.scenarioType=S.scenarioType}let{family:T}=qe(n.originalModel||n.body.model),x=i?.enableFamilyRouting&&T?i.families?.[T]:void 0,v=[x?.image,i?.image].filter((S,C,P)=>!!S&&P.indexOf(S)===C);if(v.length>0&&sc(n)&&!ro(h))if(v.includes(h))n.scenarioType="image";else{let S=v.map(C=>G(C,a,!1,"image",l,!c,c)).find(C=>!!C);if(S)n.log.info(`Using image model fallback for ${h}`),h=S,n.scenarioType="image";else{let C=l?K("image",a,x?.fallback,n.fallbackConfig,T||void 0,c):null;C?(n.log.info(`Using image fallback model: ${C}`),h=C,n.scenarioType="image"):c?Y(n,v[0],a,"image"):(n.log.warn(`Image models ${v.join(", ")} unavailable (fail pool), keeping ${h}`),n.scenarioType="image")}}typeof h=="string"&&h.trim()?n.body.model=h:(n.log.warn(`Router could not resolve a valid model for ${n.originalModel||n.body.model}; keeping original request model`),n.scenarioType=n.scenarioType||"default")}catch(p){if(p instanceof ae)throw p;if(n.log.error(`Error in router middleware: ${p.message}`),c){let f=n.sessionId||n.clientContext?.stableSessionId;throw new ae(`Project routing error: router failure in project mode. ${p.message}. Session: "${f||"unknown"}".`,{sessionId:f,configuredTarget:i?.default,code:"project_router_failure",statusCode:502})}n.body.model=i?.default,n.scenarioType="default"}},he=new Map,Kr=1e3,Oe=new Set,Qr=1e3,cc=3,lc=50,uc=n=>new Promise(e=>setTimeout(e,n));Vr=async n=>{let e=await ec(Wr),t=[];for await(let s of e)s.isDirectory()&&t.push(s.name);let o=t.map(async s=>{let i=oo(Wr,s,`${n}.jsonl`);try{return(await tc(i)).isFile()?s:null}catch{return null}}),r=await Promise.all(o);for(let s of r)if(s)return s;return null},es=async n=>{let e=we(n);if(!e)return null;if(he.has(e))return he.get(e)||null;try{let t=await Vr(e);if(!t&&!Oe.has(e)){Oe.add(e),pc();for(let o=0;o<cc&&!t;o++)await uc(lc),t=await Vr(e)}return t?(he.set(e,t),dc(),t):null}catch(t){return console.error("Error searching for project by session:",t),null}}});function Ze(n){let e=[],t=Array.isArray(n.input)?n.input:[n.input];for(let o of t)if(o.type==="function_call")e.push({role:"assistant",tool_calls:[{id:o.call_id,type:"function",function:{name:o.name,arguments:o.arguments||"{}"}}]});else if(o.type==="function_call_output")e.push({role:"tool",tool_call_id:o.call_id,content:typeof o.output=="string"?o.output:JSON.stringify(o.output)});else if(o.type==="reasoning"){let r=Array.isArray(o.summary)?o.summary.filter(s=>s.type==="summary_text"&&s.text).map(s=>s.text).join(`
|
|
42
|
+
`))}}}P();let j=O();j&&E.enqueue(j),D="",E.close()}catch(N){E.error(N)}}})}wrapChatInResponses(e){let t=e?.choices?.[0],o=[],r=[];if(t?.message?.content&&r.push({type:"output_text",text:t.message.content}),o.push({type:"message",role:"assistant",content:r}),Array.isArray(t?.message?.tool_calls))for(let s of t.message.tool_calls)o.push({type:"function_call",id:s.id,call_id:s.id,name:s.function?.name||"",arguments:s.function?.arguments||"{}"});return{id:e.id||`resp_${Date.now()}`,object:"response",model:e.model,output:o,usage:e.usage?{...this.buildResponsesUsage(e.usage)}:void 0}}convertResponseToChat(e){let t=e.output?.find(c=>c.type==="message"),o=e.output?.find(c=>c.type==="function_call"),r;t?.content?.length&&t?.content[0].annotations&&(r=t.content[0].annotations.map(c=>({type:"url_citation",url_citation:{url:c.url||"",title:c.title||"",content:"",start_index:c.start_index||0,end_index:c.end_index||0}}))),this.logger.debug({data:r,type:"url_citation"});let s=null,i=null,l=null;if(t&&t.reasoning&&(l={content:t.reasoning}),t&&t.content){let c=[],u=[];if(t.content.forEach(d=>{if(d.type==="output_text")c.push(d.text||"");else if(d.type==="output_image"){let g=this.buildImageContent({url:d.image_url,mime_type:d.mime_type});g&&u.push(g)}else if(d.type==="output_image_base64"){let g=this.buildImageContent({b64_json:d.image_base64,mime_type:d.mime_type});g&&u.push(g)}}),u.length>0){let d=[];c.length>0&&d.push({type:"text",text:c.join("")}),d.push(...u),s=d}else s=c.join("")}return o&&(i=[{id:o.call_id||o.id,function:{name:o.name,arguments:o.arguments},type:"function"}]),{id:e.id||"chatcmpl-"+Date.now(),object:"chat.completion",created:e.created_at,model:e.model,choices:[{index:0,message:{role:"assistant",content:s||null,tool_calls:i,thinking:l,annotations:r},logprobs:null,finish_reason:i?"tool_calls":"stop"}],usage:e.usage?{prompt_tokens:e.usage.input_tokens||0,completion_tokens:e.usage.output_tokens||0,total_tokens:e.usage.total_tokens||0,prompt_tokens_details:{cached_tokens:this.getCacheReadInputTokens(e.usage),cache_creation_tokens:this.getCacheCreationInputTokens(e.usage)},cache_read_input_tokens:this.getCacheReadInputTokens(e.usage),cache_creation_input_tokens:this.getCacheCreationInputTokens(e.usage)}:null}}buildImageContent(e){return e&&(e.url||e.b64_json)?{type:"image_url",image_url:{url:e.url||"",b64_json:e.b64_json},media_type:e.mime_type}:null}}});var Xn,V,Rt=w(()=>{"use strict";Xn=class{capacity;cache;constructor(e){this.capacity=e,this.cache=new Map}get(e){if(!this.cache.has(e))return;let t=this.cache.get(e);return this.cache.delete(e),this.cache.set(e,t),t}put(e,t){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.capacity){let o=this.cache.keys().next().value;o!==void 0&&this.cache.delete(o)}this.cache.set(e,t)}values(){return Array.from(this.cache.values())}delete(e){return this.cache.delete(e)}},V=new Xn(100)});import{existsSync as Ur,mkdirSync as $a,readFileSync as Na,writeFileSync as La}from"fs";import{join as jr}from"path";import{HOME_DIR as Da}from"@wengine-ai/claude-code-router-shared";function eo(n,e){n&&Se.set(n,{...e,provider:n,capturedAt:Date.now()})}function wt(n){let e=Se.get(n);return e?{...e}:void 0}function to(){return Array.from(Se.values()).map(n=>({...n}))}function Fa(){try{if(!Ur(Zn))return;let n=JSON.parse(Na(Zn,"utf-8"));if(!Array.isArray(n))return;let e=Date.now();for(let t of n)if(t&&t.provider){if(t.capturedAt&&e-t.capturedAt>1440*60*1e3)continue;Se.set(t.provider,t)}}catch{}}function Fr(){try{if(Se.size===0)return;Ur(qn)||$a(qn,{recursive:!0}),La(Zn,JSON.stringify(Array.from(Se.values()),null,2),"utf-8")}catch{}}function Ke(){Lr||(Lr=!0,Fa(),Dr=setInterval(Fr,6e4),Dr.unref?.(),process.on("exit",Fr))}var qn,Zn,Se,Lr,Dr,Re=w(()=>{"use strict";qn=jr(Da,"runtime"),Zn=jr(qn,"quota-store.json"),Se=new Map,Lr=!1,Dr=null});function we(n){if(typeof n!="string")return;let e=n.trim();if(!(!e||!Ua.test(e)))return e}function Qe(n){if(!n)return;if(typeof n=="object")return we(n.session_id??n.sessionId);if(typeof n!="string")return;let e=n.trim();if(!e)return;try{let r=JSON.parse(e),s=we(r?.session_id??r?.sessionId);if(s)return s}catch{}let t="_session_",o=e.lastIndexOf(t);if(o!==-1)return we(e.slice(o+t.length))}var Ua,Ve=w(()=>{"use strict";Ua=/^[A-Za-z0-9_-]+$/});import{randomUUID as ja}from"node:crypto";function za(n){if(typeof n=="string")return n.slice(0,1e3);if(Array.isArray(n)){let e=n.find(t=>t&&typeof t.text=="string");return e?String(e.text).slice(0,1e3):""}return""}function Ba(n){if(typeof n?.pathname=="string")return n.pathname;if(typeof n?.url!="string")return"";try{return new URL(n.url,"http://127.0.0.1").pathname}catch{return n.url}}function Ye(n,e=!0){return{clientType:n,usageScope:"request",supportsExplicitExtendedContext:e}}function Hr(n,e,t=!0){let o=Qe(n?.body?.metadata?.user_id);return{clientType:e,usageScope:o?"session":"request",stableSessionId:o,supportsExplicitExtendedContext:t}}function Br(n){return typeof n=="string"&&Ha.includes(n)}function Pe(n){if(Br(n?.clientType))return n.clientType;let e=Ba(n),t=n?.headers||{},o=typeof t["user-agent"]=="string"?t["user-agent"]:"",r=n?.body||{},s=za(r.system);if(/\bYou are Qwen Code\b/i.test(s)||/Qwen Code, an interactive CLI agent/i.test(s))return"qwen-code";if(/operating inside pi\b/i.test(s)||/a coding agent harness/i.test(s))return"pi";if(/\bYou are opencode\b/i.test(s))return"opencode";let i=t["x-anthropic-billing-header"];if(typeof i=="string"&&i.includes("cc_version="))return"claude-code";if(o.includes("codex")||o.includes("Codex")||e.endsWith("/v1/responses"))return"codex";if(r.metadata&&typeof r.metadata=="object"&&typeof r.metadata.user_id=="string")return"claude-code";if(o.includes("opencode"))return"opencode";if(o.includes("pi-coding-agent"))return"pi";if(o.includes("QwenCode"))return"qwen-code";let l=n?.originalModel||r.model||"";return/^ccr-(opus|sonnet|haiku)(\[1m\])?$/i.test(l)?o.includes("Anthropic/")?"pi":o.includes("claude-cli")||o.includes("Claude-CLI")?"qwen-code":typeof t["x-stainless-package-version"]=="string"?"pi":"claude-code":o.includes("claude-cli")||o.includes("Claude-CLI")?"claude-code":String(l).toLowerCase()==="ccr-codex"?"codex":e.endsWith("/v1/messages")?"api":"unknown"}function Jr(n){return zr[n]}function Xa(n){if(typeof n?.__ccrRequestScopeId=="string"&&n.__ccrRequestScopeId)return n.__ccrRequestScopeId;let e=typeof n?.id=="string"&&n.id||ja();return n.__ccrRequestScopeId=e,e}function ge(n,e={}){let t=Pe(n),o=Jr(t).createContext(n,e),r=o.stableSessionId||Xa(n),s=o.usageScope==="session"?"session":"request";return n.clientType=t,n.clientContext=o,o.stableSessionId?n.sessionId=o.stableSessionId:delete n.sessionId,n.usageSessionId=r,n.usageCacheKey=`${t}:${s}:${r}`,o}function qa(){}var Ha,Ja,Wa,Ga,Ka,Qa,Va,Ya,zr,Ee=w(()=>{"use strict";Ve();Ha=["claude-code","pi","qwen-code","opencode","codex","api","unknown"];Ja={type:"claude-code",createContext(n){return Hr(n,"claude-code")}},Wa={type:"pi",createContext(){return Ye("pi",!1)}},Ga={type:"qwen-code",createContext(n){return Hr(n,"qwen-code")}},Ka={type:"opencode",createContext(){return Ye("opencode")}},Qa={type:"codex",createContext(){return Ye("codex")}},Va={type:"api",createContext(){return Ye("api")}},Ya={type:"unknown",createContext(){return Ye("unknown")}},zr={"claude-code":Ja,pi:Wa,"qwen-code":Ga,opencode:Ka,codex:Qa,api:Va,unknown:Ya}});import{get_encoding as Za}from"tiktoken";import{readFile as no}from"fs/promises";import{opendir as ec,stat as tc}from"fs/promises";import{join as oo}from"path";import{CLAUDE_PROJECTS_DIR as Wr,HOME_DIR as Gr}from"@wengine-ai/claude-code-router-shared";function Y(n,e,t,o){let r=Xr(e,t);if(r.code==="model_unhealthy"){let l=G(e,t,!0);if(l)return n.log.warn(`Strict project target ${e} is in the health fail-pool; retrying it anyway (no fallback available). scenario=${o}`),l}let s=n.sessionId||n.clientContext?.stableSessionId,i=Yr[r.code]||502;throw new ae(`Project routing error (${o}): ${r.reason}. Project-level Router target: "${e}". Session: "${s||"unknown"}".`,{sessionId:s,configuredTarget:e,code:r.code,statusCode:i})}function Et(n){let e=n||"";return e.includes(",")&&(e=e.split(",").pop()||e),e.includes("/")&&(e=e.split("/").pop()||e),e.includes(":")&&(e=e.split(":")[0]),e.trim().toLowerCase()}function qe(n){let e=Et(n),t=e.includes("[1m]")||e.endsWith("[1m"),o=e.replace(/\[1m\]|\[1m$/g,""),r=o.match(/^ccr-(opus|sonnet|haiku)$/i);if(r)return{family:r[1].toLowerCase(),extended:t,isCcrAlias:!0};let s=o.match(/claude-(?:\d+-\d+-|\d+-)?(sonnet|opus|haiku)(?:-|$)/i)||o.match(/claude-(sonnet|opus|haiku)(?:-|$)/i);return s?{family:s[1].toLowerCase(),extended:t,isCcrAlias:!1}:{family:null,extended:t,isCcrAlias:!1}}function oc(n,e){if(!e||!n)return null;let t=Et(n);if(e[n])return e[n];if(e[t])return e[t];let{family:o}=qe(n);if(o&&e[o])return e[o];for(let[r,s]of Object.entries(e)){let i=Et(r);if(i&&t.includes(i))return s}return null}function rc(n){return n?(n.input_tokens||0)+(n.cache_read_input_tokens||0)+(n.cache_creation_input_tokens||0):0}function Pt(n){if(!n?.includes(","))return null;let[e,...t]=n.split(","),o=e.trim(),r=t.join(",").trim();return!o||!r?null:{providerName:o,routeModel:r}}function Xe(n,e,t){let o=n.find(s=>s.name.toLowerCase()===e.toLowerCase());if(!o||o.enabled===!1)return null;let r=o.models?.find(s=>String(s).toLowerCase()===t.toLowerCase());return r?{provider:o,model:String(r)}:null}function Xr(n,e){let t=Pt(n);if(!t)return{reason:`invalid model format "${n}" (expected "provider,model")`,code:"invalid_model_format"};let{providerName:o,routeModel:r}=t,s=e.find(c=>c.name?.toLowerCase()===o.toLowerCase());if(!s)return{reason:`provider "${o}" not found`,code:"provider_not_found"};if(s.enabled===!1)return{reason:`provider "${o}" is disabled`,code:"provider_disabled"};let i=s.models?.find(c=>String(c).toLowerCase()===r.toLowerCase());if(!i)return{reason:`model "${r}" not found in provider "${o}"`,code:"model_not_found"};if(!F().isAvailable(s.name,String(i)))return{reason:`model "${r}" in provider "${o}" is temporarily unavailable (health fail-pool)`,code:"model_unhealthy"};let a=wt(s.name);if(a){let c=a.limitDaily!==void 0&&a.usedDailyBalance!==void 0&&a.usedDailyBalance>=a.limitDaily,u=a.totalBalance!==void 0&&a.usedBalance!==void 0&&a.usedBalance>=a.totalBalance;if(c||u)return{reason:`provider "${o}" quota is exhausted`,code:"quota_exhausted"}}return{reason:`unable to resolve model "${n}"`,code:"resolution_failed"}}function G(n,e,t,o,r,s,i){let l=Pt(n);if(!l)return i?null:n;let{providerName:a,routeModel:c}=l,u=Xe(e,a,c);if(!u){if(r===!0&&o&&!t&&s!==!1){let g=Te(),m=g.getPromotion(a,c,o,e);if(m){let y=Pt(m);if(y){let p=Xe(e,y.providerName,y.routeModel);if(p)return`${p.provider.name},${p.model}`}g.clear(a,c,o)}}return null}if(r===!0&&o&&!t&&s!==!1){let g=Te(),m=g.getPromotion(a,c,o,e);if(m){let y=Pt(m);if(y){let p=Xe(e,y.providerName,y.routeModel);if(p)return`${p.provider.name},${p.model}`}g.clear(a,c,o)}}if(!t&&!F().isAvailable(u.provider.name,u.model))return null;let d=wt(u.provider.name);if(d){let g=d.limitDaily!==void 0&&d.usedDailyBalance!==void 0&&d.usedDailyBalance>=d.limitDaily,m=d.totalBalance!==void 0&&d.usedBalance!==void 0&&d.usedBalance>=d.totalBalance;if(g||m)return null}return`${u.provider.name},${u.model}`}function K(n,e,t,o,r,s){let i=F(),l=[t?.[n],o?.[n]];for(let a of l)if(!(!Array.isArray(a)||a.length===0))for(let c of a){let u=G(c,e,!1,n,void 0,void 0,s);if(u)return u}return null}function sc(n){return n.body.messages?.some(e=>e.role==="user"&&Array.isArray(e.content)&&e.content.some(t=>t.type==="image"||t.type==="image_url"||Array.isArray(t?.content)&&t.content.some(o=>o.type==="image"||o.type==="image_url")))}function ro(n){let e=Et(n);return[/claude/i,/gemini/i,/gpt-4o/i,/gpt-4\.1/i,/gpt-4-vision/i,/qwen.*vl/i,/glm-4v/i,/grok.*vision/i,/pixtral/i,/llava/i].some(o=>o.test(e))}function qr(n,e,t){return t?.usageScope!=="session"?n:Math.max(n,rc(e))}function Zr(n,e,t){return n?.extendedContextThreshold??e?.extendedContextThreshold??t??2e5}function ic(n,e,t,o,r,s,i,l,a,c,u,d){let g=n.clientContext,m=g?.longContextThreshold??t.longContextThreshold??a??6e4,y=qr(e,r,g),p=n.modelFamily,f=Zr(g,t,c),_=g?.supportsExplicitExtendedContext!==!1&&s===!0;if((_||y>f)&&t.extendedContext){let b=G(t.extendedContext,o,!1,"extendedContext",l,d,u);if(b)return n.log.info(`Family: using extended context model (1M+), tokens: ${y}, estimated: ${e}, explicit: ${_}, threshold: ${f}`),{model:b,scenarioType:"extendedContext",isFallback:!1};let T=l?K("extendedContext",o,t.fallback,i,p,u):null;if(T)return n.log.info(`Family: using extended context fallback model (1M+), tokens: ${y}, estimated: ${e}, explicit: ${_}, threshold: ${f}`),{model:T,scenarioType:"extendedContext",isFallback:!0};if(u){let x=Y(n,t.extendedContext,o,"extendedContext");if(x)return{model:x,scenarioType:"extendedContext",isFallback:!1}}n.log.warn("Family: extendedContext model unavailable (fail pool), skipping")}if(y>m&&(t.longContext||t.fallback?.longContext?.length||i?.longContext?.length)){let b=t.longContext?G(t.longContext,o,!1,"longContext",l,d,u):null;if(b)return n.log.info(`Family: using long context model, tokens: ${y}, estimated: ${e}`),{model:b,scenarioType:"longContext",isFallback:!1};let T=l?K("longContext",o,t.fallback,i,p,u):null;if(T)return n.log.info(`Family: using long context fallback model, tokens: ${y}, estimated: ${e}`),{model:T,scenarioType:"longContext",isFallback:!0};if(u&&t.longContext){let x=Y(n,t.longContext,o,"longContext");if(x)return{model:x,scenarioType:"longContext",isFallback:!1}}n.log.warn("Family: no healthy longContext model available, falling through to other scenarios")}if(Array.isArray(n.body.tools)&&n.body.tools.some(b=>b.type?.startsWith("web_search"))&&t.webSearch){let b=G(t.webSearch,o,!1,"webSearch",l,d,u);if(b)return{model:b,scenarioType:"webSearch",isFallback:!1};let T=l?K("webSearch",o,t.fallback,i,p,u):null;if(T)return n.log.info("Family: using webSearch fallback model"),{model:T,scenarioType:"webSearch",isFallback:!0};if(u){let x=Y(n,t.webSearch,o,"webSearch");if(x)return{model:x,scenarioType:"webSearch",isFallback:!1}}n.log.warn("Family: webSearch model unavailable (fail pool), skipping")}if(n.body.thinking?.type==="enabled"&&t.think){let b=G(t.think,o,!1,"think",l,d,u);if(b)return{model:b,scenarioType:"think",isFallback:!1};let T=l?K("think",o,t.fallback,i,p,u):null;if(T)return n.log.info("Family: using think fallback model"),{model:T,scenarioType:"think",isFallback:!0};if(u){let x=Y(n,t.think,o,"think");if(x)return{model:x,scenarioType:"think",isFallback:!1}}n.log.warn("Family: think model unavailable (fail pool), skipping")}if(t.default){let b=G(t.default,o,!1,"default",l,d,u);if(b)return{model:b,scenarioType:"default",isFallback:!1};let T=l?K("default",o,t.fallback,i,p,u):null;if(T)return n.log.info("Family: using default fallback model"),{model:T,scenarioType:"default",isFallback:!0};if(u){let x=Y(n,t.default,o,"default");if(x)return{model:x,scenarioType:"default",isFallback:!1}}n.log.warn("Family: default model unavailable (fail pool), skipping")}return null}function dc(){if(he.size<=Kr)return;let n=[...he.keys()].slice(0,he.size-Kr);for(let e of n)he.delete(e)}function pc(){if(Oe.size<=Qr)return;let n=[...Oe].slice(0,Oe.size-Qr);for(let e of n)Oe.delete(e)}var Yr,ae,ie,Ot,nc,ac,At,he,Kr,Oe,Qr,cc,lc,uc,Vr,es,Ae=w(()=>{"use strict";Rt();ee();Re();xt();Ve();Ee();Yr={provider_not_found:404,model_not_found:404,invalid_model_format:400,provider_disabled:503,model_unhealthy:503,quota_exhausted:503,resolution_failed:502,project_config_error:500},ae=class extends Error{statusCode;code;type;sessionId;configuredTarget;constructor(e,t){super(e),this.name="ProjectRoutingError",this.statusCode=t?.statusCode||Yr[t?.code||""]||502,this.code=t?.code||"project_routing_error",this.type="api_error",this.sessionId=t?.sessionId,this.configuredTarget=t?.configuredTarget}};ie=Za("cl100k_base"),Ot=(n,e,t)=>{let o=0;return Array.isArray(n)&&n.forEach(r=>{typeof r.content=="string"?o+=ie.encode(r.content).length:Array.isArray(r.content)&&r.content.forEach(s=>{s.type==="text"?o+=ie.encode(s.text).length:s.type==="tool_use"?o+=ie.encode(JSON.stringify(s.input)).length:s.type==="tool_result"&&(o+=ie.encode(typeof s.content=="string"?s.content:JSON.stringify(s.content)).length)})}),typeof e=="string"?o+=ie.encode(e).length:Array.isArray(e)&&e.forEach(r=>{r.type==="text"&&(typeof r.text=="string"?o+=ie.encode(r.text).length:Array.isArray(r.text)&&r.text.forEach(s=>{o+=ie.encode(s||"").length}))}),t&&t.forEach(r=>{r.description&&(o+=ie.encode(r.name+r.description).length),r.input_schema&&(o+=ie.encode(JSON.stringify(r.input_schema)).length)}),o},nc=async(n,e)=>{if(n.sessionId){let t=await es(n.sessionId);if(t){let o=oo(Gr,t,"config.json"),r=oo(Gr,t,`${n.sessionId}.json`);try{let s=JSON.parse(await no(r,"utf8"));if(s&&s.Router&&Object.keys(s.Router).length>0)return s.Router}catch{}try{let s=JSON.parse(await no(o,"utf8"));if(s&&s.Router&&Object.keys(s.Router).length>0)return s.Router}catch(s){if(s&&s.code!=="ENOENT"){let i=n.sessionId||n.clientContext?.stableSessionId;throw new ae(`Project routing error: project config.json is malformed or unreadable in project "${t}". ${s.message}. Session: "${i||"unknown"}".`,{sessionId:i,configuredTarget:o,code:"project_config_error",statusCode:500})}}}}};ac=async(n,e,t,o,r,s)=>{let i=t.get("providers")||[],l=r||t.get("Router"),a=l?.enableFallback===!0,c=a?l?.fallback:void 0,u=a&&!s?c||t.get("fallback"):c,d=!s,g=null;if(n.body?.system?.length>1&&n.body?.system[1]?.text?.includes("<CCR-SUBAGENT-MODEL>")){let v=n.body?.system[1].text.match(/<CCR-SUBAGENT-MODEL>(.*?)<\/CCR-SUBAGENT-MODEL>/s);v&&(n.body.system[1].text=n.body.system[1].text.replace(`<CCR-SUBAGENT-MODEL>${v[1]}</CCR-SUBAGENT-MODEL>`,""),g=v[1])}let{family:m,extended:y,isCcrAlias:p}=qe(n.body.model),f=l?.families?.[m||""];if(f&&l?.enableFamilyRouting){n.log.info(`Using model family routing for: ${m}${y?" (1M)":""}`),n.modelFamily=m,n.familyFallback=f.fallback;let v=ic(n,e,f,i,o,y,u,a,l?.longContextThreshold,l?.extendedContextThreshold,s,d);if(v)return{model:v.model,scenarioType:v.scenarioType}}if(n.body.model.includes(",")&&!s){let v=G(n.body.model,i,!1,"default",a,d,s);if(v)return{model:v,scenarioType:"default"};n.log.warn(`Explicit model ${n.body.model} unavailable (fail pool), trying fallback`);let S=a?K("default",i,void 0,u,void 0,s):null;if(S)return n.log.info(`Using fallback for explicit model: ${S}`),{model:S,scenarioType:"default"};n.log.warn(`No fallback available for explicit model ${n.body.model}, continuing through routing logic`)}let _=p&&!l?.enableFamilyRouting?null:oc(n.body.model,l?.models);if(_){let v=G(_,i,!1,"modelMapping",a,d,s);if(v)return n.log.info(`Using mapped model for ${n.body.model}: ${_}`),{model:v,scenarioType:"modelMapping"};let S=a?K("modelMapping",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"modelMapping"};if(s){let C=Y(n,_,i,"modelMapping");if(C)return{model:C,scenarioType:"modelMapping"}}n.log.warn(`Mapped model ${_} unavailable (fail pool), skipping`)}let k=n.clientContext,h=qr(e,o,k),b=Zr(k,void 0,l?.extendedContextThreshold);if(h>b&&l?.extendedContext){n.log.info(`Using extended context (1M) model due to token count: ${h}, estimated: ${e}, threshold: ${b}`);let v=G(l.extendedContext,i,!1,"extendedContext",a,d,s);if(v)return{model:v,scenarioType:"extendedContext"};n.log.warn(`Extended context model ${l.extendedContext} unavailable (fail pool), trying fallback`);let S=a?K("extendedContext",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"extendedContext"};if(s){let C=Y(n,l.extendedContext,i,"extendedContext");if(C)return{model:C,scenarioType:"extendedContext"}}}let T=k?.longContextThreshold??l?.longContextThreshold??6e4;if(h>T&&l?.longContext){n.log.info(`Using long context model due to token count: ${h}, estimated: ${e}, threshold: ${T}`);let v=G(l.longContext,i,!1,"longContext",a,d,s);if(v)return{model:v,scenarioType:"longContext"};n.log.warn(`Long context model ${l.longContext} unavailable (fail pool), trying fallback`);let S=a?K("longContext",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"longContext"};if(s){let C=Y(n,l.longContext,i,"longContext");if(C)return{model:C,scenarioType:"longContext"}}}if(!s&&g)return{model:g,scenarioType:"default"};if(n.body.model?.includes("claude")&&n.body.model?.includes("haiku")&&l?.background){n.log.info(`Using background model for ${n.body.model}`);let v=G(l.background,i,!1,"background",a,d,s);if(v)return{model:v,scenarioType:"background"};let S=a?K("background",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"background"};if(s){let C=Y(n,l.background,i,"background");if(C)return{model:C,scenarioType:"background"}}n.log.warn(`Background model ${l.background} unavailable (fail pool), falling through`)}if(Array.isArray(n.body.tools)&&n.body.tools.some(v=>v.type?.startsWith("web_search"))&&l?.webSearch){let v=G(l.webSearch,i,!1,"webSearch",a,d,s);if(v)return{model:v,scenarioType:"webSearch"};n.log.warn(`WebSearch model ${l.webSearch} unavailable (fail pool), trying fallback`);let S=a?K("webSearch",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"webSearch"};if(s){let C=Y(n,l.webSearch,i,"webSearch");if(C)return{model:C,scenarioType:"webSearch"}}}if(n.body.thinking?.type==="enabled"&&l?.think){n.log.info(`Using think model for ${n.body.thinking}`);let v=G(l.think,i,!1,"think",a,d,s);if(v)return{model:v,scenarioType:"think"};n.log.warn(`Think model ${l.think} unavailable (fail pool), trying fallback`);let S=a?K("think",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"think"};if(s){let C=Y(n,l.think,i,"think");if(C)return{model:C,scenarioType:"think"}}}if(l?.default){let v=G(l.default,i,!1,"default",a,d,s);if(v)return{model:v,scenarioType:"default"};n.log.warn(`Default model ${l.default} unavailable (fail pool), trying fallback`);let S=a?K("default",i,void 0,u,void 0,s):null;if(S)return{model:S,scenarioType:"default"};let C=G(l.default,i,!0,"default",a,d,s);if(C)return n.log.warn(`No fallback available; retrying default model ${l.default} despite fail-pool state (strict=${s})`),{model:C,scenarioType:"default"}}if(s){let v=Y(n,l?.default||n.body.model,i,"default");if(v)return{model:v,scenarioType:"default"}}return{model:void 0,scenarioType:"default"}},At=async(n,e,t)=>{let{configService:o,event:r}=t;!n.originalModel&&n.body.model&&(n.originalModel=n.body.model),ge(n,o.getAll());let s=await nc(n,o),i=s||o.get("Router"),l=i?.enableFallback===!0,a=o.get("providers")||[],c=!!s;n.enableFallback=l,n.strictProjectRouting=c,n.fallbackConfig=c?i?.fallback:i?.fallback||o.get("fallback");let u=n.clientContext?.usageScope==="session"?n.previousUsage??V.get(n.usageCacheKey):void 0,{messages:d,system:g=[],tools:m}=n.body,y=o.get("REWRITE_SYSTEM_PROMPT");if(y&&g.length>1&&g[1]?.text?.includes("<env>")){let p=await no(y,"utf-8");g[1].text=`${p}<env>${g[1].text.split("<env>").pop()}`}try{let[p,f]=n.body.model.split(","),_=t.tokenizerService?.getTokenizerConfigForModel(p,f),k;t.tokenizerService?k=(await t.tokenizerService.countTokens({messages:d,system:g,tools:m},_,p)).tokenCount:k=Ot(d,g,m),n.tokenCount=k;let h,b=c?void 0:o.get("CUSTOM_ROUTER_PATH");if(b)try{h=await Be(b)(n,o.getAll(),{event:r})}catch(S){n.log.error(`failed to load custom router: ${S.message}`)}if(h)n.scenarioType="default";else{let S=await ac(n,k,o,u,s,!!s);h=S.model,n.scenarioType=S.scenarioType}let{family:T}=qe(n.originalModel||n.body.model),x=i?.enableFamilyRouting&&T?i.families?.[T]:void 0,v=[x?.image,i?.image].filter((S,C,P)=>!!S&&P.indexOf(S)===C);if(v.length>0&&sc(n)&&!ro(h))if(v.includes(h))n.scenarioType="image";else{let S=v.map(C=>G(C,a,!1,"image",l,!c,c)).find(C=>!!C);if(S)n.log.info(`Using image model fallback for ${h}`),h=S,n.scenarioType="image";else{let C=l?K("image",a,x?.fallback,n.fallbackConfig,T||void 0,c):null;if(C)n.log.info(`Using image fallback model: ${C}`),h=C,n.scenarioType="image";else if(c){let P=Y(n,v[0],a,"image");P&&(h=P,n.scenarioType="image")}else n.log.warn(`Image models ${v.join(", ")} unavailable (fail pool), keeping ${h}`),n.scenarioType="image"}}typeof h=="string"&&h.trim()?n.body.model=h:(n.log.warn(`Router could not resolve a valid model for ${n.originalModel||n.body.model}; keeping original request model`),n.scenarioType=n.scenarioType||"default")}catch(p){if(p instanceof ae)throw p;if(n.log.error(`Error in router middleware: ${p.message}`),c){let f=n.sessionId||n.clientContext?.stableSessionId;throw new ae(`Project routing error: router failure in project mode. ${p.message}. Session: "${f||"unknown"}".`,{sessionId:f,configuredTarget:i?.default,code:"project_router_failure",statusCode:502})}n.body.model=i?.default,n.scenarioType="default"}},he=new Map,Kr=1e3,Oe=new Set,Qr=1e3,cc=3,lc=50,uc=n=>new Promise(e=>setTimeout(e,n));Vr=async n=>{let e=await ec(Wr),t=[];for await(let s of e)s.isDirectory()&&t.push(s.name);let o=t.map(async s=>{let i=oo(Wr,s,`${n}.jsonl`);try{return(await tc(i)).isFile()?s:null}catch{return null}}),r=await Promise.all(o);for(let s of r)if(s)return s;return null},es=async n=>{let e=we(n);if(!e)return null;if(he.has(e))return he.get(e)||null;try{let t=await Vr(e);if(!t&&!Oe.has(e)){Oe.add(e),pc();for(let o=0;o<cc&&!t;o++)await uc(lc),t=await Vr(e)}return t?(he.set(e,t),dc(),t):null}catch(t){return console.error("Error searching for project by session:",t),null}}});function Ze(n){let e=[],t=Array.isArray(n.input)?n.input:[n.input];for(let o of t)if(o.type==="function_call")e.push({role:"assistant",tool_calls:[{id:o.call_id,type:"function",function:{name:o.name,arguments:o.arguments||"{}"}}]});else if(o.type==="function_call_output")e.push({role:"tool",tool_call_id:o.call_id,content:typeof o.output=="string"?o.output:JSON.stringify(o.output)});else if(o.type==="reasoning"){let r=Array.isArray(o.summary)?o.summary.filter(s=>s.type==="summary_text"&&s.text).map(s=>s.text).join(`
|
|
43
43
|
`):"";r&&e.push({role:"assistant",content:[{type:"text",text:`[reasoning]
|
|
44
44
|
${r}`}],_reasoningItem:!0})}else if(o.role){let r=o.content;Array.isArray(r)&&(r=r.map(s=>s.type==="input_text"?{type:"text",text:s.text}:s.type==="output_text"?{type:"text",text:s.text}:s.type==="input_image"?{type:"image_url",image_url:{url:s.image_url},media_type:s.mime_type}:s)),e.push({role:o.role,content:r})}n.messages=e,delete n.input,n.instructions&&typeof n.instructions=="string"&&(n.system=n.instructions,delete n.instructions),Array.isArray(n.tools)&&(n.tools=n.tools.filter(o=>o&&typeof o=="object").map(o=>o.type==="function"&&o.name&&!o.function?{type:"function",function:{name:o.name,description:o.description||"",parameters:o.parameters||{type:"object",properties:{}}}}:o.function?.name?o:o.type==="web_search"?{type:"function",function:{name:"web_search",description:"Search the web",parameters:{type:"object",properties:{query:{type:"string"}}}}}:null).filter(Boolean)),n.reasoning&&typeof n.reasoning=="object"&&(n.reasoning={enabled:!0,effort:n.reasoning.effort}),delete n.store,delete n.previous_response_id,delete n.include}async function ts(n,e,t,o){let r=n.body;(n.ccrHookOrder||=[]).push("handler"),o.endPoint==="/v1/responses"&&r?.input&&!r?.messages&&Ze(r),o.endPoint==="/v1/responses"&&!n.provider&&typeof r?.model=="string"&&fc.test(r.model)&&await At(n,e,{configService:t.configService,tokenizerService:t.tokenizerService});let s=n.provider;if(!s&&r?.model){let c=r.model.split(",");c.length>1&&(s=c[0],r.model=c.slice(1).join(","))}let i=s?t.providerService.getProvider(s):void 0;if(!i&&r?.model){let c=t.providerService.resolveModelRoute(r.model);c&&(i=c.provider,r.model=c.targetModel)}if(!i&&r?.model){let u=t.configService.get("Router")?.default;if(u&&u.includes(",")){let[d,...g]=u.split(","),m=t.providerService.getProvider(d);m&&(i=m,r.model=g.join(","))}}if(n.originalModel||(n.originalModel=r?.model),!i)throw B(`Provider '${s}' not found`,404,"provider_not_found");n.provider=i.name||s;let l=hc(n),a=o.endPoint==="/v1/messages"&&l;l&&e.header("X-Codex-Detected","true"),a&&e.header("X-Codex-On-Messages","true"),n.isCodexOnMessagesEndpoint=a,n.codexDetected=l;try{o.endPoint==="/v1/responses"&&r.input&&!r.messages&&Ze(r);let{requestBody:c,config:u,bypass:d}=await os(r,i,o,n.headers,{req:n});if(c?.messages&&!d&&!n.isTargetAnthropic){let p=c.messages,f=new Set,_=[],k=[];for(let h of p){if(h?.role!=="system"){k.push(h);continue}let b=JSON.stringify(h.content??"");f.has(b)||(f.add(b),_.push(h))}_.length>0&&k.length>0&&(c.messages=[..._,...k])}let g=await rs(c,u,i,t,d,o,{req:n});try{i?.baseUrl&&g?.headers&&We(s,i.baseUrl,g.headers)}catch{}let m=await ss(c,g,i,o,d,{req:n,isCodexOnMessagesEndpoint:a});m=await ns(r,m,i.name||s);let y=is(m,e,r,t);try{let p=r.model||n.originalModel;s&&p&&F().recordSuccess(s,p)}catch{}return y}catch(c){if(c instanceof ae)throw c;if(!n.__retryAttempted){n.__retryAttempted=!0;try{return await ts(n,e,t,o)}catch(d){if(n.__fallbackExhausted)throw d;c=d}}let u=await mc(n,e,t,o,c);if(u)return u;throw n.__fallbackExhausted=!0,c}}async function ns(n,e,t){if(!n?.stream||!e?.body)return e;let o=e.body.getReader(),r=await o.read();if(r.done)throw o.releaseLock(),B(`Provider returned empty streaming response from ${t}`,400,"provider_response_error");let s=new TextDecoder().decode(r.value);if(s.includes("event: error")){o.releaseLock();let a=s.length<500?s:s.slice(0,500);throw B(`Provider ${t} returned error in SSE stream: ${a}`,400,"provider_response_error")}if(s.split(`
|
|
45
45
|
`).filter(a=>a.startsWith("data:")&&a.trim().length>5).length===0){o.releaseLock();let a=s.length<500?s:s.slice(0,500);throw B(`Provider ${t} returned streaming response with no SSE data lines: ${a}`,400,"provider_response_error")}let l=new ReadableStream({start:a=>{a.enqueue(r.value);let c=()=>{o.read().then(({done:u,value:d})=>{u?a.close():(a.enqueue(d),c())}).catch(u=>a.error(u))};c()},cancel:()=>{o.cancel()}});return new Response(l,{headers:e.headers,status:e.status,statusText:e.statusText})}async function mc(n,e,t,o,r){let s=n.scenarioType||"default",i=n.familyFallback,l=n.modelFamily,a=n.strictProjectRouting?n.fallbackConfig:n.fallbackConfig??t.configService.get("fallback"),c=F(),u=n.provider||"",d=n.body.model||"",g=new Set,m=r?.statusCode===429||r?.isRateLimit===!0||r?.rawBody&&It(r.rawBody)||r?.message&&It(r.message);if(u&&d&&(m?(c.markRateLimited(u,d,120,r?.message),n.log.warn(`Primary model ${u},${d} rate-limited, will try fallbacks`)):c.recordFailure(u,d,r?.message),g.add(`${u},${d}`),t.recordUsage?.({provider:u,model:d,originalModel:n.originalModel||d,scenarioType:s,modelFamily:n.modelFamily,errorMessage:r?.message||String(r),sessionId:n.usageSessionId||n.id,stream:n.body.stream,inputTokens:n.tokenCount||0,req:n})),!(n.enableFallback??t.configService.get("Router")?.enableFallback===!0))return n.log.info("Fallback disabled by configuration, skipping fallback attempts"),null;let p=k=>{let[h,...b]=k.split(","),T=h?.trim(),x=b.join(",").trim();return!T||!x?null:{provider:T,model:x,key:`${T},${x}`}},f=[];if(l){let k=i?.[s];if(Array.isArray(k)&&k.length>0)f.push({name:`${l}/${s}`,models:k});else{let h=n.strictProjectRouting;n.log.warn(`No ${l} fallback configured for ${s}; ${h?"no project fallback available":"will try global fallback"}`)}}if(Array.isArray(a?.[s])&&a[s].length>0&&f.push({name:`global/${s}`,models:a[s]}),f.length===0&&s!=="image"&&n.body?.messages?.some(b=>b.role==="user"&&Array.isArray(b.content)&&b.content.some(T=>T.type==="image"||T.type==="image_url"||Array.isArray(T?.content)&&T.content.some(x=>x.type==="image"||x.type==="image_url")))&&Array.isArray(a?.image)&&a.image.length>0&&(n.log.info(`No fallback for scenario '${s}', but request has images \u2014 trying fallback.image`),f.push({name:"global/image (auto-detected)",models:a.image})),f.length===0)return null;let _=f.reduce((k,h)=>k+h.models.length,0);n.log.warn(`Request failed for ${s}, trying ${_} fallback models across ${f.length} fallback stage(s)`);for(let k of f){n.log.info(`Trying ${k.name} fallback stage with ${k.models.length} models`);for(let h of k.models){let b=p(h);if(!b){n.log.warn(`Fallback model '${h}' is invalid, skipping`);continue}if(g.has(b.key))continue;g.add(b.key);let T=t.providerService.getProviders(),x=Xe(T,b.provider,b.model);if(!x){n.log.warn(`Fallback model ${h} is not configured or provider is disabled, skipping`);continue}let v=x.provider.name,S=x.model;if(!c.isAvailable(v,S)){n.log.warn(`Fallback model ${h} unavailable (fail pool), skipping`);continue}let C;for(let P=1;P<=2;P++)try{n.log.info(`Trying fallback model: ${v},${S}${P>1?" (retry)":""}`);let R={...n.body};R.model=S;let O={...n,provider:v,body:R},E=x.provider,{requestBody:A,config:N,bypass:D}=await os(R,E,o,n.headers,{req:O}),j=await rs(A,N,E,t,D,o,{req:O});try{E?.baseUrl&&j?.headers&&We(v,E.baseUrl,j.headers)}catch{}let $=await ss(A,j,E,o,D,{req:O,isCodexOnMessagesEndpoint:n.isCodexOnMessagesEndpoint||!1});return $=await ns(R,$,v),n.log.info(`Fallback model ${v},${S} succeeded`),c.recordSuccess(v,S),u&&d&&!n.strictProjectRouting&&(Te().promote(u,d,s,v,S),n.log.info(`Promoted fallback model ${v},${S} for ${u},${d}:${s}`),m?n.log.info(`Rate-limited original model ${u},${d} already marked unavailable with cooldown`):(c.forceOpen(u,d,r?.message),n.log.info(`Marked original model ${u},${d} as unavailable`))),n.provider=v,n.body=R,is($,e,R,t)}catch(R){if(C=R,P===1){n.log.warn(`Fallback model ${v},${S} failed, retrying once: ${R.message}`);continue}}c.recordFailure(v,S,C?.message),n.log.warn(`Fallback model ${v},${S} failed after retry: ${C?.message}`),t.recordUsage?.({provider:v,model:S,originalModel:n.originalModel||d||n.body.model,scenarioType:s,modelFamily:n.modelFamily,errorMessage:C?.message||String(C),sessionId:n.usageSessionId||n.id,stream:n.body.stream,inputTokens:n.tokenCount||0,req:n})}}return n.log.error(`All fallback models failed for ${s}`),null}async function os(n,e,t,o,r){let s=JSON.parse(JSON.stringify(n)),i=s?.system;if(typeof i=="string"&&i.includes("cch="))s.system=i.replace(/cch=[^;]+;?/g,"cch=ccr-stable;");else if(Array.isArray(i))for(let c=0;c<i.length;c++){let u=i[c],d=typeof u=="string"?u:u?.text??"";if(d.includes("cch=")){let g=d.replace(/cch=[^;]+;?/g,"cch=ccr-stable;");typeof u=="string"?i[c]=g:typeof u?.text=="string"&&(u.text=g)}}let l={},a=!1;if(a=gc(e,t,n),a&&(o instanceof Headers?o.delete("content-length"):delete o["content-length"],l.headers=o),!a&&typeof t.transformRequestOut=="function"){let c=await t.transformRequestOut(s);c.body?(s=c.body,l=c.config||{}):s=c}if(!a&&e.transformer?.use?.length)for(let c of e.transformer.use){if(!c||typeof c.transformRequestIn!="function")continue;let u=await c.transformRequestIn(s,e,r);u.body?(s=u.body,l={...l,...u.config}):s=u}if(!a&&e.transformer?.[n.model]?.use?.length)for(let c of e.transformer[n.model].use)!c||typeof c.transformRequestIn!="function"||(s=await c.transformRequestIn(s,e,r));return{requestBody:s,config:l,bypass:a}}function gc(n,e,t){return e.endPoint==="/v1/chat/completions"&&Array.isArray(t?.system)?!1:n.transformer?.use?.length===1&&n.transformer.use[0].name===e.name&&(!n.transformer?.[t.model]?.use.length||n.transformer?.[t.model]?.use.length===1&&n.transformer?.[t.model]?.use[0].name===e.name)}function hc(n){if(n.clientType)return n.clientType==="codex";let e=n.headers||{},t=e["x-anthropic-billing-header"]||"";if(typeof t=="string"&&t.includes("cc_version="))return!1;let o=e["user-agent"]||"";if(typeof o=="string"&&/codex/i.test(o))return!0;let r=n.pathname||n.url||"";if(typeof r=="string"&&r.split("?",1)[0].endsWith("/v1/responses"))return!0;let s=n.originalModel||n.body?.model||"";return typeof s=="string"&&s.toLowerCase()==="ccr-codex"}async function rs(n,e,t,o,r,s,i){let l=e.url||new URL(t.baseUrl);if(!e.TIMEOUT){let u=o.configService.get("API_TIMEOUT_MS");u&&(e.TIMEOUT=typeof u=="string"?parseInt(u,10):u)}if(r&&typeof s.auth=="function"){let u=await s.auth(n,t);if(u.body){n=u.body;let d=e.headers||{};u.config?.headers&&(d={...d,...u.config.headers},delete d.host,delete u.config.headers),e={...e,...u.config,headers:d}}else n=u}let a={Authorization:`Bearer ${t.apiKey}`,...e?.headers||{}};for(let u in a)(a[u]==="undefined"||["authorization","Authorization"].includes(u)&&a[u]?.includes("undefined"))&&delete a[u];bt(o.configService)&&br(o.log,i.req.id,{url:String(l),headers:a,body:n});let c=await vr(l,n,{...e,headers:JSON.parse(JSON.stringify(a)),httpsProxy:se(o.configService,t)},i,o.log);if(!c.ok){let u=await c.text();o.log.error(`[provider_response_error] Error from provider(${t.name},${n.model}: ${c.status}): ${u}`);let d=B(`Error from provider(${t.name},${n.model}: ${c.status}): ${u}`,c.status,"provider_response_error");throw d.isRateLimit=c.status===429||It(u),d.rawBody=u,d}if(c.ok){let u=c.headers.get("content-type")||"",d=n.stream===!0;if(o.log.info(`[hidden-error-check] provider=${t.name} model=${n.model} stream=${n.stream} isStreamRequest=${d} contentType=${u} ok=${c.ok} status=${c.status} hasBody=${!!c.body}`),!d||u.includes("application/json")){let g=c.clone(),m="";try{if(m=await g.text(),!m||m.trim()==="")throw new SyntaxError("Empty JSON body");let y=JSON.parse(m);if(y&&typeof y=="object"&&y.error&&(typeof y.error=="string"||typeof y.error=="object"&&Object.keys(y.error).length>0)){o.log.error(`[provider_response_error] Hidden error from provider(${t.name},${n.model}: ${c.status}): ${m}`);let f=It(m),_=B(`Error from provider(${t.name},${n.model}: ${c.status}): ${m}`,400,"provider_response_error");throw _.isRateLimit=f,_.rawBody=m,_}}catch(y){if(y instanceof SyntaxError){o.log.warn(`[provider_response_error] Empty or malformed JSON response from provider(${t.name},${n.model}: 200): "${m}"`);let p=B(`API returned an empty or malformed response (HTTP 200) from ${t.name} \u2014 check for a proxy or gateway intercepting the request`,400,"provider_response_error");throw p.rawBody=m,p}throw y}}}if(!n.stream&&bt(o.configService)){let d=await c.clone().text();Tr(o.log,i.req.id,{status:c.status,headers:Object.fromEntries(c.headers.entries()),body:d})}return c}async function ss(n,e,t,o,r,s){let i=e;if(!r&&t.transformer?.use?.length)for(let l of Array.from(t.transformer.use).reverse())!l||typeof l.transformResponseOut!="function"||(i=await l.transformResponseOut(i,s));if(!r&&t.transformer?.[n.model]?.use?.length)for(let l of Array.from(t.transformer[n.model].use).reverse())!l||typeof l.transformResponseOut!="function"||(i=await l.transformResponseOut(i,s));if(!r&&o.transformResponseIn&&(s.provider||(s.provider=t),i=await o.transformResponseIn(i,s)),s?.isCodexOnMessagesEndpoint)try{i=await new xe().transformResponseIn(i,{...s,provider:t})}catch(l){console.error("Failed to apply Responses API conversion for codex client:",l)}return i}function is(n,e,t,o){if(n.ok||e.code(n.status),t.stream===!0){if(e.header("Content-Type","text/event-stream"),e.header("Cache-Control","no-cache"),e.header("Connection","keep-alive"),o&&bt(o.configService)){let[s,i]=n.body.tee(),l=kr(o.configService);return Cr(s,o.log,e.request.id,l),e.send(i)}return e.send(n.body)}else return n.json()}function It(n){let e=n.toLowerCase();return e.includes("rate limit")||e.includes("rate_limit")||e.includes("rate_limit_error")||e.includes("too many requests")||e.includes("too many")||e.includes("quota exhausted")||e.includes("qps_limit")||e.includes("token_limit")||e.includes("\u9650\u6D41")||e.includes("\u9891\u7387\u9650\u5236")}function yc(n){try{return new URL(n),!0}catch{return!1}}var fc,as,Mt=w(()=>{"use strict";xr();_t();Je();jn();ee();ve();xt();Yn();Ae();Z();fc=/^ccr-(opus|sonnet|haiku)(\[1m\])?$/i;as=async n=>{n.get("/",async()=>({message:"LLMs API",version:vt})),n.get("/health",async()=>({status:"ok",timestamp:new Date().toISOString()})),n.get("/providers/health",async()=>({states:F().getAllStates().map(r=>({provider:r.provider,model:r.model,status:r.status,failureCount:r.failureCount,successCount:r.successCount,lastFailureTime:r.lastFailureTime,lastError:r.lastError,rateLimitUntil:r.rateLimitUntil??null})),timestamp:new Date().toISOString()}));let e=n.transformerService.getTransformersWithEndpoint();for(let{transformer:t}of e)t.endPoint&&n.post(t.endPoint,async(o,r)=>ts(o,r,n,t));n.post("/providers",{schema:{body:{type:"object",properties:{id:{type:"string"},name:{type:"string"},type:{type:"string",enum:["openai","anthropic"]},baseUrl:{type:"string"},apiKey:{type:"string"},models:{type:"array",items:{type:"string"}},proxyEnabled:{type:"boolean"}},required:["id","name","type","baseUrl","apiKey","models"]}}},async(t,o)=>{let{name:r,baseUrl:s,apiKey:i,models:l}=t.body;if(!r?.trim())throw B("Provider name is required",400,"invalid_request");if(!s||!yc(s))throw B("Valid base URL is required",400,"invalid_request");if(!i?.trim())throw B("API key is required",400,"invalid_request");if(!l||!Array.isArray(l)||l.length===0)throw B("At least one model is required",400,"invalid_request");if(n.providerService.getProvider(t.body.name))throw B(`Provider with name '${t.body.name}' already exists`,400,"provider_exists");return n.providerService.registerProvider(t.body)}),n.get("/providers",async()=>n.providerService.getProviders()),n.get("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]}}},async t=>{let o=n.providerService.getProvider(t.params.id);if(!o)throw B("Provider not found",404,"provider_not_found");return o}),n.put("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]},body:{type:"object",properties:{name:{type:"string"},type:{type:"string",enum:["openai","anthropic"]},baseUrl:{type:"string"},apiKey:{type:"string"},models:{type:"array",items:{type:"string"}},proxyEnabled:{type:"boolean"},enabled:{type:"boolean"}}}}},async(t,o)=>{let r=n.providerService.updateProvider(t.params.id,t.body);if(!r)throw B("Provider not found",404,"provider_not_found");return r}),n.delete("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]}}},async t=>{if(!n.providerService.deleteProvider(t.params.id))throw B("Provider not found",404,"provider_not_found");return{message:"Provider deleted successfully"}}),n.patch("/providers/:id/toggle",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]},body:{type:"object",properties:{enabled:{type:"boolean"}},required:["enabled"]}}},async(t,o)=>{if(!n.providerService.toggleProvider(t.params.id,t.body.enabled))throw B("Provider not found",404,"provider_not_found");return{message:`Provider ${t.body.enabled?"enabled":"disabled"} successfully`}})}});var ce,$t=w(()=>{"use strict";ce=class{constructor(e,t,o){this.configService=e;this.transformerService=t;this.logger=o;this.initializeCustomProviders()}providers=new Map;modelRoutes=new Map;initializeCustomProviders(){let e=this.configService.get("providers");if(e&&Array.isArray(e)){this.initializeFromProvidersArray(e);return}}initializeFromProvidersArray(e){e.forEach(t=>{try{if(!t.name||!t.api_base_url||!t.api_key)return;let o={};t.transformer&&Object.keys(t.transformer).forEach(r=>{r==="use"?Array.isArray(t.transformer.use)&&(o.use=t.transformer.use.map(s=>{if(Array.isArray(s)&&typeof s[0]=="string"){let i=this.transformerService.getTransformer(s[0]);if(i)return new i(s[1])}if(typeof s=="string"){let i=this.transformerService.getTransformer(s);return typeof i=="function"?new i:i}}).filter(s=>typeof s<"u")):Array.isArray(t.transformer[r]?.use)&&(o[r]={use:t.transformer[r].use.map(s=>{if(Array.isArray(s)&&typeof s[0]=="string"){let i=this.transformerService.getTransformer(s[0]);if(i)return new i(s[1])}if(typeof s=="string"){let i=this.transformerService.getTransformer(s);return typeof i=="function"?new i:i}}).filter(s=>typeof s<"u")})}),this.registerProvider({name:t.name,baseUrl:t.api_base_url,apiKey:t.api_key,models:t.models||[],quotaToken:t.quota_token,quotaSecToken:t.quota_sec_token,transformer:t.transformer?o:void 0,cacheMode:t.cache_mode||"exclusive",enabled:t.enabled!==!1,proxyEnabled:t.proxy_enabled===!0,wakeupEnabled:t.wakeup_enabled===!0,wakeupTime:t.wakeup_time||"06:00",wakeupModel:t.wakeup_model||""}),this.logger.info(`${t.name} provider registered`)}catch(o){this.logger.error(`${t.name} provider registered error: ${o}`)}})}registerProvider(e){let t={...e,enabled:e.enabled!==!1,proxyEnabled:e.proxyEnabled===!0,wakeupEnabled:e.wakeupEnabled===!0,wakeupTime:e.wakeupTime||"06:00",wakeupModel:e.wakeupModel||""};return this.providers.set(t.name,t),e.models.forEach(o=>{let r=`${t.name},${o}`,s={provider:t.name,model:o,fullModel:r};this.modelRoutes.set(r,s),this.modelRoutes.has(o)||this.modelRoutes.set(o,s)}),t}getProviders(){return Array.from(this.providers.values())}getProvider(e){return this.providers.get(e)}updateProvider(e,t){let o=this.providers.get(e);if(!o)return null;let r={...o,...t,updatedAt:new Date};return this.providers.set(e,r),t.models&&(o.models.forEach(s=>{let i=`${o.name},${s}`;this.modelRoutes.delete(i),this.modelRoutes.delete(s)}),t.models.forEach(s=>{let i=`${o.name},${s}`,l={provider:o.name,model:s,fullModel:i};this.modelRoutes.set(i,l),this.modelRoutes.has(s)||this.modelRoutes.set(s,l)})),r}deleteProvider(e){let t=this.providers.get(e);return t?(t.models.forEach(o=>{let r=`${t.name},${o}`;this.modelRoutes.delete(r),this.modelRoutes.delete(o)}),this.providers.delete(e),!0):!1}toggleProvider(e,t){let o=this.providers.get(e);if(!o)return!1;o.enabled=t;let r=this.configService.get("providers");if(r&&Array.isArray(r)){let s=r.find(i=>i.name===e);s&&(s.enabled=t)}return!0}resolveModelRoute(e){let t=this.modelRoutes.get(e);if(!t)return null;let o=this.providers.get(t.provider);return o?{provider:o,originalModel:e,targetModel:t.model}:null}getAvailableModelNames(){let e=[];return this.providers.forEach(t=>{t.enabled!==!1&&t.models.forEach(o=>{e.push(o),e.push(`${t.name},${o}`)})}),e}getModelRoutes(){return Array.from(this.modelRoutes.values())}parseTransformerConfig(e){return e?Array.isArray(e)?e.reduce((t,o)=>{if(Array.isArray(o)){let[r,s={}]=o;t[r]=s}else t[o]={};return t},{}):e:{}}async getAvailableModels(){let e=[];return this.providers.forEach(t=>{t.enabled!==!1&&t.models.forEach(o=>{e.push({id:o,object:"model",owned_by:t.name,provider:t.name}),e.push({id:`${t.name},${o}`,object:"model",owned_by:t.name,provider:t.name})})}),{object:"list",data:e}}}});var cs,ls=w(()=>{cs=n=>n<=0?"none":n<=1024?"low":n<=8192?"medium":"high"});var us,ds=w(()=>{us=(n,e)=>(n.includes("base64")&&(n=n.split("base64").pop(),n.startsWith(",")&&(n=n.slice(1))),`data:${e};base64,${n}`)});function _c(n){return n.filter(e=>!!e?.function?.name).map(e=>({name:e.function.name,description:e.function.description,input_schema:e.function.parameters}))}function ps(n){let e=[],t=[],o=g=>{if(typeof g=="string"){t.push({type:"text",text:g});return}Array.isArray(g)&&g.forEach(m=>{if(typeof m=="string"){t.push({type:"text",text:m});return}m&&typeof m=="object"&&m.type==="text"&&m.text&&t.push({...m})})},r=()=>{let g=new Map;for(let m=0;m<t.length;m++){let y=t[m],p=y?.text??JSON.stringify(y),f=g.get(p);if(f===void 0){g.set(p,m);continue}!t[f]?.cache_control&&y?.cache_control&&(t[f]=y),t.splice(m,1),m--}};n.messages.forEach(g=>{g.role==="system"?o(g.content):e.push(g)}),r();let s=[];for(let g=0;g<e.length;g++){let m=e[g];if(m.role==="tool"){let y=m.content;try{typeof m.content=="string"&&(y=JSON.parse(m.content))}catch{}y!=null&&typeof y!="object"&&typeof y!="string"&&(y=String(y));let p={type:"tool_result",tool_use_id:m.tool_call_id,content:y};m.cache_control&&(p.cache_control=m.cache_control);let f=s[s.length-1];f&&f.role==="user"&&Array.isArray(f.content)?f.content.push(p):s.push({role:"user",content:[p]})}else if(m.role==="user"){let y=[];typeof m.content=="string"?y.push({type:"text",text:m.content}):Array.isArray(m.content)&&m.content.forEach(f=>{f&&typeof f=="object"&&f.type==="image_url"&&f.image_url?.url?y.push({type:"image",source:{type:"base64",media_type:f.media_type||"image/jpeg",data:f.image_url.url.split(",")[1]||f.image_url.url}}):y.push(f)});let p=s[s.length-1];p&&p.role==="user"&&Array.isArray(p.content)?p.content.push(...y):s.push({role:"user",content:y.length>0?y:[{type:"text",text:" "}]})}else if(m.role==="assistant"){let y=[];m.content&&(typeof m.content=="string"?y.push({type:"text",text:m.content}):Array.isArray(m.content)&&y.push(...m.content)),m.tool_calls&&m.tool_calls.length>0&&m.tool_calls.forEach(f=>{let _={};try{_=JSON.parse(f.function.arguments)}catch{_=f.function.arguments}y.push({type:"tool_use",id:f.id,name:f.function.name,input:_})}),m.thinking&&y.unshift({type:"thinking",thinking:m.thinking.content,signature:m.thinking.signature});let p=s[s.length-1];p&&p.role==="assistant"&&Array.isArray(p.content)?p.content.push(...y):s.push({role:"assistant",content:y.length>0?y:[{type:"text",text:" "}]})}}let i=()=>{let g=t.filter(m=>m?.cache_control).length;for(let m of s)Array.isArray(m.content)&&(g+=m.content.filter(y=>y?.cache_control).length);return g},l=g=>g&&typeof g=="object"?{...g}:{type:"ephemeral"},a=()=>{for(let g=s.length-1;g>=0;g--){let m=s[g]?.content;if(!Array.isArray(m))continue;let y=m.find(p=>p?.cache_control);if(y?.cache_control)return y.cache_control}for(let g=t.length-1;g>=0;g--)if(t[g]?.cache_control)return t[g].cache_control;return{type:"ephemeral"}},c=(g,m)=>{if(!Array.isArray(g?.content)||g.content.some(p=>p?.cache_control))return!1;let y=g.content.find(p=>p&&typeof p=="object"&&!p.cache_control);return y?(y.cache_control=l(m),!0):!1};(()=>{let g=4-i();if(g<=0||s.length===0)return;let m=s,y=a(),p=[];for(let f=m.length-1;f>=0;f--)m[f]?.role!=="user"||!Array.isArray(m[f].content)||p.push(f);for(let f of p){if(g<=0)break;c(m[f],y)&&g--}})();let d={messages:s,model:n.model,max_tokens:n.max_tokens||4096,temperature:n.temperature,stream:n.stream};if(t.length>0){let g=t.some(m=>m?.cache_control);d.system=g?t:t.map(m=>m.text||"").join(`
|
|
@@ -312,7 +312,7 @@ Stack: ${e.stack}`)}}async registerDefaultTransformersInternal(){try{Object.valu
|
|
|
312
312
|
${this.toMarkdown(r,t+1)}`:`${o}- ${r}`).join(`
|
|
313
313
|
`):typeof e=="object"&&e!==null?Object.entries(e).map(([r,s])=>typeof s=="object"&&s!==null?`${o}${r}:
|
|
314
314
|
${this.toMarkdown(s,t+1)}`:`${o}${r}: ${s}`).join(`
|
|
315
|
-
`):`${o}${e}`}async output(e,t={}){try{let o=this.formatData(e,t);switch(this.config.level||"log"){case"info":console.info(o);break;case"warn":console.warn(o);break;case"error":console.error(o);break;case"debug":console.debug(o);break;case"log":default:console.log(o);break}return!0}catch(o){return console.error("[ConsoleOutputHandler] Output failed:",o),!1}}}});var rt,No=w(()=>{"use strict";rt=class{type="webhook";config;defaultTimeout=3e4;constructor(e){if(!e.url)throw new Error("Webhook URL is required");this.config={method:"POST",retry:{maxAttempts:3,backoffMs:1e3},silent:!1,...e}}buildHeaders(){let e={"Content-Type":"application/json",...this.config.headers||{}};if(this.config.auth)switch(this.config.auth.type){case"bearer":this.config.auth.token&&(e.Authorization=`Bearer ${this.config.auth.token}`);break;case"basic":if(this.config.auth.username&&this.config.auth.password){let t=Buffer.from(`${this.config.auth.username}:${this.config.auth.password}`).toString("base64");e.Authorization=`Basic ${t}`}break;case"custom":this.config.auth.custom&&(e[this.config.auth.custom.header]=this.config.auth.custom.value);break}return e}buildBody(e,t){let{format:o="json",timestamp:r=!0,prefix:s,metadata:i}=t||{},l={data:e};return r&&(l.timestamp=new Date().toISOString()),s&&(l.prefix=s),i&&Object.keys(i).length>0&&(l.metadata=i),l}async sendRequest(e,t,o,r,s){let i=new AbortController,l=setTimeout(()=>i.abort(),s);try{let a=await fetch(e,{method:t,headers:o,body:JSON.stringify(r),signal:i.signal});if(clearTimeout(l),!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);return a}catch(a){throw clearTimeout(l),a}}delay(e){return new Promise(t=>setTimeout(t,e))}async sendWithRetry(e,t,o,r,s,i){let l=null;for(let a=1;a<=i.maxAttempts;a++)try{return await this.sendRequest(e,t,o,r,s)}catch(c){if(l=c,a===i.maxAttempts)break;let u=i.backoffMs*Math.pow(2,a-1);console.warn(`[WebhookOutputHandler] Request failed (attempt ${a}/${i.maxAttempts}), retrying in ${u}ms...`,c.message),await this.delay(u)}throw l}async output(e,t={}){let o=t.timeout||this.defaultTimeout;try{let r=this.buildHeaders(),s=this.buildBody(e,t),i=await this.sendWithRetry(this.config.url,this.config.method,r,s,o,this.config.retry);return!0}catch(r){let s=r instanceof Error?r.message:String(r);if(this.config.silent)return console.error(`[WebhookOutputHandler] Failed to send data: ${s}`),!1;throw new Error(`Webhook output failed: ${s}`)}}}});import{writeFileSync as al,existsSync as cl,mkdirSync as ll}from"fs";import{join as ei}from"path";import{tmpdir as ul}from"os";var st,Lo=w(()=>{"use strict";st=class{type="temp-file";config;baseDir;constructor(e={}){this.config={subdirectory:"claude-code-router",extension:"json",includeTimestamp:!1,prefix:"session",...e};let t=ul();this.baseDir=ei(t,this.config.subdirectory),this.ensureDir()}ensureDir(){try{cl(this.baseDir)||ll(this.baseDir,{recursive:!0})}catch{}}getFilePath(e){let t=this.config.prefix||"session",o=this.config.extension?`.${this.config.extension}`:"",r;if(this.config.includeTimestamp){let s=Date.now();r=`${t}-${e}-${s}${o}`}else r=`${t}-${e}${o}`;return ei(this.baseDir,r)}async output(e,t={}){try{let o=t.metadata?.sessionId;if(!o)return!1;let r={...e,timestamp:Date.now(),sessionId:o},s=this.getFilePath(o);return al(s,JSON.stringify(r,null,2),"utf-8"),!0}catch{return!1}}getBaseDir(){return this.baseDir}}});var Do,De,ti=w(()=>{"use strict";$o();No();Lo();Do=class{handlers=new Map;defaultOptions={};registerHandler(e,t){this.handlers.set(e,t)}registerHandlers(e){for(let t of e)if(t.enabled!==!1)try{let o=this.createHandler(t),r=t.type+"_"+Date.now();this.registerHandler(r,o)}catch(o){console.error(`[OutputManager] Failed to register ${t.type} handler:`,o)}}createHandler(e){switch(e.type){case"console":return new ot(e.config);case"webhook":return new rt(e.config);case"temp-file":return new st(e.config);default:throw new Error(`Unknown output handler type: ${e.type}`)}}unregisterHandler(e){return this.handlers.delete(e)}getHandler(e){return this.handlers.get(e)}getAllHandlers(){return new Map(this.handlers)}clearHandlers(){this.handlers.clear()}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}getDefaultOptions(){return{...this.defaultOptions}}async output(e,t){let o={...this.defaultOptions,...t},r={success:[],failed:[]},s=Array.from(this.handlers.entries()).map(async([i,l])=>{try{await l.output(e,o)?r.success.push(i):r.failed.push(i)}catch(a){console.error(`[OutputManager] Handler ${i} failed:`,a),r.failed.push(i)}});return await Promise.all(s),r}async outputTo(e,t,o){let r={...this.defaultOptions,...o},s={success:[],failed:[]},i=e.map(async l=>{let a=this.handlers.get(l);if(!a){console.warn(`[OutputManager] Handler ${l} not found`),s.failed.push(l);return}try{await a.output(t,r)?s.success.push(l):s.failed.push(l)}catch(c){console.error(`[OutputManager] Handler ${l} failed:`,c),s.failed.push(l)}});return await Promise.all(i),s}async outputToType(e,t,o){let r=Array.from(this.handlers.entries()).filter(([s,i])=>i.type===e).map(([s])=>s);return this.outputTo(r,t,o)}},De=new Do});var Fo=w(()=>{"use strict";Zs();$o();No();Lo();ti()});import dl from"fastify-plugin";function ni(n,e,t=0){if(n<=0)return 0;let o=Math.max((e-t)/1e3,pl);return Math.round(n/o)}function at(n){let e=(n.match(/[\u4e00-\u9fa5]/g)||[]).length,t=n.length-e;return Math.ceil(e/1.5+t/4)}async function oi(n,e,t,o=!1){let r=o?"[Token Speed Final]":"[Token Speed]",s={requestId:n.requestId.substring(0,8),sessionId:n.sessionId,stream:n.stream,tokenCount:n.tokenCount,tokensPerSecond:n.tokensPerSecond,timeToFirstToken:n.timeToFirstToken?`${n.timeToFirstToken}ms`:"N/A",duration:`${((n.lastTokenTime-n.startTime)/1e3).toFixed(2)}s`,timestamp:Date.now()},i={prefix:r,metadata:{sessionId:n.sessionId},...t};for(let l of e)try{await De.outputToType(l,s,i)}catch(a){console.error(`[TokenSpeedPlugin] Failed to output to ${l}:`,a)}}var it,Uo,pl,hn,ri=w(()=>{"use strict";Mo();Fo();Ve();it=new Map,Uo=new Map,pl=1,hn={name:"token-speed",version:"1.0.0",description:"Statistics for streaming response token generation speed",register:dl(async(n,e)=>{let t={reporter:["console","temp-file"],...e},o=Array.isArray(t.reporter)?t.reporter:[t.reporter];if(t.outputHandlers&&t.outputHandlers.length>0)De.registerHandlers(t.outputHandlers);else{let i=[];for(let l of o)l==="console"?i.push({type:"console",enabled:!0,config:{colors:!0,level:"log"}}):l==="temp-file"?i.push({type:"temp-file",enabled:!0,config:{subdirectory:"claude-code-router",extension:"json",includeTimestamp:!0,prefix:"session"}}):l==="webhook"&&console.warn("[TokenSpeedPlugin] Webhook reporter requires explicit configuration in outputHandlers");i.length>0&&De.registerHandlers(i)}t.outputOptions&&De.setDefaultOptions(t.outputOptions);let r=async i=>{let l=n.tokenizerService;if(!l)return n.log?.warn("TokenizerService not available"),null;if(!i.provider||!i.model)return null;let a=i.provider,c=i.model,u=`${a}:${c}`;if(Uo.has(u))return Uo.get(u);let d=l.getTokenizerConfigForModel(a,c);if(!d)return n.log?.debug(`No tokenizer config for ${a}:${c}, using fallback`),null;try{let g=await l.getTokenizer(d,a);return Uo.set(u,g),n.log?.info(`Created tokenizer for ${a}:${c} - ${g.name}`),g}catch(g){return n.log?.warn(`Failed to create tokenizer for ${a}:${c}: ${g.message}`),null}},s=i=>{let l=new URL(`http://127.0.0.1${i}`).pathname;return l.endsWith("/v1/messages")||l.endsWith("/v1/responses")};n.addHook("onRequest",async i=>{s(i.url)&&(i.requestStartTime=performance.now())}),n.addHook("onSend",async(i,l,a)=>{let c=i.requestStartTime;if(!c)return;let u=i.id||Date.now().toString(),d=i.usageSessionId;if(!d)try{d=Qe(i.body?.metadata?.user_id)}catch{}if(!d){let f=i.headers?.["x-request-id"],_=Array.isArray(f)?f[0]:f;d=(typeof _=="string"?_:void 0)||u}let g=await r(i);if(a instanceof ReadableStream){it.set(u,{requestId:u,sessionId:d,startTime:c,lastTokenTime:c,tokenCount:0,tokensPerSecond:0,stream:!0});let[f,_]=a.tee(),k=async()=>{let h=null,b=async T=>{let x=it.get(u);if(!x)return;let v=x.firstTokenTime?x.firstTokenTime-x.startTime:0,C=(T?x.lastTokenTime:performance.now())-x.startTime;x.tokensPerSecond=ni(x.tokenCount,C,v),await oi(x,o,t.outputOptions,T).catch(P=>{n.log?.warn(`Failed to output streaming stats: ${P.message}`)})};try{let x=_.pipeThrough(new TextDecoderStream).pipeThrough(new re).getReader();for(h=setInterval(async()=>{it.get(u)&&await b(!1)},1e3);;){let{done:v,value:S}=await x.read();if(v)break;let C=S,P=it.get(u);if(!P)continue;let R=performance.now(),O=C.event||C.data?.type,E=C.event==="content_block_start"||C.event==="content_block_delta"||C.event==="text_block"||C.event==="content_block"||O==="response.output_text.delta"||O==="response.function_call_arguments.delta"||O==="response.reasoning_summary_text.delta";!P.firstTokenTime&&E&&(P.firstTokenTime=R,P.timeToFirstToken=Math.round(R-P.startTime));let A="";if(C.event==="content_block_delta"&&C.data?.delta){let N=C.data.delta.type;N==="text_delta"?A=C.data.delta.text||"":N==="input_json_delta"?A=C.data.delta.partial_json||"":N==="thinking_delta"&&(A=C.data.delta.thinking||"")}if((O==="response.output_text.delta"||O==="response.function_call_arguments.delta"||O==="response.reasoning_summary_text.delta")&&(A=typeof C.data?.delta=="string"?C.data.delta:""),A){let N=g&&g.encodeText?g.encodeText(A).length:at(A);P.tokenCount+=N,P.lastTokenTime=R}(C.event==="message_stop"||O==="response.completed"||O==="response.failed")&&(h&&(clearInterval(h),h=null),await b(!0),it.delete(u))}}catch(T){h&&clearInterval(h),T.name!=="AbortError"&&T.code!=="ERR_STREAM_PREMATURE_CLOSE"&&n.log?.warn(`Error processing token stats: ${T.message}`)}};return i.tokenSpeedCapturePromise=k().catch(h=>{console.log(h),n.log?.warn(`Background stats processing failed: ${h.message}`)}),f}let m=performance.now(),y=0,p=!1;if(a&&typeof a=="string")try{let f=JSON.parse(a);if(typeof f.usage?.output_tokens=="number")y=f.usage.output_tokens,p=!0;else{let _=f.content??f.message?.content;if(_!==void 0)if(p=!0,g)Array.isArray(_)?y=_.reduce((k,h)=>{if(h.type==="text"){let b=h.text||"";return k+(g.encodeText?g.encodeText(b).length:at(b))}return k},0):typeof _=="string"&&(y=g.encodeText?g.encodeText(_).length:at(_));else{let k=Array.isArray(_)?_.map(h=>h.text).join(""):typeof _=="string"?_:"";y=at(k)}}}catch{}if(p){let f=Math.round(m-c),_=m-c,k={requestId:u,sessionId:d,startTime:c,lastTokenTime:m,tokenCount:y,tokensPerSecond:ni(y,_),timeToFirstToken:f,stream:!1};await oi(k,o,t.outputOptions,!0)}return a})})}});var jo=w(()=>{"use strict";Xs();qs();ri();Fo()});import X from"node:fs/promises";import si from"json5";import ye from"node:path";import{CONFIG_FILE as q,HOME_DIR as yn,PLUGINS_DIR as fl}from"@wengine-ai/claude-code-router-shared";function ii(){if(process.env.VITEST||process.env.CI)throw new Error("Config write attempted during test/CI. Set CCR_CONFIG_DIR to a temp dir to isolate.")}var Ho,ct,_n,zo,ne,kn,Fe,ml,Bo,bn=w(()=>{"use strict";Ho=n=>{if(typeof n=="string")return n.replace(/\$\{([^}]+)\}|\$([A-Z_][A-Z0-9_]*)/g,(e,t,o)=>{let r=t||o;return process.env[r]||e});if(Array.isArray(n))return n.map(Ho);if(n!==null&&typeof n=="object"){let e={};for(let[t,o]of Object.entries(n))e[t]=Ho(o);return e}return n},ct=async n=>{try{await X.access(n)}catch{await X.mkdir(n,{recursive:!0})}},_n=async()=>{await ct(yn),await ct(fl),await ct(ye.join(yn,"logs"))},zo=async()=>{let n=await X.readFile(q,"utf-8");return si.parse(n)},ne=async()=>{try{let n=await X.readFile(q,"utf-8");try{let e=si.parse(n);return Ho(e)}catch(e){console.error(`Failed to parse config file at ${q}`),console.error("Error details:",e.message),console.error("Please check your config file syntax."),process.exit(1)}}catch(n){if(n.code==="ENOENT")try{await _n();let e=await kn();e&&console.log(`Backed up existing configuration file to ${e}`);let t={PORT:3456,Providers:[],Router:{}};return await Fe(t),console.log("Created minimal default configuration file at ~/.claude-code-router/config.json"),console.log("Please edit this file with your actual configuration."),t}catch(e){console.error("Failed to create default configuration:",e.message),process.exit(1)}else console.error(`Failed to read config file at ${q}`),console.error("Error details:",n.message),process.exit(1)}};kn=async()=>{ii();try{if(await X.access(q).then(()=>!0).catch(()=>!1)){let n=new Date().toISOString().replace(/[:.]/g,"-"),e=`${q}.${n}.bak`;await X.copyFile(q,e);try{let t=ye.dirname(q),o=ye.basename(q),s=(await X.readdir(t)).filter(i=>i.startsWith(o)&&i.endsWith(".bak")).sort().reverse();if(s.length>3)for(let i=3;i<s.length;i++){let l=ye.join(t,s[i]);await X.unlink(l)}}catch(t){console.warn("Failed to clean up old backups:",t)}return e}}catch(n){console.error("Failed to backup config file:",n)}return null},Fe=async n=>{ii(),await ct(yn),await ml();let e=`${JSON.stringify(n,null,2)}`;await X.writeFile(q,e)},ml=async()=>{if(!await X.access(q).then(()=>!0).catch(()=>!1))return;let e=ye.join(yn,"config-history");await ct(e);let t=new Date().toISOString().replace(/[:.]/g,"-"),o=ye.join(e,`config-${t}.json`);await X.copyFile(q,o);try{let s=(await X.readdir(e)).filter(i=>i.startsWith("config-")&&i.endsWith(".json")).sort().reverse();if(s.length>50)for(let i of s.slice(50))await X.unlink(ye.join(e,i))}catch(r){console.warn("Failed to prune config-history:",r)}},Bo=async()=>{let n=await ne();return Object.assign(process.env,n),n}});function gl(n){return n?.cache_read_input_tokens??n?.input_tokens_details?.cached_tokens??n?.prompt_tokens_details?.cached_tokens??0}function hl(n){return n?.cache_creation_input_tokens??n?.input_tokens_details?.cache_creation_tokens??n?.input_tokens_details?.cache_write_tokens??n?.prompt_tokens_details?.cache_creation_tokens??n?.prompt_tokens_details?.cache_write_tokens??0}function Ue(n){if(!(!n||typeof n!="object"))return{...n,input_tokens:n.input_tokens??n.prompt_tokens??0,output_tokens:n.output_tokens??n.completion_tokens??0,cache_read_input_tokens:gl(n),cache_creation_input_tokens:hl(n)}}function Tn(n,e,t){let o=t?{}:n||{},r=e||{};return{...o,input_tokens:r.input_tokens||o.input_tokens||0,output_tokens:r.output_tokens||o.output_tokens||0,cache_read_input_tokens:r.cache_read_input_tokens||o.cache_read_input_tokens||0,cache_creation_input_tokens:r.cache_creation_input_tokens||o.cache_creation_input_tokens||0}}var Jo=w(()=>{"use strict"});function Cn(n,e,t){if(n){if(typeof n=="string"){let o=n.indexOf(",");if(o>0){let r=n.slice(0,o).trim(),s=n.slice(o+1).trim();r&&s&&e.has(r)&&t.add(Wo(r,s))}return}if(Array.isArray(n)){for(let o of n)Cn(o,e,t);return}if(typeof n=="object")for(let o of Object.values(n))Cn(o,e,t)}}function ai(n){let e=n?.Providers||n?.providers||[],t=new Set,o=new Set;for(let r of e){let s=r?.name;if(!s)continue;t.add(s);let i=Array.isArray(r?.models)?r.models:[];for(let l of i)l&&o.add(Wo(s,l))}return Cn(n?.Router,t,o),Cn(n?.fallback,t,o),o}function lt(n,e){try{let t=F();if(!t?.getAllStates||!t?.recover)return 0;let o=ai(n),r=0;for(let s of t.getAllStates()||[]){let i=s?.provider,l=s?.model;!i||!l||o.has(Wo(i,l))||(t.recover(i,l),r++)}return r>0&&e?.info?.(`[health-reconcile] Pruned ${r} orphaned provider-health entr${r===1?"y":"ies"}`),r}catch(t){return e?.warn?.(`[health-reconcile] Failed to reconcile health store: ${t?.message||t}`),0}}function vn(n,e){try{if(!n)return 0;let t=F();if(!t?.getAllStates||!t?.recover)return 0;let o=0;for(let r of t.getAllStates()||[])r?.provider===n&&r?.model&&(t.recover(n,r.model),o++);return o>0&&e?.info?.(`[health-reconcile] Cleared ${o} health entr${o===1?"y":"ies"} for probed provider ${n}`),o}catch(t){return e?.warn?.(`[health-reconcile] Failed to clear provider health for ${n}: ${t?.message||t}`),0}}var yl,Wo,xn=w(()=>{"use strict";ee();yl="\0",Wo=(n,e)=>`${n}${yl}${e}`});function _l(n){return/\[1m\]/i.test(n)?1e6:2e5}function kl(n){let e=n.toLowerCase();return e.includes("haiku")||e.includes("mini")?8192:32e3}function bl(n,e=n){let t=_l(n),o=kl(n);return{type:"model",id:n,display_name:e,created_at:"2024-01-01T00:00:00Z",context_window:t,contextWindow:t,max_input_tokens:t,maxInputTokens:t,max_tokens:o,maxTokens:o,max_output_tokens:o,maxOutputTokens:o,capabilities:{context_window:t,contextWindow:t,max_input_tokens:t,maxInputTokens:t,max_tokens:o,maxTokens:o,max_output_tokens:o,maxOutputTokens:o}}}function Sn(n){let e=new Map,t=(o,r=o)=>{!o||e.has(o)||e.set(o,bl(o,r))};t("ccr-opus","CCR Opus"),t("ccr-sonnet","CCR Sonnet"),t("ccr-haiku","CCR Haiku"),t("ccr-opus[1m]","CCR Opus 1M"),t("ccr-sonnet[1m]","CCR Sonnet 1M"),t("ccr-haiku[1m]","CCR Haiku 1M");for(let o of n.Providers||n.providers||[])if(!(!o?.name||!Array.isArray(o.models)))for(let r of o.models)typeof r!="string"||!r||(t(r,r),t(`${o.name},${r}`,`${o.name}/${r}`));return Array.from(e.values())}var Go=w(()=>{"use strict"});function Tl(n){let e=n.ip||n.connection?.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}var Rn,Ko=w(()=>{"use strict";Rn=n=>async(e,t,o)=>{if(["/","/health"].includes(e.url)||e.url.startsWith("/ui")||Tl(e))return o();let s=n.Providers||n.providers||[];if(!s||s.length===0)return o();let i=n.APIKEY;if(!i){let u=[`http://127.0.0.1:${n.PORT||3456}`,`http://localhost:${n.PORT||3456}`];if(e.headers.origin&&!u.includes(e.headers.origin)){t.status(403).send("CORS not allowed for this origin");return}else t.header("Access-Control-Allow-Origin",`http://127.0.0.1:${n.PORT||3456}`),t.header("Access-Control-Allow-Origin",`http://localhost:${n.PORT||3456}`);return o()}let l=e.headers.authorization||e.headers["x-api-key"],a=Array.isArray(l)?l[0]:l||"";if(!a){t.log.warn({url:e.url,headers:Object.keys(e.headers)},"[AUTH] No auth header"),t.status(401).send("APIKEY is missing");return}let c="";if(a.startsWith("Bearer")?c=a.split(" ")[1]:c=a,c!==i){t.log.warn({url:e.url,gotPrefix:c.slice(0,10),gotSuffix:c.slice(-6),gotLen:c.length,expectedPrefix:i.slice(0,6),expectedSuffix:i.slice(-6),expectedLen:i.length},"[AUTH] Key mismatch"),t.status(401).send("Invalid API key");return}o()}});var gi={};Nn(gi,{append:()=>ft,clear:()=>Zo,close:()=>zl,getOldestRecordTimestamp:()=>Bl,query:()=>qo,querySummary:()=>mt,readTokenSpeedStats:()=>er});import{existsSync as Yo,mkdirSync as Cl,readFileSync as Vo,readdirSync as vl}from"fs";import{join as He}from"path";import{homedir as xl,tmpdir as Sl}from"os";import Rl from"better-sqlite3";function Al(){Yo(Pn)||Cl(Pn,{recursive:!0})}function pt(){if(pe)return pe;Al();let n=new Rl(wl);n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL"),n.pragma("busy_timeout = 5000");let e=n.pragma("user_version",{simple:!0})||0;return e<1&&(Il(n),n.pragma("user_version = 1")),e<2&&(n.prepare("PRAGMA table_info(usage_records)").all().some(o=>o.name==="upstream_model")||n.exec("ALTER TABLE usage_records ADD COLUMN upstream_model TEXT"),n.pragma("user_version = 2")),$l(n),pi(n,!0),Xo=n.prepare(`
|
|
315
|
+
`):`${o}${e}`}async output(e,t={}){try{let o=this.formatData(e,t);switch(this.config.level||"log"){case"info":console.info(o);break;case"warn":console.warn(o);break;case"error":console.error(o);break;case"debug":console.debug(o);break;case"log":default:console.log(o);break}return!0}catch(o){return console.error("[ConsoleOutputHandler] Output failed:",o),!1}}}});var rt,No=w(()=>{"use strict";rt=class{type="webhook";config;defaultTimeout=3e4;constructor(e){if(!e.url)throw new Error("Webhook URL is required");this.config={method:"POST",retry:{maxAttempts:3,backoffMs:1e3},silent:!1,...e}}buildHeaders(){let e={"Content-Type":"application/json",...this.config.headers||{}};if(this.config.auth)switch(this.config.auth.type){case"bearer":this.config.auth.token&&(e.Authorization=`Bearer ${this.config.auth.token}`);break;case"basic":if(this.config.auth.username&&this.config.auth.password){let t=Buffer.from(`${this.config.auth.username}:${this.config.auth.password}`).toString("base64");e.Authorization=`Basic ${t}`}break;case"custom":this.config.auth.custom&&(e[this.config.auth.custom.header]=this.config.auth.custom.value);break}return e}buildBody(e,t){let{format:o="json",timestamp:r=!0,prefix:s,metadata:i}=t||{},l={data:e};return r&&(l.timestamp=new Date().toISOString()),s&&(l.prefix=s),i&&Object.keys(i).length>0&&(l.metadata=i),l}async sendRequest(e,t,o,r,s){let i=new AbortController,l=setTimeout(()=>i.abort(),s);try{let a=await fetch(e,{method:t,headers:o,body:JSON.stringify(r),signal:i.signal});if(clearTimeout(l),!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);return a}catch(a){throw clearTimeout(l),a}}delay(e){return new Promise(t=>setTimeout(t,e))}async sendWithRetry(e,t,o,r,s,i){let l=null;for(let a=1;a<=i.maxAttempts;a++)try{return await this.sendRequest(e,t,o,r,s)}catch(c){if(l=c,a===i.maxAttempts)break;let u=i.backoffMs*Math.pow(2,a-1);console.warn(`[WebhookOutputHandler] Request failed (attempt ${a}/${i.maxAttempts}), retrying in ${u}ms...`,c.message),await this.delay(u)}throw l}async output(e,t={}){let o=t.timeout||this.defaultTimeout;try{let r=this.buildHeaders(),s=this.buildBody(e,t),i=await this.sendWithRetry(this.config.url,this.config.method,r,s,o,this.config.retry);return!0}catch(r){let s=r instanceof Error?r.message:String(r);if(this.config.silent)return console.error(`[WebhookOutputHandler] Failed to send data: ${s}`),!1;throw new Error(`Webhook output failed: ${s}`)}}}});import{writeFileSync as al,existsSync as cl,mkdirSync as ll}from"fs";import{join as ei}from"path";import{tmpdir as ul}from"os";var st,Lo=w(()=>{"use strict";st=class{type="temp-file";config;baseDir;constructor(e={}){this.config={subdirectory:"claude-code-router",extension:"json",includeTimestamp:!1,prefix:"session",...e};let t=ul();this.baseDir=ei(t,this.config.subdirectory),this.ensureDir()}ensureDir(){try{cl(this.baseDir)||ll(this.baseDir,{recursive:!0})}catch{}}getFilePath(e){let t=this.config.prefix||"session",o=this.config.extension?`.${this.config.extension}`:"",r;if(this.config.includeTimestamp){let s=Date.now();r=`${t}-${e}-${s}${o}`}else r=`${t}-${e}${o}`;return ei(this.baseDir,r)}async output(e,t={}){try{let o=t.metadata?.sessionId;if(!o)return!1;let r={...e,timestamp:Date.now(),sessionId:o},s=this.getFilePath(o);return al(s,JSON.stringify(r,null,2),"utf-8"),!0}catch{return!1}}getBaseDir(){return this.baseDir}}});var Do,De,ti=w(()=>{"use strict";$o();No();Lo();Do=class{handlers=new Map;defaultOptions={};registerHandler(e,t){this.handlers.set(e,t)}registerHandlers(e){for(let t of e)if(t.enabled!==!1)try{let o=this.createHandler(t),r=t.type+"_"+Date.now();this.registerHandler(r,o)}catch(o){console.error(`[OutputManager] Failed to register ${t.type} handler:`,o)}}createHandler(e){switch(e.type){case"console":return new ot(e.config);case"webhook":return new rt(e.config);case"temp-file":return new st(e.config);default:throw new Error(`Unknown output handler type: ${e.type}`)}}unregisterHandler(e){return this.handlers.delete(e)}getHandler(e){return this.handlers.get(e)}getAllHandlers(){return new Map(this.handlers)}clearHandlers(){this.handlers.clear()}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}getDefaultOptions(){return{...this.defaultOptions}}async output(e,t){let o={...this.defaultOptions,...t},r={success:[],failed:[]},s=Array.from(this.handlers.entries()).map(async([i,l])=>{try{await l.output(e,o)?r.success.push(i):r.failed.push(i)}catch(a){console.error(`[OutputManager] Handler ${i} failed:`,a),r.failed.push(i)}});return await Promise.all(s),r}async outputTo(e,t,o){let r={...this.defaultOptions,...o},s={success:[],failed:[]},i=e.map(async l=>{let a=this.handlers.get(l);if(!a){console.warn(`[OutputManager] Handler ${l} not found`),s.failed.push(l);return}try{await a.output(t,r)?s.success.push(l):s.failed.push(l)}catch(c){console.error(`[OutputManager] Handler ${l} failed:`,c),s.failed.push(l)}});return await Promise.all(i),s}async outputToType(e,t,o){let r=Array.from(this.handlers.entries()).filter(([s,i])=>i.type===e).map(([s])=>s);return this.outputTo(r,t,o)}},De=new Do});var Fo=w(()=>{"use strict";Zs();$o();No();Lo();ti()});import dl from"fastify-plugin";function ni(n,e,t=0){if(n<=0)return 0;let o=Math.max((e-t)/1e3,pl);return Math.round(n/o)}function at(n){let e=(n.match(/[\u4e00-\u9fa5]/g)||[]).length,t=n.length-e;return Math.ceil(e/1.5+t/4)}async function oi(n,e,t,o=!1){let r=o?"[Token Speed Final]":"[Token Speed]",s={requestId:n.requestId.substring(0,8),sessionId:n.sessionId,stream:n.stream,tokenCount:n.tokenCount,tokensPerSecond:n.tokensPerSecond,timeToFirstToken:n.timeToFirstToken?`${n.timeToFirstToken}ms`:"N/A",duration:`${((n.lastTokenTime-n.startTime)/1e3).toFixed(2)}s`,timestamp:Date.now()},i={prefix:r,metadata:{sessionId:n.sessionId},...t};for(let l of e)try{await De.outputToType(l,s,i)}catch(a){console.error(`[TokenSpeedPlugin] Failed to output to ${l}:`,a)}}var it,Uo,pl,hn,ri=w(()=>{"use strict";Mo();Fo();Ve();it=new Map,Uo=new Map,pl=1,hn={name:"token-speed",version:"1.0.0",description:"Statistics for streaming response token generation speed",register:dl(async(n,e)=>{let t={reporter:["console","temp-file"],...e},o=Array.isArray(t.reporter)?t.reporter:[t.reporter];if(t.outputHandlers&&t.outputHandlers.length>0)De.registerHandlers(t.outputHandlers);else{let i=[];for(let l of o)l==="console"?i.push({type:"console",enabled:!0,config:{colors:!0,level:"log"}}):l==="temp-file"?i.push({type:"temp-file",enabled:!0,config:{subdirectory:"claude-code-router",extension:"json",includeTimestamp:!0,prefix:"session"}}):l==="webhook"&&console.warn("[TokenSpeedPlugin] Webhook reporter requires explicit configuration in outputHandlers");i.length>0&&De.registerHandlers(i)}t.outputOptions&&De.setDefaultOptions(t.outputOptions);let r=async i=>{let l=n.tokenizerService;if(!l)return n.log?.warn("TokenizerService not available"),null;if(!i.provider||!i.model)return null;let a=i.provider,c=i.model,u=`${a}:${c}`;if(Uo.has(u))return Uo.get(u);let d=l.getTokenizerConfigForModel(a,c);if(!d)return n.log?.debug(`No tokenizer config for ${a}:${c}, using fallback`),null;try{let g=await l.getTokenizer(d,a);return Uo.set(u,g),n.log?.info(`Created tokenizer for ${a}:${c} - ${g.name}`),g}catch(g){return n.log?.warn(`Failed to create tokenizer for ${a}:${c}: ${g.message}`),null}},s=i=>{let l=new URL(`http://127.0.0.1${i}`).pathname;return l.endsWith("/v1/messages")||l.endsWith("/v1/responses")};n.addHook("onRequest",async i=>{s(i.url)&&(i.requestStartTime=performance.now())}),n.addHook("onSend",async(i,l,a)=>{let c=i.requestStartTime;if(!c)return;let u=i.id||Date.now().toString(),d=i.usageSessionId;if(!d)try{d=Qe(i.body?.metadata?.user_id)}catch{}if(!d){let f=i.headers?.["x-request-id"],_=Array.isArray(f)?f[0]:f;d=(typeof _=="string"?_:void 0)||u}let g=await r(i);if(a instanceof ReadableStream){it.set(u,{requestId:u,sessionId:d,startTime:c,lastTokenTime:c,tokenCount:0,tokensPerSecond:0,stream:!0});let[f,_]=a.tee(),k=async()=>{let h=null,b=async T=>{let x=it.get(u);if(!x)return;let v=x.firstTokenTime?x.firstTokenTime-x.startTime:0,C=(T?x.lastTokenTime:performance.now())-x.startTime;x.tokensPerSecond=ni(x.tokenCount,C,v),await oi(x,o,t.outputOptions,T).catch(P=>{n.log?.warn(`Failed to output streaming stats: ${P.message}`)})};try{let x=_.pipeThrough(new TextDecoderStream).pipeThrough(new re).getReader();for(h=setInterval(async()=>{it.get(u)&&await b(!1)},1e3);;){let{done:v,value:S}=await x.read();if(v)break;let C=S,P=it.get(u);if(!P)continue;let R=performance.now(),O=C.event||C.data?.type,E=C.event==="content_block_start"||C.event==="content_block_delta"||C.event==="text_block"||C.event==="content_block"||O==="response.output_text.delta"||O==="response.function_call_arguments.delta"||O==="response.reasoning_summary_text.delta";!P.firstTokenTime&&E&&(P.firstTokenTime=R,P.timeToFirstToken=Math.round(R-P.startTime));let A="";if(C.event==="content_block_delta"&&C.data?.delta){let N=C.data.delta.type;N==="text_delta"?A=C.data.delta.text||"":N==="input_json_delta"?A=C.data.delta.partial_json||"":N==="thinking_delta"&&(A=C.data.delta.thinking||"")}if((O==="response.output_text.delta"||O==="response.function_call_arguments.delta"||O==="response.reasoning_summary_text.delta")&&(A=typeof C.data?.delta=="string"?C.data.delta:""),A){let N=g&&g.encodeText?g.encodeText(A).length:at(A);P.tokenCount+=N,P.lastTokenTime=R}(C.event==="message_stop"||O==="response.completed"||O==="response.failed")&&(h&&(clearInterval(h),h=null),await b(!0),it.delete(u))}}catch(T){h&&clearInterval(h),T.name!=="AbortError"&&T.code!=="ERR_STREAM_PREMATURE_CLOSE"&&n.log?.warn(`Error processing token stats: ${T.message}`)}};return i.tokenSpeedCapturePromise=k().catch(h=>{console.log(h),n.log?.warn(`Background stats processing failed: ${h.message}`)}),f}let m=performance.now(),y=0,p=!1;if(a&&typeof a=="string")try{let f=JSON.parse(a);if(typeof f.usage?.output_tokens=="number")y=f.usage.output_tokens,p=!0;else{let _=f.content??f.message?.content;if(_!==void 0)if(p=!0,g)Array.isArray(_)?y=_.reduce((k,h)=>{if(h.type==="text"){let b=h.text||"";return k+(g.encodeText?g.encodeText(b).length:at(b))}return k},0):typeof _=="string"&&(y=g.encodeText?g.encodeText(_).length:at(_));else{let k=Array.isArray(_)?_.map(h=>h.text).join(""):typeof _=="string"?_:"";y=at(k)}}}catch{}if(p){let f=m-c,_={requestId:u,sessionId:d,startTime:c,lastTokenTime:m,tokenCount:y,tokensPerSecond:ni(y,f),stream:!1};await oi(_,o,t.outputOptions,!0)}return a})})}});var jo=w(()=>{"use strict";Xs();qs();ri();Fo()});import X from"node:fs/promises";import si from"json5";import ye from"node:path";import{CONFIG_FILE as q,HOME_DIR as yn,PLUGINS_DIR as fl}from"@wengine-ai/claude-code-router-shared";function ii(){if(process.env.VITEST||process.env.CI)throw new Error("Config write attempted during test/CI. Set CCR_CONFIG_DIR to a temp dir to isolate.")}var Ho,ct,_n,zo,ne,kn,Fe,ml,Bo,bn=w(()=>{"use strict";Ho=n=>{if(typeof n=="string")return n.replace(/\$\{([^}]+)\}|\$([A-Z_][A-Z0-9_]*)/g,(e,t,o)=>{let r=t||o;return process.env[r]||e});if(Array.isArray(n))return n.map(Ho);if(n!==null&&typeof n=="object"){let e={};for(let[t,o]of Object.entries(n))e[t]=Ho(o);return e}return n},ct=async n=>{try{await X.access(n)}catch{await X.mkdir(n,{recursive:!0})}},_n=async()=>{await ct(yn),await ct(fl),await ct(ye.join(yn,"logs"))},zo=async()=>{let n=await X.readFile(q,"utf-8");return si.parse(n)},ne=async()=>{try{let n=await X.readFile(q,"utf-8");try{let e=si.parse(n);return Ho(e)}catch(e){console.error(`Failed to parse config file at ${q}`),console.error("Error details:",e.message),console.error("Please check your config file syntax."),process.exit(1)}}catch(n){if(n.code==="ENOENT")try{await _n();let e=await kn();e&&console.log(`Backed up existing configuration file to ${e}`);let t={PORT:3456,Providers:[],Router:{}};return await Fe(t),console.log("Created minimal default configuration file at ~/.claude-code-router/config.json"),console.log("Please edit this file with your actual configuration."),t}catch(e){console.error("Failed to create default configuration:",e.message),process.exit(1)}else console.error(`Failed to read config file at ${q}`),console.error("Error details:",n.message),process.exit(1)}};kn=async()=>{ii();try{if(await X.access(q).then(()=>!0).catch(()=>!1)){let n=new Date().toISOString().replace(/[:.]/g,"-"),e=`${q}.${n}.bak`;await X.copyFile(q,e);try{let t=ye.dirname(q),o=ye.basename(q),s=(await X.readdir(t)).filter(i=>i.startsWith(o)&&i.endsWith(".bak")).sort().reverse();if(s.length>3)for(let i=3;i<s.length;i++){let l=ye.join(t,s[i]);await X.unlink(l)}}catch(t){console.warn("Failed to clean up old backups:",t)}return e}}catch(n){console.error("Failed to backup config file:",n)}return null},Fe=async n=>{ii(),await ct(yn),await ml();let e=`${JSON.stringify(n,null,2)}`;await X.writeFile(q,e)},ml=async()=>{if(!await X.access(q).then(()=>!0).catch(()=>!1))return;let e=ye.join(yn,"config-history");await ct(e);let t=new Date().toISOString().replace(/[:.]/g,"-"),o=ye.join(e,`config-${t}.json`);await X.copyFile(q,o);try{let s=(await X.readdir(e)).filter(i=>i.startsWith("config-")&&i.endsWith(".json")).sort().reverse();if(s.length>50)for(let i of s.slice(50))await X.unlink(ye.join(e,i))}catch(r){console.warn("Failed to prune config-history:",r)}},Bo=async()=>{let n=await ne();return Object.assign(process.env,n),n}});function gl(n){return n?.cache_read_input_tokens??n?.input_tokens_details?.cached_tokens??n?.prompt_tokens_details?.cached_tokens??0}function hl(n){return n?.cache_creation_input_tokens??n?.input_tokens_details?.cache_creation_tokens??n?.input_tokens_details?.cache_write_tokens??n?.prompt_tokens_details?.cache_creation_tokens??n?.prompt_tokens_details?.cache_write_tokens??0}function Ue(n){if(!(!n||typeof n!="object"))return{...n,input_tokens:n.input_tokens??n.prompt_tokens??0,output_tokens:n.output_tokens??n.completion_tokens??0,cache_read_input_tokens:gl(n),cache_creation_input_tokens:hl(n)}}function Tn(n,e,t){let o=t?{}:n||{},r=e||{};return{...o,input_tokens:r.input_tokens||o.input_tokens||0,output_tokens:r.output_tokens||o.output_tokens||0,cache_read_input_tokens:r.cache_read_input_tokens||o.cache_read_input_tokens||0,cache_creation_input_tokens:r.cache_creation_input_tokens||o.cache_creation_input_tokens||0}}var Jo=w(()=>{"use strict"});function Cn(n,e,t){if(n){if(typeof n=="string"){let o=n.indexOf(",");if(o>0){let r=n.slice(0,o).trim(),s=n.slice(o+1).trim();r&&s&&e.has(r)&&t.add(Wo(r,s))}return}if(Array.isArray(n)){for(let o of n)Cn(o,e,t);return}if(typeof n=="object")for(let o of Object.values(n))Cn(o,e,t)}}function ai(n){let e=n?.Providers||n?.providers||[],t=new Set,o=new Set;for(let r of e){let s=r?.name;if(!s)continue;t.add(s);let i=Array.isArray(r?.models)?r.models:[];for(let l of i)l&&o.add(Wo(s,l))}return Cn(n?.Router,t,o),Cn(n?.fallback,t,o),o}function lt(n,e){try{let t=F();if(!t?.getAllStates||!t?.recover)return 0;let o=ai(n),r=0;for(let s of t.getAllStates()||[]){let i=s?.provider,l=s?.model;!i||!l||o.has(Wo(i,l))||(t.recover(i,l),r++)}return r>0&&e?.info?.(`[health-reconcile] Pruned ${r} orphaned provider-health entr${r===1?"y":"ies"}`),r}catch(t){return e?.warn?.(`[health-reconcile] Failed to reconcile health store: ${t?.message||t}`),0}}function vn(n,e){try{if(!n)return 0;let t=F();if(!t?.getAllStates||!t?.recover)return 0;let o=0;for(let r of t.getAllStates()||[])r?.provider===n&&r?.model&&(t.recover(n,r.model),o++);return o>0&&e?.info?.(`[health-reconcile] Cleared ${o} health entr${o===1?"y":"ies"} for probed provider ${n}`),o}catch(t){return e?.warn?.(`[health-reconcile] Failed to clear provider health for ${n}: ${t?.message||t}`),0}}var yl,Wo,xn=w(()=>{"use strict";ee();yl="\0",Wo=(n,e)=>`${n}${yl}${e}`});function _l(n){return/\[1m\]/i.test(n)?1e6:2e5}function kl(n){let e=n.toLowerCase();return e.includes("haiku")||e.includes("mini")?8192:32e3}function bl(n,e=n){let t=_l(n),o=kl(n);return{type:"model",id:n,display_name:e,created_at:"2024-01-01T00:00:00Z",context_window:t,contextWindow:t,max_input_tokens:t,maxInputTokens:t,max_tokens:o,maxTokens:o,max_output_tokens:o,maxOutputTokens:o,capabilities:{context_window:t,contextWindow:t,max_input_tokens:t,maxInputTokens:t,max_tokens:o,maxTokens:o,max_output_tokens:o,maxOutputTokens:o}}}function Sn(n){let e=new Map,t=(o,r=o)=>{!o||e.has(o)||e.set(o,bl(o,r))};t("ccr-opus","CCR Opus"),t("ccr-sonnet","CCR Sonnet"),t("ccr-haiku","CCR Haiku"),t("ccr-opus[1m]","CCR Opus 1M"),t("ccr-sonnet[1m]","CCR Sonnet 1M"),t("ccr-haiku[1m]","CCR Haiku 1M");for(let o of n.Providers||n.providers||[])if(!(!o?.name||!Array.isArray(o.models)))for(let r of o.models)typeof r!="string"||!r||(t(r,r),t(`${o.name},${r}`,`${o.name}/${r}`));return Array.from(e.values())}var Go=w(()=>{"use strict"});function Tl(n){let e=n.ip||n.connection?.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}var Rn,Ko=w(()=>{"use strict";Rn=n=>async(e,t,o)=>{if(["/","/health"].includes(e.url)||e.url.startsWith("/ui")||Tl(e))return o();let s=n.Providers||n.providers||[];if(!s||s.length===0)return o();let i=n.APIKEY;if(!i){let u=[`http://127.0.0.1:${n.PORT||3456}`,`http://localhost:${n.PORT||3456}`];if(e.headers.origin&&!u.includes(e.headers.origin)){t.status(403).send("CORS not allowed for this origin");return}else t.header("Access-Control-Allow-Origin",`http://127.0.0.1:${n.PORT||3456}`),t.header("Access-Control-Allow-Origin",`http://localhost:${n.PORT||3456}`);return o()}let l=e.headers.authorization||e.headers["x-api-key"],a=Array.isArray(l)?l[0]:l||"";if(!a){t.log.warn({url:e.url,headers:Object.keys(e.headers)},"[AUTH] No auth header"),t.status(401).send("APIKEY is missing");return}let c="";if(a.startsWith("Bearer")?c=a.split(" ")[1]:c=a,c!==i){t.log.warn({url:e.url,gotPrefix:c.slice(0,10),gotSuffix:c.slice(-6),gotLen:c.length,expectedPrefix:i.slice(0,6),expectedSuffix:i.slice(-6),expectedLen:i.length},"[AUTH] Key mismatch"),t.status(401).send("Invalid API key");return}o()}});var gi={};Nn(gi,{append:()=>ft,clear:()=>Zo,close:()=>zl,getOldestRecordTimestamp:()=>Bl,query:()=>qo,querySummary:()=>mt,readTokenSpeedStats:()=>er});import{existsSync as Yo,mkdirSync as Cl,readFileSync as Vo,readdirSync as vl}from"fs";import{join as He}from"path";import{homedir as xl,tmpdir as Sl}from"os";import Rl from"better-sqlite3";function Al(){Yo(Pn)||Cl(Pn,{recursive:!0})}function pt(){if(pe)return pe;Al();let n=new Rl(wl);n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL"),n.pragma("busy_timeout = 5000");let e=n.pragma("user_version",{simple:!0})||0;return e<1&&(Il(n),n.pragma("user_version = 1")),e<2&&(n.prepare("PRAGMA table_info(usage_records)").all().some(o=>o.name==="upstream_model")||n.exec("ALTER TABLE usage_records ADD COLUMN upstream_model TEXT"),n.pragma("user_version = 2")),$l(n),pi(n,!0),Xo=n.prepare(`
|
|
316
316
|
INSERT INTO usage_records (
|
|
317
317
|
id, timestamp, session_id, provider, original_model, model, upstream_model, model_family,
|
|
318
318
|
scenario_type, client_type,
|
|
@@ -382,7 +382,7 @@ ${this.toMarkdown(s,t+1)}`:`${o}${r}: ${s}`).join(`
|
|
|
382
382
|
@cache_read_input_tokens, @cache_creation_input_tokens, @ttft,
|
|
383
383
|
@tokens_per_second, @duration_ms, @status, @error_message, @response_body
|
|
384
384
|
)
|
|
385
|
-
`)}function Dl(n,e,t){if(n<=0||e==null||!Number.isFinite(e))return null;let o=t!=null&&Number.isFinite(t)?t:0,r=Math.max((e-o)/1e3,Pl);return Math.round(n/r)}function En(n){let e=Number(n.outputTokens)||0,t=Number(n.durationMs),o=Number.isFinite(t)?t:null,r=_e(n.ttft);return{...n,ttft:r,tokensPerSecond:Dl(e,o,r)}}function de(n){return typeof n=="string"?n:n==null?"":String(n)}function wn(n){if(n==null)return;let e=String(n);return e.length>0?e:void 0}function dt(n){let e=Number(n);return Number.isFinite(e)?e:0}function ui(n){return n==="success"?"success":"error"}function di(n){let e=En(n);return{id:de(e.id),timestamp:de(e.timestamp),session_id:de(e.sessionId),provider:de(e.provider),original_model:de(e.originalModel),model:de(e.model),upstream_model:wn(e.upstreamModel)??null,model_family:de(e.modelFamily),scenario_type:de(e.scenarioType),client_type:wn(e.clientType)??null,stream:e.stream?1:0,input_tokens:Math.trunc(dt(e.inputTokens)),output_tokens:Math.trunc(dt(e.outputTokens)),cache_read_input_tokens:Math.trunc(dt(e.cacheReadInputTokens)),cache_creation_input_tokens:Math.trunc(dt(e.cacheCreationInputTokens)),ttft:_e(e.ttft),tokens_per_second:_e(e.tokensPerSecond),duration_ms:Math.trunc(dt(e.durationMs)),status:ui(e.status),error_message:wn(e.errorMessage)??null,response_body:wn(e.responseBody)??null}}function Fl(n){return En({id:n.id,timestamp:n.timestamp,sessionId:n.session_id,provider:n.provider,originalModel:n.original_model,model:n.model,upstreamModel:n.upstream_model??void 0,modelFamily:n.model_family,scenarioType:n.scenario_type,clientType:n.client_type??void 0,stream:n.stream===1,inputTokens:n.input_tokens,outputTokens:n.output_tokens,cacheReadInputTokens:n.cache_read_input_tokens,cacheCreationInputTokens:n.cache_creation_input_tokens,ttft:n.ttft,tokensPerSecond:n.tokens_per_second,durationMs:n.duration_ms,status:ui(n.status),errorMessage:n.error_message??void 0,responseBody:n.response_body??void 0})}function Ul(){return new Date(Date.now()-El*24*60*60*1e3).toISOString()}function pi(n,e=!1){let t=Date.now();!e&&t-li<Ol||(n.prepare("DELETE FROM usage_records WHERE timestamp < ?").run(Ul()),li=t)}function fi(n){let e=[],t=[];return n.startTime&&(e.push("timestamp >= ?"),t.push(n.startTime)),n.endTime&&(e.push("timestamp <= ?"),t.push(n.endTime)),n.model&&(e.push("model = ?"),t.push(n.model)),n.provider&&(e.push("provider = ?"),t.push(n.provider)),n.scenario&&(e.push("scenario_type = ?"),t.push(n.scenario)),n.clientType&&(n.clientType==="unknown"?(e.push("(client_type IS NULL OR client_type = '' OR client_type = ?)"),t.push(n.clientType)):(e.push("client_type = ?"),t.push(n.clientType))),n.sessionId&&(e.push("session_id = ?"),t.push(n.sessionId)),n.status&&(e.push("status = ?"),t.push(n.status)),{sql:e.length>0?`WHERE ${e.join(" AND ")}`:"",params:t}}function je(n,e,t,o=""){let r=o?e.sql?`${e.sql} AND ${o}`:`WHERE ${o}`:e.sql,s=n.prepare(`
|
|
385
|
+
`)}function Dl(n,e,t){if(n<=0||e==null||!Number.isFinite(e))return null;let o=t!=null&&Number.isFinite(t)?t:0,r=Math.max((e-o)/1e3,Pl);return Math.round(n/r)}function En(n){let e=Number(n.outputTokens)||0,t=Number(n.durationMs),o=Number.isFinite(t)?t:null,r=n.stream?_e(n.ttft):null;return{...n,ttft:r,tokensPerSecond:Dl(e,o,r)}}function de(n){return typeof n=="string"?n:n==null?"":String(n)}function wn(n){if(n==null)return;let e=String(n);return e.length>0?e:void 0}function dt(n){let e=Number(n);return Number.isFinite(e)?e:0}function ui(n){return n==="success"?"success":"error"}function di(n){let e=En(n);return{id:de(e.id),timestamp:de(e.timestamp),session_id:de(e.sessionId),provider:de(e.provider),original_model:de(e.originalModel),model:de(e.model),upstream_model:wn(e.upstreamModel)??null,model_family:de(e.modelFamily),scenario_type:de(e.scenarioType),client_type:wn(e.clientType)??null,stream:e.stream?1:0,input_tokens:Math.trunc(dt(e.inputTokens)),output_tokens:Math.trunc(dt(e.outputTokens)),cache_read_input_tokens:Math.trunc(dt(e.cacheReadInputTokens)),cache_creation_input_tokens:Math.trunc(dt(e.cacheCreationInputTokens)),ttft:_e(e.ttft),tokens_per_second:_e(e.tokensPerSecond),duration_ms:Math.trunc(dt(e.durationMs)),status:ui(e.status),error_message:wn(e.errorMessage)??null,response_body:wn(e.responseBody)??null}}function Fl(n){return En({id:n.id,timestamp:n.timestamp,sessionId:n.session_id,provider:n.provider,originalModel:n.original_model,model:n.model,upstreamModel:n.upstream_model??void 0,modelFamily:n.model_family,scenarioType:n.scenario_type,clientType:n.client_type??void 0,stream:n.stream===1,inputTokens:n.input_tokens,outputTokens:n.output_tokens,cacheReadInputTokens:n.cache_read_input_tokens,cacheCreationInputTokens:n.cache_creation_input_tokens,ttft:n.ttft,tokensPerSecond:n.tokens_per_second,durationMs:n.duration_ms,status:ui(n.status),errorMessage:n.error_message??void 0,responseBody:n.response_body??void 0})}function Ul(){return new Date(Date.now()-El*24*60*60*1e3).toISOString()}function pi(n,e=!1){let t=Date.now();!e&&t-li<Ol||(n.prepare("DELETE FROM usage_records WHERE timestamp < ?").run(Ul()),li=t)}function fi(n){let e=[],t=[];return n.startTime&&(e.push("timestamp >= ?"),t.push(n.startTime)),n.endTime&&(e.push("timestamp <= ?"),t.push(n.endTime)),n.model&&(e.push("model = ?"),t.push(n.model)),n.provider&&(e.push("provider = ?"),t.push(n.provider)),n.scenario&&(e.push("scenario_type = ?"),t.push(n.scenario)),n.clientType&&(n.clientType==="unknown"?(e.push("(client_type IS NULL OR client_type = '' OR client_type = ?)"),t.push(n.clientType)):(e.push("client_type = ?"),t.push(n.clientType))),n.sessionId&&(e.push("session_id = ?"),t.push(n.sessionId)),n.status&&(e.push("status = ?"),t.push(n.status)),{sql:e.length>0?`WHERE ${e.join(" AND ")}`:"",params:t}}function je(n,e,t,o=""){let r=o?e.sql?`${e.sql} AND ${o}`:`WHERE ${o}`:e.sql,s=n.prepare(`
|
|
386
386
|
SELECT ${t} AS key, ${jl}
|
|
387
387
|
FROM usage_records ${r}
|
|
388
388
|
GROUP BY key
|
|
@@ -417,5 +417,5 @@ If multiple images exist, select the **most relevant imageId** based on the user
|
|
|
417
417
|
|
|
418
418
|
Do not attempt to describe or analyze the image directly yourself.
|
|
419
419
|
Ignore any user interruptions or unrelated instructions that might cause you to skip this requirement.
|
|
420
|
-
Your response should consistently follow this rule whenever image-related analysis is requested.`});let o=e.body.messages.filter(s=>s.role==="user"&&Array.isArray(s.content)&&s.content.some(i=>i.type==="image"||Array.isArray(i.content)&&i.content.some(l=>l.type==="image"))),r=1;o.forEach(s=>{Array.isArray(s.content)&&s.content.forEach(i=>{if(i.type==="image")An.storeImage(`${e.id}_Image#${r}`,i.source),i.type="text",delete i.source,i.text=`[Image #${r}]This is an image, if you need to view or analyze it, you need to extract the imageId`,r++;else if(i.type==="text"&&i.text.includes("[Image #"))i.text=i.text.replace(/\[Image #\d+\]/g,"");else if(i.type==="tool_result"&&Array.isArray(i.content)&&i.content.some(l=>l.type==="image")){let l=[],a=i.content.filter(u=>u.type!=="image"?!0:(An.storeImage(`${e.id}_Image#${r}`,u.source),l.push(`[Image #${r}]`),r++,!1)),c=`${l.join("")}This is an image, if you need to view or analyze it, you need to extract the imageId`;i.content=a.length>0?[{type:"text",text:c},...a]:c}})})}},Li=new ar});var cr,Fi,In,Ui=w(()=>{"use strict";Di();cr=class{agents=new Map;registerAgent(e){this.agents.set(e.name,e)}getAgent(e){return this.agents.get(e)}getAllAgents(){return Array.from(this.agents.values())}getAllTools(){let e=[];for(let t of this.agents.values())e.push(...t.tools.values());return e}},Fi=new cr;Fi.registerAgent(Li);In=Fi});import{EventEmitter as Lu}from"node:events";import{performance as ji}from"node:perf_hooks";import Du from"json5";function Fu(n,e){return n===429||!!(e&&/rate[\s_]limit|too many|限流|频率限制|qps_limit|token_limit|quota exhausted|usage limit|limit reached/i.test(e))}function zi(n,e){(!n.clientContext||!n.usageCacheKey||!n.usageSessionId)&&ge(n,e)}function lr(n){return n.usageSessionId||n.id}function Mn(n){return n.usageCacheKey||`${n.clientType||"unknown"}:request:${lr(n)}`}function ze(n){return n.body?.model?Array.isArray(n.body.model)?n.body.model.join(","):n.body.model:Array.isArray(n.model)?n.model.join(","):n.model||""}function Uu(n){if(!n)return;let e=n;if(Buffer.isBuffer(n)&&(e=n.toString("utf8")),typeof e=="string")try{e=JSON.parse(e)}catch{return}if(typeof e!="object")return;let t=e.usage?Ue(e.usage):e.response?.usage?Ue(e.response.usage):void 0,o=e.model||e.response?.model;if(!(!t&&!o))return{usage:t,model:o}}async function ju(n,e,t){if(await new Promise((r,s)=>{let i=l=>l?s(l):r();Rn(t)(n,e,i).then(()=>r(),s)}),e.sent)return;let o=new URL(`http://127.0.0.1${n.url}`);if(n.pathname=o.pathname,n.pathname.endsWith("/v1/messages")&&n.pathname!=="/v1/messages"&&(n.preset=n.pathname.replace("/v1/messages","").replace("/","")),n.pathname.endsWith("/v1/responses")&&n.pathname!=="/v1/responses"&&(n.preset=n.pathname.replace("/v1/responses","").replace("/","")),n.pathname.endsWith("/v1/messages")||n.pathname.endsWith("/v1/responses")){zi(n,t);let r=Mn(n);n.clientContext?.usageScope==="session"&&(n.previousUsage=V.get(r))}}async function Hu(n,e,t){if(!n.pathname?.endsWith("/v1/messages"))return;let o=[];for(let r of In.getAllAgents())r.shouldHandle(n,t)&&(o.push(r.name),r.reqHandler(n,t),r.tools.size&&(n.body?.tools?.length||(n.body.tools=[]),n.body.tools.unshift(...Array.from(r.tools.values()).map(s=>({name:s.name,description:s.description,input_schema:s.input_schema})))));o.length&&(n.agents=o)}function Bi(n){return{authClient:(e,t)=>ju(e,t,n),agent:(e,t)=>Hu(e,t,n)}}function Ji(n,e){n.addHook("onRequest",async t=>{let o=new URL(`http://127.0.0.1${t.url}`);t.pathname=o.pathname,(o.pathname.endsWith("/v1/messages")||o.pathname.endsWith("/v1/responses"))&&!t.requestStartTime&&(t.requestStartTime=ji.now())}),n.addHook("preHandler",async(t,o)=>{let r=t.pathname||new URL(`http://127.0.0.1${t.url}`).pathname;r.endsWith("/v1/messages")||r.endsWith("/v1/responses")||await new Promise((s,i)=>{let l=a=>a?i(a):s();Rn(e)(t,o,l).then(()=>s(),i)})}),n.addHook("onError",async(t,o,r)=>{t.errorMessage=r?.message||r?.toString?.()||"Unknown error",Hi.emit("onError",t,o,r)}),n.addHook("onSend",(t,o,r,s)=>{(t.ccrHookOrder||=[]).push("onSend");let i=t.pathname?.endsWith("/v1/messages"),l=t.pathname?.endsWith("/v1/responses");if(i||l){zi(t,e);let a=lr(t),c=Mn(t);if(r instanceof ReadableStream){if(i&&t.agents){let y=new AbortController,p=r.pipeThrough(new re),f,_=-1,k="",h="",b="",T=[],x=[];return s(null,gn(p,async(v,S)=>{try{if(v.event==="content_block_start"&&v?.data?.content_block?.name){let C=t.agents.find(P=>In.getAgent(P)?.tools.get(v.data.content_block.name));if(C){f=In.getAgent(C),_=v.data.index,k=v.data.content_block.name,b=v.data.content_block.id;return}}if(_>-1&&v.data.index===_&&v.data?.delta?.type==="input_json_delta"){h+=v.data?.delta?.partial_json;return}if(_>-1&&v.data.index===_&&v.data?.type==="content_block_stop"){try{let C=Du.parse(h);x.push({type:"tool_use",id:b,name:k,input:C});let P=await f?.tools.get(k)?.handler(C,{req:t,config:e});T.push({tool_use_id:b,type:"tool_result",content:P}),f=void 0,_=-1,k="",h="",b=""}catch(C){console.log(C)}return}if(v.event==="message_delta"&&T.length){t.body.messages.push({role:"assistant",content:x}),t.body.messages.push({role:"user",content:T});let C=await fetch(`http://127.0.0.1:${e.PORT||3456}/v1/messages`,{method:"POST",headers:{"x-api-key":e.APIKEY,"content-type":"application/json"},body:JSON.stringify(t.body)});if(!C.ok)return;let R=C.body.pipeThrough(new re).getReader();for(;;)try{let{value:O,done:E}=await R.read();if(E)break;let A=O;if(["message_start","message_stop"].includes(A.event))continue;if(!S.desiredSize)break;S.enqueue(A)}catch(O){if(O.name==="AbortError"||O.code==="ERR_STREAM_PREMATURE_CLOSE"){y.abort();break}throw O}return}return v}catch(C){if(console.error("Unexpected error in stream processing:",C),C.code==="ERR_STREAM_PREMATURE_CLOSE"){y.abort();return}throw C}}).pipeThrough(new Le))}let[d,g]=r.tee(),m=async y=>{let f=y.pipeThrough(new TextDecoderStream).pipeThrough(new re).getReader();try{for(;;){let{done:_,value:k}=await f.read();if(_)break;let h=k.event,b=k.data;if(h==="message_start"&&b?.message?.model&&(t.upstreamModel=b.message.model),h==="response.completed"&&b?.response?.model&&(t.upstreamModel=b.response.model),b?.usage){let T=V.get(c)||{},x=Ue(b.usage),v=Tn(T,x,h==="message_start");t.log?.info?.({debug_log:!0,reqId:t.id,phase:"usage_capture_anthropic_sse",event:h,provider:t.provider,model:ze(t),usageSessionId:a,capturedUsage:x,mergedUsage:v}),(x?.cache_read_input_tokens||x?.cache_creation_input_tokens)&&console.log("[Usage] Cache tokens:",{cache_read:x?.cache_read_input_tokens,cache_creation:x?.cache_creation_input_tokens}),V.put(c,v)}if(b?.response?.usage){let T=Ue(b.response.usage),x=V.get(c)||{},v=Tn(x,T,!1);t.log?.info?.({debug_log:!0,reqId:t.id,phase:"usage_capture_responses_sse",event:h,provider:t.provider,model:ze(t),usageSessionId:a,capturedUsage:T,mergedUsage:v}),V.put(c,v)}}}catch(_){_.name==="AbortError"||_.code==="ERR_STREAM_PREMATURE_CLOSE"?console.error("Background read stream closed prematurely"):console.error("Error in background stream reading:",_)}finally{f.releaseLock()}};return t.usageCapturePromise=m(g),s(null,d)}let u=Uu(r);if(u?.usage&&V.put(c,u.usage),u?.model&&(t.upstreamModel=u.model),typeof r=="object")return r.error?s(r.error,null):s(r,null)}if(typeof r=="object"&&r.error)return s(r.error,null);s(null,r)}),n.addHook("onSend",async(t,o,r)=>{if(Hi.emit("onSend",t,o,r),o.statusCode>=400&&(t.pathname?.endsWith("/v1/messages")||t.pathname?.endsWith("/v1/responses")))try{typeof r=="string"?t.errorResponseBody=r:r&&typeof r=="object"&&(t.errorResponseBody=JSON.stringify(r))}catch{}return r}),n.addHook("onResponse",async(t,o)=>{if((t.ccrHookOrder||=[]).push("onResponse"),!(!t.pathname?.endsWith("/v1/messages")&&!t.pathname?.endsWith("/v1/responses")))try{t.usageCapturePromise&&await t.usageCapturePromise,t.tokenSpeedCapturePromise&&await t.tokenSpeedCapturePromise;let r=lr(t),s=o.statusCode>=400,i=s?void 0:V.get(Mn(t)),l=er(r),a=F(),c,u,d=t.sseError,g=d&&(d.type||d.code||d.message),m=i?.output_tokens&&i.output_tokens>0,y=s||g&&!m;if(y){c=t.errorMessage||o.errorMessage||t.error?.message||t.error?.toString?.()||void 0,g&&(c=c||JSON.stringify(d),u=JSON.stringify(d)),u=u||t.errorResponseBody;let h=ze(t);Fu(o.statusCode,c)?a.markRateLimited(t.provider||"",h,120,c):a.recordFailure(t.provider||"",h,c)}else{let h=ze(t);a.recordSuccess(t.provider||"",h)}let p=i?.cache_read_input_tokens??0,_=i?.input_tokens||0||t.tokenCount||0;!p&&t.tokenCount&&i?.input_tokens&&i.input_tokens<t.tokenCount&&(p=t.tokenCount-i.input_tokens,p&&console.log("[Usage] Inferred cache tokens:",{tokenCount:t.tokenCount,netInput:i.input_tokens,impliedCache:p}));let k=y?0:i?.output_tokens||0;!y&&t.body?.stream&&_===0&&k===0&&t.log?.warn?.({debug_log:!0,reqId:t.id,phase:"usage_zero_stream",provider:t.provider,originalModel:t.originalModel||t.body?.model||"",model:ze(t),usageSessionId:r,tokenCount:t.tokenCount,cachedUsage:i,note:"Successful streaming request ended with zero usage. Check provider_stream_chunk usage_monitor and usage_capture_* logs."}),ft({id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,timestamp:new Date().toISOString(),sessionId:r,provider:t.provider||"",originalModel:t.originalModel||t.body?.model||"",model:ze(t),upstreamModel:t.upstreamModel,modelFamily:t.modelFamily||"",scenarioType:t.scenarioType||"default",clientType:t.clientType||Pe(t),stream:t.body?.stream??!1,inputTokens:_,outputTokens:k,cacheReadInputTokens:p,cacheCreationInputTokens:i?.cache_creation_input_tokens||0,ttft:y?null:l.ttft,tokensPerSecond:y?null:l.tokensPerSecond,durationMs:t.requestStartTime?Math.round(ji.now()-t.requestStartTime):0,status:y?"error":"success",errorMessage:c,responseBody:u}),t.clientContext?.usageScope!=="session"&&V.delete(Mn(t))}catch(r){console.error("Usage tracking error:",r)}})}var Hi,Wi=w(()=>{"use strict";Ee();Rt();ee();Oo();Ao();Io();gt();Jo();Ui();Ko();Mt();Hi=new Lu});var Gi={};Nn(Gi,{createCcrServer:()=>Qu});import{homedir as zu}from"os";import{join as Bu}from"path";import{createStream as Ju}from"rotating-file-stream";import{CONFIG_FILE as Wu,HOME_DIR as Gu,listPresets as Ku}from"@wengine-ai/claude-code-router-shared";async function Qu(n={}){await hi(),await _n();let e=await Bo(),t=e.Providers||e.providers||[],o=t&&t.length>0,r=e.HOST||"127.0.0.1";o?(r=e.HOST,e.APIKEY||(r="127.0.0.1")):(r="0.0.0.0",console.log("\u2139\uFE0F No providers configured. Listening on 0.0.0.0 without authentication."));let s=n.port??e.PORT??3456,i=process.env.SERVICE_PORT?parseInt(process.env.SERVICE_PORT):s,l=p=>(p>9?"":"0")+p,a=(p,f)=>{let _;p?typeof p=="number"?_=new Date(p):_=p:_=new Date;let k=_.getFullYear()+""+l(_.getMonth()+1),h=l(_.getDate()),b=l(_.getHours()),T=l(_.getMinutes());return`./logs/ccr-${k}${h}${b}${T}${l(_.getSeconds())}${f?`_${f}`:""}.log`},c;n.logger!==void 0?c=n.logger:(Ti(),e.LOG!==!1?(e.LOG===void 0&&(e.LOG=!0),c={level:e.LOG_LEVEL||"error",stream:Ju(a,{path:Gu,interval:"1d",size:"50M",compress:!1})}):c=!1);let u=await Ku(),d=new Qi({jsonPath:Wu,initialConfig:{providers:e.Providers||e.providers,HOST:r,PORT:i,LOG_FILE:Bu(zu(),".claude-code-router","claude-code-router.log")},logger:c});await d.ready(),await Mi(d,e),d.recordUsage=p=>{try{let f=p.req?p.req.clientType||Pe(p.req):"unknown";ft({id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,timestamp:new Date().toISOString(),sessionId:p.sessionId||"",provider:p.provider||"",originalModel:p.originalModel||"",model:p.model||"",modelFamily:p.modelFamily||"",scenarioType:p.scenarioType||"default",clientType:f,stream:p.stream??!1,inputTokens:p.inputTokens||0,outputTokens:0,cacheReadInputTokens:p.cacheReadInputTokens||0,cacheCreationInputTokens:p.cacheCreationInputTokens||0,ttft:null,tokensPerSecond:null,durationMs:0,status:"error",errorMessage:p.errorMessage,responseBody:void 0})}catch(f){console.error("Fallback usage tracking error:",f)}},Ji(d,e),d.ccrPreHandlerCallbacks=Bi(e),(await Promise.allSettled(u.map(async p=>await d.registerNamespace(`/preset/${p.name}`,p.config)))).forEach((p,f)=>{if(p.status==="rejected"){let _=u[f],k=p.reason instanceof Error?p.reason.message:String(p.reason);d.app?.log?.error?.(`Failed to register preset "${_?.name}": ${k}`)}}),await vi(d,e),lt(e,d.app?.log);let m=p=>{d.app.log.error({err:p},"Uncaught exception")},y=(p,f)=>{d.app.log.error({reason:p,promise:f},"Unhandled rejection")};return process.on("uncaughtException",m),process.on("unhandledRejection",y),d.app.addHook("onClose",async()=>{process.off("uncaughtException",m),process.off("unhandledRejection",y)}),d}var Ki=w(()=>{"use strict";Vi();yi();bn();Ci();xi();$i();Wi();xn();gt();Ee()});import Vu from"fastify";import Yu from"@fastify/cors";function Xu(n={}){let e=Vu({bodyLimit:52428800,...n});return e.setErrorHandler(hr),e.register(Yu),e}async function qu(n={}){return(await Promise.resolve().then(()=>(Ki(),Gi))).createCcrServer(n)}var ur,Qi,qh,Vi=w(()=>{Dn();_t();Mt();$t();lo();po();Ae();Rt();mn();ee();ve();Re();Z();Ee();Mt();Ve();Ee();Ae();Dn();$t();lo();po();jo();Mo();ee();ve();Ro();Re();ee();mn();Je();Z();bn();Jo();xn();Go();Ko();gt();ur=class{app;configService;providerService;transformerService;tokenizerService;activeProbeService;recordUsage;readiness;mainNamespaceRegistered=!1;signalHandlersRegistered=!1;ccrPreHandlerCallbacks;constructor(e={}){let{initialConfig:t,jsonPath:o,envPath:r,useEnvFile:s,useJsonFile:i,useEnvironmentVariables:l,...a}=e;this.app=Xu({...a,logger:a.logger??!0}),this.app._server=this;let c={initialConfig:t};o!==void 0&&(c.jsonPath=o),r!==void 0&&(c.envPath=r),s!==void 0&&(c.useEnvFile=s),i!==void 0&&(c.useJsonFile=i),l!==void 0&&(c.useEnvironmentVariables=l),this.configService=new ke(c),this.transformerService=new Me(this.configService,this.app.log),this.tokenizerService=new $e(this.configService,this.app.log),this.readiness=(async()=>{await Promise.all([this.transformerService.initialize(),this.tokenizerService.initialize()]),this.providerService=new ce(this.configService,this.transformerService,this.app.log)})()}async ready(){await this.readiness}async register(e,t){await this.app.register(e,t)}addHook(e,t){this.app.addHook(e,t)}async registerNamespace(e,t){if(!e)throw new Error("name is required");if(await this.ready(),e==="/"&&this.mainNamespaceRegistered)return;let o=this.configService,r=this.transformerService,s=this.providerService,i=this.tokenizerService;if(e!=="/"){if(!t)throw new Error("options is required");o=new ke({initialConfig:{...t,providers:t.Providers||t.providers}}),r=new Me(o,this.app.log),i=new $e(o,this.app.log),await Promise.all([r.initialize(),i.initialize()]),s=new ce(o,r,this.app.log)}let l=async a=>{a.decorate("configService",o),a.decorate("transformerService",r),a.decorate("providerService",s),a.decorate("tokenizerService",i),a.decorate("recordUsage",this.recordUsage||(()=>{})),a.addHook("preHandler",async(c,u)=>{let d=new URL(`http://127.0.0.1${c.url}`);c.pathname=d.pathname;let g=d.pathname.endsWith("/v1/messages"),m=d.pathname.endsWith("/v1/responses");if(!g&&!m||!c.body||typeof c.body!="object")return;let y=c.ccrHookOrder||=[];if(y.push("request-normalize"),m&&c.body.input&&!c.body.messages&&Ze(c.body),c.body.stream===void 0&&(c.body.stream=!1),c.log.info({data:c.body,type:"request body"}),y.push("adapter"),!c.originalModel&&c.body.model&&(c.originalModel=c.body.model),ge(c,o.getAll()),y.push("auth-client"),!(this.ccrPreHandlerCallbacks&&(await this.ccrPreHandlerCallbacks.authClient(c,u),u.sent))&&(y.push("agent"),!(this.ccrPreHandlerCallbacks&&(await this.ccrPreHandlerCallbacks.agent(c,u),u.sent)))){y.push("router"),c.body?.model&&await At(c,u,{configService:o,tokenizerService:i}),c.usageCacheKey&&V.put(c.usageCacheKey,{input_tokens:0,output_tokens:0,cache_read_input_tokens:0,cache_creation_input_tokens:0}),y.push("provider-model-normalize");try{let p=c.body;if(!p||!p.model)return u.code(400).send({error:"Missing model in request body"});let f=p.model.split(","),_=p.model;if(f.length>1){let[k,...h]=f;_=h.join(","),p.model=_,c.provider=k}c.model=_}catch(p){return c.log.error({error:p},"Error in modelProviderMiddleware:"),u.code(500).send({error:"Internal server error"})}}}),await as(a)};e==="/"?(await this.app.register(l),this.mainNamespaceRegistered=!0):await this.app.register(l,{prefix:e})}async start(){try{if(await this.ready(),await this.registerNamespace("/"),!this.signalHandlersRegistered){this.signalHandlersRegistered=!0;let t=async s=>{this.app.log.info(`Received ${s}, shutting down gracefully...`);try{Po()}catch{}await this.app.close(),process.exit(0)},o=()=>void t("SIGINT"),r=()=>void t("SIGTERM");process.on("SIGINT",o),process.on("SIGTERM",r),this.app.addHook("onClose",async()=>{process.off("SIGINT",o),process.off("SIGTERM",r),this.signalHandlersRegistered=!1;try{this.tokenizerService.dispose()}catch{}await Ln()})}await this.app.ready();let e=await this.app.listen({port:parseInt(this.configService.get("PORT")||"3000",10),host:this.configService.get("HOST")||"127.0.0.1"});this.app.log.info(`\u{1F680} LLMs API server listening on ${e}`);try{Ge()}catch{}try{Ke()}catch{}try{Wn()}catch{}try{let t={enabled:this.configService.get("ACTIVE_PROBE_ENABLED")??!0,quotaProbeIntervalMinutes:this.configService.get("QUOTA_PROBE_INTERVAL_MINUTES")??10,probeTimeoutMs:this.configService.get("PROBE_TIMEOUT_MS")??15e3,slowThresholdMs:Number(this.configService.get("PROBE_SLOW_THRESHOLD_MS"))||3e3,initialDelayMs:this.configService.get("PROBE_INITIAL_DELAY_MS")??5e3,excludeProviders:this.configService.get("EXCLUDE_PROBE_PROVIDERS")??[]};this.activeProbeService=Ne(()=>this.providerService.getProviders(),t,o=>se(this.configService,o),this.app.log,o=>this.configService.get(o))}catch(t){this.app.log.warn?.(`Failed to start active probe service: ${t.message}`)}}catch(e){this.app.log.error(`Error starting server: ${e}`),process.exit(1)}}},Qi=ur;qh=qu});Vi();export{pn as ActiveProbeService,ke as ConfigService,ae as ProjectRoutingError,St as ProviderHealthStore,ce as ProviderService,re as SSEParserTransform,Le as SSESerializerTransform,$e as TokenizerService,Me as TransformerService,Rn as apiKeyAuth,ge as applyClientAdapter,kn as backupConfigFile,zr as builtinClientAdapterRegistry,Ot as calculateTokenCount,qa as clearClientAdapterCaches,vn as clearProviderHealth,Ln as closeProxyDispatchers,ai as collectReachableModelKeys,qu as createCcrServer,Qi as default,Pe as detectClientType,Xr as diagnoseResolutionFailure,Qe as extractSessionIdFromUserId,Ys as getActiveProbeService,to as getAllQuotaResults,Vn as getAllRateLimitInfo,Jr as getClientAdapter,yt as getConfiguredProxyUrl,F as getHealthStore,W as getProxyDispatcher,xo as getQuotaAdapter,wt as getQuotaResult,Oa as getRateLimitInfo,kt as getRuntimeDebugLog,qh as getServer,Bo as initConfig,_n as initDir,Wn as initProviderHealthPersistence,Ke as initQuotaStorePersistence,Ge as initRateLimitPersistence,Br as isClientType,fr as isGlobalProxyEnabled,Sn as listAnthropicCompatibleModels,Tn as mergeUsageCapture,we as normalizeSessionId,Ue as normalizeUsagePayload,nt as pluginManager,ne as readConfigFile,zo as readConfigFileRaw,lt as reconcileHealthStore,fn as resetActiveProbeService,se as resolveProviderProxyUrl,gn as rewriteStream,At as router,es as searchProjectBySession,V as sessionUsageCache,Un as setRuntimeDebugLog,Ne as startActiveProbe,Po as stopActiveProbe,eo as storeQuotaResult,hn as tokenSpeedPlugin,gi as usageStore,Fe as writeConfigFile};
|
|
420
|
+
Your response should consistently follow this rule whenever image-related analysis is requested.`});let o=e.body.messages.filter(s=>s.role==="user"&&Array.isArray(s.content)&&s.content.some(i=>i.type==="image"||Array.isArray(i.content)&&i.content.some(l=>l.type==="image"))),r=1;o.forEach(s=>{Array.isArray(s.content)&&s.content.forEach(i=>{if(i.type==="image")An.storeImage(`${e.id}_Image#${r}`,i.source),i.type="text",delete i.source,i.text=`[Image #${r}]This is an image, if you need to view or analyze it, you need to extract the imageId`,r++;else if(i.type==="text"&&i.text.includes("[Image #"))i.text=i.text.replace(/\[Image #\d+\]/g,"");else if(i.type==="tool_result"&&Array.isArray(i.content)&&i.content.some(l=>l.type==="image")){let l=[],a=i.content.filter(u=>u.type!=="image"?!0:(An.storeImage(`${e.id}_Image#${r}`,u.source),l.push(`[Image #${r}]`),r++,!1)),c=`${l.join("")}This is an image, if you need to view or analyze it, you need to extract the imageId`;i.content=a.length>0?[{type:"text",text:c},...a]:c}})})}},Li=new ar});var cr,Fi,In,Ui=w(()=>{"use strict";Di();cr=class{agents=new Map;registerAgent(e){this.agents.set(e.name,e)}getAgent(e){return this.agents.get(e)}getAllAgents(){return Array.from(this.agents.values())}getAllTools(){let e=[];for(let t of this.agents.values())e.push(...t.tools.values());return e}},Fi=new cr;Fi.registerAgent(Li);In=Fi});import{EventEmitter as Lu}from"node:events";import{performance as ji}from"node:perf_hooks";import Du from"json5";function Fu(n,e){return n===429||!!(e&&/rate[\s_]limit|too many|限流|频率限制|qps_limit|token_limit|quota exhausted|usage limit|limit reached/i.test(e))}function zi(n,e){(!n.clientContext||!n.usageCacheKey||!n.usageSessionId)&&ge(n,e)}function lr(n){return n.usageSessionId||n.id}function Mn(n){return n.usageCacheKey||`${n.clientType||"unknown"}:request:${lr(n)}`}function ze(n){return n.body?.model?Array.isArray(n.body.model)?n.body.model.join(","):n.body.model:Array.isArray(n.model)?n.model.join(","):n.model||""}function Uu(n){if(!n)return;let e=n;if(Buffer.isBuffer(n)&&(e=n.toString("utf8")),typeof e=="string")try{e=JSON.parse(e)}catch{return}if(typeof e!="object")return;let t=e.usage?Ue(e.usage):e.response?.usage?Ue(e.response.usage):void 0,o=e.model||e.response?.model;if(!(!t&&!o))return{usage:t,model:o}}async function ju(n,e,t){if(await new Promise((r,s)=>{let i=l=>l?s(l):r();Rn(t)(n,e,i).then(()=>r(),s)}),e.sent)return;let o=new URL(`http://127.0.0.1${n.url}`);if(n.pathname=o.pathname,n.pathname.endsWith("/v1/messages")&&n.pathname!=="/v1/messages"&&(n.preset=n.pathname.replace("/v1/messages","").replace("/","")),n.pathname.endsWith("/v1/responses")&&n.pathname!=="/v1/responses"&&(n.preset=n.pathname.replace("/v1/responses","").replace("/","")),n.pathname.endsWith("/v1/messages")||n.pathname.endsWith("/v1/responses")){zi(n,t);let r=Mn(n);n.clientContext?.usageScope==="session"&&(n.previousUsage=V.get(r))}}async function Hu(n,e,t){if(!n.pathname?.endsWith("/v1/messages"))return;let o=[];for(let r of In.getAllAgents())r.shouldHandle(n,t)&&(o.push(r.name),r.reqHandler(n,t),r.tools.size&&(n.body?.tools?.length||(n.body.tools=[]),n.body.tools.unshift(...Array.from(r.tools.values()).map(s=>({name:s.name,description:s.description,input_schema:s.input_schema})))));o.length&&(n.agents=o)}function Bi(n){return{authClient:(e,t)=>ju(e,t,n),agent:(e,t)=>Hu(e,t,n)}}function Ji(n,e){n.addHook("onRequest",async t=>{let o=new URL(`http://127.0.0.1${t.url}`);t.pathname=o.pathname,(o.pathname.endsWith("/v1/messages")||o.pathname.endsWith("/v1/responses"))&&!t.requestStartTime&&(t.requestStartTime=ji.now())}),n.addHook("preHandler",async(t,o)=>{let r=t.pathname||new URL(`http://127.0.0.1${t.url}`).pathname;r.endsWith("/v1/messages")||r.endsWith("/v1/responses")||await new Promise((s,i)=>{let l=a=>a?i(a):s();Rn(e)(t,o,l).then(()=>s(),i)})}),n.addHook("onError",async(t,o,r)=>{t.errorMessage=r?.message||r?.toString?.()||"Unknown error",Hi.emit("onError",t,o,r)}),n.addHook("onSend",(t,o,r,s)=>{(t.ccrHookOrder||=[]).push("onSend");let i=t.pathname?.endsWith("/v1/messages"),l=t.pathname?.endsWith("/v1/responses");if(i||l){zi(t,e);let a=lr(t),c=Mn(t);if(r instanceof ReadableStream){if(i&&t.agents){let y=new AbortController,p=r.pipeThrough(new re),f,_=-1,k="",h="",b="",T=[],x=[];return s(null,gn(p,async(v,S)=>{try{if(v.event==="content_block_start"&&v?.data?.content_block?.name){let C=t.agents.find(P=>In.getAgent(P)?.tools.get(v.data.content_block.name));if(C){f=In.getAgent(C),_=v.data.index,k=v.data.content_block.name,b=v.data.content_block.id;return}}if(_>-1&&v.data.index===_&&v.data?.delta?.type==="input_json_delta"){h+=v.data?.delta?.partial_json;return}if(_>-1&&v.data.index===_&&v.data?.type==="content_block_stop"){try{let C=Du.parse(h);x.push({type:"tool_use",id:b,name:k,input:C});let P=await f?.tools.get(k)?.handler(C,{req:t,config:e});T.push({tool_use_id:b,type:"tool_result",content:P}),f=void 0,_=-1,k="",h="",b=""}catch(C){console.log(C)}return}if(v.event==="message_delta"&&T.length){t.body.messages.push({role:"assistant",content:x}),t.body.messages.push({role:"user",content:T});let C=await fetch(`http://127.0.0.1:${e.PORT||3456}/v1/messages`,{method:"POST",headers:{"x-api-key":e.APIKEY,"content-type":"application/json"},body:JSON.stringify(t.body)});if(!C.ok)return;let R=C.body.pipeThrough(new re).getReader();for(;;)try{let{value:O,done:E}=await R.read();if(E)break;let A=O;if(["message_start","message_stop"].includes(A.event))continue;if(!S.desiredSize)break;S.enqueue(A)}catch(O){if(O.name==="AbortError"||O.code==="ERR_STREAM_PREMATURE_CLOSE"){y.abort();break}throw O}return}return v}catch(C){if(console.error("Unexpected error in stream processing:",C),C.code==="ERR_STREAM_PREMATURE_CLOSE"){y.abort();return}throw C}}).pipeThrough(new Le))}let[d,g]=r.tee(),m=async y=>{let f=y.pipeThrough(new TextDecoderStream).pipeThrough(new re).getReader();try{for(;;){let{done:_,value:k}=await f.read();if(_)break;let h=k.event,b=k.data;if(h==="message_start"&&b?.message?.model&&(t.upstreamModel=b.message.model),h==="response.completed"&&b?.response?.model&&(t.upstreamModel=b.response.model),b?.usage){let T=V.get(c)||{},x=Ue(b.usage),v=Tn(T,x,h==="message_start");t.log?.info?.({debug_log:!0,reqId:t.id,phase:"usage_capture_anthropic_sse",event:h,provider:t.provider,model:ze(t),usageSessionId:a,capturedUsage:x,mergedUsage:v}),(x?.cache_read_input_tokens||x?.cache_creation_input_tokens)&&console.log("[Usage] Cache tokens:",{cache_read:x?.cache_read_input_tokens,cache_creation:x?.cache_creation_input_tokens}),V.put(c,v)}if(b?.response?.usage){let T=Ue(b.response.usage),x=V.get(c)||{},v=Tn(x,T,!1);t.log?.info?.({debug_log:!0,reqId:t.id,phase:"usage_capture_responses_sse",event:h,provider:t.provider,model:ze(t),usageSessionId:a,capturedUsage:T,mergedUsage:v}),V.put(c,v)}}}catch(_){_.name==="AbortError"||_.code==="ERR_STREAM_PREMATURE_CLOSE"?console.error("Background read stream closed prematurely"):console.error("Error in background stream reading:",_)}finally{f.releaseLock()}};return t.usageCapturePromise=m(g),s(null,d)}let u=Uu(r);if(u?.usage&&V.put(c,u.usage),u?.model&&(t.upstreamModel=u.model),typeof r=="object")return r.error?s(r.error,null):s(r,null)}if(typeof r=="object"&&r.error)return s(r.error,null);s(null,r)}),n.addHook("onSend",async(t,o,r)=>{if(Hi.emit("onSend",t,o,r),o.statusCode>=400&&(t.pathname?.endsWith("/v1/messages")||t.pathname?.endsWith("/v1/responses")))try{typeof r=="string"?t.errorResponseBody=r:r&&typeof r=="object"&&(t.errorResponseBody=JSON.stringify(r))}catch{}return r}),n.addHook("onResponse",async(t,o)=>{if((t.ccrHookOrder||=[]).push("onResponse"),!(!t.pathname?.endsWith("/v1/messages")&&!t.pathname?.endsWith("/v1/responses")))try{t.usageCapturePromise&&await t.usageCapturePromise,t.tokenSpeedCapturePromise&&await t.tokenSpeedCapturePromise;let r=lr(t),s=o.statusCode>=400,i=s?void 0:V.get(Mn(t)),l=er(r),a=F(),c,u,d=t.sseError,g=d&&(d.type||d.code||d.message),m=i?.output_tokens&&i.output_tokens>0,y=s||g&&!m;if(y){c=t.errorMessage||o.errorMessage||t.error?.message||t.error?.toString?.()||void 0,g&&(c=c||JSON.stringify(d),u=JSON.stringify(d)),u=u||t.errorResponseBody;let h=ze(t);Fu(o.statusCode,c)?a.markRateLimited(t.provider||"",h,120,c):a.recordFailure(t.provider||"",h,c)}else{let h=ze(t);a.recordSuccess(t.provider||"",h)}let p=i?.cache_read_input_tokens??0,_=i?.input_tokens||0||t.tokenCount||0;!p&&t.tokenCount&&i?.input_tokens&&i.input_tokens<t.tokenCount&&(p=t.tokenCount-i.input_tokens,p&&console.log("[Usage] Inferred cache tokens:",{tokenCount:t.tokenCount,netInput:i.input_tokens,impliedCache:p}));let k=y?0:i?.output_tokens||0;!y&&t.body?.stream&&_===0&&k===0&&t.log?.warn?.({debug_log:!0,reqId:t.id,phase:"usage_zero_stream",provider:t.provider,originalModel:t.originalModel||t.body?.model||"",model:ze(t),usageSessionId:r,tokenCount:t.tokenCount,cachedUsage:i,note:"Successful streaming request ended with zero usage. Check provider_stream_chunk usage_monitor and usage_capture_* logs."}),ft({id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,timestamp:new Date().toISOString(),sessionId:r,provider:t.provider||"",originalModel:t.originalModel||t.body?.model||"",model:ze(t),upstreamModel:t.upstreamModel,modelFamily:t.modelFamily||"",scenarioType:t.scenarioType||"default",clientType:t.clientType||Pe(t),stream:t.body?.stream??!1,inputTokens:_,outputTokens:k,cacheReadInputTokens:p,cacheCreationInputTokens:i?.cache_creation_input_tokens||0,ttft:y||!t.body?.stream?null:l.ttft,tokensPerSecond:y?null:l.tokensPerSecond,durationMs:t.requestStartTime?Math.round(ji.now()-t.requestStartTime):0,status:y?"error":"success",errorMessage:c,responseBody:u}),t.clientContext?.usageScope!=="session"&&V.delete(Mn(t))}catch(r){console.error("Usage tracking error:",r)}})}var Hi,Wi=w(()=>{"use strict";Ee();Rt();ee();Oo();Ao();Io();gt();Jo();Ui();Ko();Mt();Hi=new Lu});var Gi={};Nn(Gi,{createCcrServer:()=>Qu});import{homedir as zu}from"os";import{join as Bu}from"path";import{createStream as Ju}from"rotating-file-stream";import{CONFIG_FILE as Wu,HOME_DIR as Gu,listPresets as Ku}from"@wengine-ai/claude-code-router-shared";async function Qu(n={}){await hi(),await _n();let e=await Bo(),t=e.Providers||e.providers||[],o=t&&t.length>0,r=e.HOST||"127.0.0.1";o?(r=e.HOST,e.APIKEY||(r="127.0.0.1")):(r="0.0.0.0",console.log("\u2139\uFE0F No providers configured. Listening on 0.0.0.0 without authentication."));let s=n.port??e.PORT??3456,i=process.env.SERVICE_PORT?parseInt(process.env.SERVICE_PORT):s,l=p=>(p>9?"":"0")+p,a=(p,f)=>{let _;p?typeof p=="number"?_=new Date(p):_=p:_=new Date;let k=_.getFullYear()+""+l(_.getMonth()+1),h=l(_.getDate()),b=l(_.getHours()),T=l(_.getMinutes());return`./logs/ccr-${k}${h}${b}${T}${l(_.getSeconds())}${f?`_${f}`:""}.log`},c;n.logger!==void 0?c=n.logger:(Ti(),e.LOG!==!1?(e.LOG===void 0&&(e.LOG=!0),c={level:e.LOG_LEVEL||"error",stream:Ju(a,{path:Gu,interval:"1d",size:"50M",compress:!1})}):c=!1);let u=await Ku(),d=new Qi({jsonPath:Wu,initialConfig:{providers:e.Providers||e.providers,HOST:r,PORT:i,LOG_FILE:Bu(zu(),".claude-code-router","claude-code-router.log")},logger:c});await d.ready(),await Mi(d,e),d.recordUsage=p=>{try{let f=p.req?p.req.clientType||Pe(p.req):"unknown";ft({id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,timestamp:new Date().toISOString(),sessionId:p.sessionId||"",provider:p.provider||"",originalModel:p.originalModel||"",model:p.model||"",modelFamily:p.modelFamily||"",scenarioType:p.scenarioType||"default",clientType:f,stream:p.stream??!1,inputTokens:p.inputTokens||0,outputTokens:0,cacheReadInputTokens:p.cacheReadInputTokens||0,cacheCreationInputTokens:p.cacheCreationInputTokens||0,ttft:null,tokensPerSecond:null,durationMs:0,status:"error",errorMessage:p.errorMessage,responseBody:void 0})}catch(f){console.error("Fallback usage tracking error:",f)}},Ji(d,e),d.ccrPreHandlerCallbacks=Bi(e),(await Promise.allSettled(u.map(async p=>await d.registerNamespace(`/preset/${p.name}`,p.config)))).forEach((p,f)=>{if(p.status==="rejected"){let _=u[f],k=p.reason instanceof Error?p.reason.message:String(p.reason);d.app?.log?.error?.(`Failed to register preset "${_?.name}": ${k}`)}}),await vi(d,e),lt(e,d.app?.log);let m=p=>{d.app.log.error({err:p},"Uncaught exception")},y=(p,f)=>{d.app.log.error({reason:p,promise:f},"Unhandled rejection")};return process.on("uncaughtException",m),process.on("unhandledRejection",y),d.app.addHook("onClose",async()=>{process.off("uncaughtException",m),process.off("unhandledRejection",y)}),d}var Ki=w(()=>{"use strict";Vi();yi();bn();Ci();xi();$i();Wi();xn();gt();Ee()});import Vu from"fastify";import Yu from"@fastify/cors";function Xu(n={}){let e=Vu({bodyLimit:52428800,...n});return e.setErrorHandler(hr),e.register(Yu),e}async function qu(n={}){return(await Promise.resolve().then(()=>(Ki(),Gi))).createCcrServer(n)}var ur,Qi,qh,Vi=w(()=>{Dn();_t();Mt();$t();lo();po();Ae();Rt();mn();ee();ve();Re();Z();Ee();Mt();Ve();Ee();Ae();Dn();$t();lo();po();jo();Mo();ee();ve();Ro();Re();ee();mn();Je();Z();bn();Jo();xn();Go();Ko();gt();ur=class{app;configService;providerService;transformerService;tokenizerService;activeProbeService;recordUsage;readiness;mainNamespaceRegistered=!1;signalHandlersRegistered=!1;ccrPreHandlerCallbacks;constructor(e={}){let{initialConfig:t,jsonPath:o,envPath:r,useEnvFile:s,useJsonFile:i,useEnvironmentVariables:l,...a}=e;this.app=Xu({...a,logger:a.logger??!0}),this.app._server=this;let c={initialConfig:t};o!==void 0&&(c.jsonPath=o),r!==void 0&&(c.envPath=r),s!==void 0&&(c.useEnvFile=s),i!==void 0&&(c.useJsonFile=i),l!==void 0&&(c.useEnvironmentVariables=l),this.configService=new ke(c),this.transformerService=new Me(this.configService,this.app.log),this.tokenizerService=new $e(this.configService,this.app.log),this.readiness=(async()=>{await Promise.all([this.transformerService.initialize(),this.tokenizerService.initialize()]),this.providerService=new ce(this.configService,this.transformerService,this.app.log)})()}async ready(){await this.readiness}async register(e,t){await this.app.register(e,t)}addHook(e,t){this.app.addHook(e,t)}async registerNamespace(e,t){if(!e)throw new Error("name is required");if(await this.ready(),e==="/"&&this.mainNamespaceRegistered)return;let o=this.configService,r=this.transformerService,s=this.providerService,i=this.tokenizerService;if(e!=="/"){if(!t)throw new Error("options is required");o=new ke({initialConfig:{...t,providers:t.Providers||t.providers}}),r=new Me(o,this.app.log),i=new $e(o,this.app.log),await Promise.all([r.initialize(),i.initialize()]),s=new ce(o,r,this.app.log)}let l=async a=>{a.decorate("configService",o),a.decorate("transformerService",r),a.decorate("providerService",s),a.decorate("tokenizerService",i),a.decorate("recordUsage",this.recordUsage||(()=>{})),a.addHook("preHandler",async(c,u)=>{let d=new URL(`http://127.0.0.1${c.url}`);c.pathname=d.pathname;let g=d.pathname.endsWith("/v1/messages"),m=d.pathname.endsWith("/v1/responses");if(!g&&!m||!c.body||typeof c.body!="object")return;let y=c.ccrHookOrder||=[];if(y.push("request-normalize"),m&&c.body.input&&!c.body.messages&&Ze(c.body),c.body.stream===void 0&&(c.body.stream=!1),c.log.info({data:c.body,type:"request body"}),y.push("adapter"),!c.originalModel&&c.body.model&&(c.originalModel=c.body.model),ge(c,o.getAll()),y.push("auth-client"),!(this.ccrPreHandlerCallbacks&&(await this.ccrPreHandlerCallbacks.authClient(c,u),u.sent))&&(y.push("agent"),!(this.ccrPreHandlerCallbacks&&(await this.ccrPreHandlerCallbacks.agent(c,u),u.sent)))){y.push("router"),c.body?.model&&await At(c,u,{configService:o,tokenizerService:i}),c.usageCacheKey&&V.put(c.usageCacheKey,{input_tokens:0,output_tokens:0,cache_read_input_tokens:0,cache_creation_input_tokens:0}),y.push("provider-model-normalize");try{let p=c.body;if(!p||!p.model)return u.code(400).send({error:"Missing model in request body"});let f=p.model.split(","),_=p.model;if(f.length>1){let[k,...h]=f;_=h.join(","),p.model=_,c.provider=k}c.model=_}catch(p){return c.log.error({error:p},"Error in modelProviderMiddleware:"),u.code(500).send({error:"Internal server error"})}}}),await as(a)};e==="/"?(await this.app.register(l),this.mainNamespaceRegistered=!0):await this.app.register(l,{prefix:e})}async start(){try{if(await this.ready(),await this.registerNamespace("/"),!this.signalHandlersRegistered){this.signalHandlersRegistered=!0;let t=async s=>{this.app.log.info(`Received ${s}, shutting down gracefully...`);try{Po()}catch{}await this.app.close(),process.exit(0)},o=()=>void t("SIGINT"),r=()=>void t("SIGTERM");process.on("SIGINT",o),process.on("SIGTERM",r),this.app.addHook("onClose",async()=>{process.off("SIGINT",o),process.off("SIGTERM",r),this.signalHandlersRegistered=!1;try{this.tokenizerService.dispose()}catch{}await Ln()})}await this.app.ready();let e=await this.app.listen({port:parseInt(this.configService.get("PORT")||"3000",10),host:this.configService.get("HOST")||"127.0.0.1"});this.app.log.info(`\u{1F680} LLMs API server listening on ${e}`);try{Ge()}catch{}try{Ke()}catch{}try{Wn()}catch{}try{let t={enabled:this.configService.get("ACTIVE_PROBE_ENABLED")??!0,quotaProbeIntervalMinutes:this.configService.get("QUOTA_PROBE_INTERVAL_MINUTES")??10,probeTimeoutMs:this.configService.get("PROBE_TIMEOUT_MS")??15e3,slowThresholdMs:Number(this.configService.get("PROBE_SLOW_THRESHOLD_MS"))||3e3,initialDelayMs:this.configService.get("PROBE_INITIAL_DELAY_MS")??5e3,excludeProviders:this.configService.get("EXCLUDE_PROBE_PROVIDERS")??[]};this.activeProbeService=Ne(()=>this.providerService.getProviders(),t,o=>se(this.configService,o),this.app.log,o=>this.configService.get(o))}catch(t){this.app.log.warn?.(`Failed to start active probe service: ${t.message}`)}}catch(e){this.app.log.error(`Error starting server: ${e}`),process.exit(1)}}},Qi=ur;qh=qu});Vi();export{pn as ActiveProbeService,ke as ConfigService,ae as ProjectRoutingError,St as ProviderHealthStore,ce as ProviderService,re as SSEParserTransform,Le as SSESerializerTransform,$e as TokenizerService,Me as TransformerService,Rn as apiKeyAuth,ge as applyClientAdapter,kn as backupConfigFile,zr as builtinClientAdapterRegistry,Ot as calculateTokenCount,qa as clearClientAdapterCaches,vn as clearProviderHealth,Ln as closeProxyDispatchers,ai as collectReachableModelKeys,qu as createCcrServer,Qi as default,Pe as detectClientType,Xr as diagnoseResolutionFailure,Qe as extractSessionIdFromUserId,Ys as getActiveProbeService,to as getAllQuotaResults,Vn as getAllRateLimitInfo,Jr as getClientAdapter,yt as getConfiguredProxyUrl,F as getHealthStore,W as getProxyDispatcher,xo as getQuotaAdapter,wt as getQuotaResult,Oa as getRateLimitInfo,kt as getRuntimeDebugLog,qh as getServer,Bo as initConfig,_n as initDir,Wn as initProviderHealthPersistence,Ke as initQuotaStorePersistence,Ge as initRateLimitPersistence,Br as isClientType,fr as isGlobalProxyEnabled,Sn as listAnthropicCompatibleModels,Tn as mergeUsageCapture,we as normalizeSessionId,Ue as normalizeUsagePayload,nt as pluginManager,ne as readConfigFile,zo as readConfigFileRaw,lt as reconcileHealthStore,fn as resetActiveProbeService,se as resolveProviderProxyUrl,gn as rewriteStream,At as router,es as searchProjectBySession,V as sessionUsageCache,Un as setRuntimeDebugLog,Ne as startActiveProbe,Po as stopActiveProbe,eo as storeQuotaResult,hn as tokenSpeedPlugin,gi as usageStore,Fe as writeConfigFile};
|
|
421
421
|
//# sourceMappingURL=server.mjs.map
|