@wengine-ai/llms 2.3.2412 → 2.3.2413
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 +1 -1
- package/dist/cjs/server.cjs +2 -2
- package/dist/cjs/server.cjs.map +3 -3
- package/dist/esm/server.mjs +2 -2
- package/dist/esm/server.mjs.map +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -93,6 +93,7 @@ npm install -g @wengine-ai/claude-code-router-next@latest && ccr restart
|
|
|
93
93
|
|
|
94
94
|
| 版本 | 发布内容 |
|
|
95
95
|
| --- | --- |
|
|
96
|
+
| **v2.3.2413** | <ul><li>**修复 TTFT 永久为空**: #65(pi 会话粘连)与 #67(temp-file 重写)合并冲突解决时丢失了 #65 的 \`statsKey\` 文件名优先逻辑,handler 用会话 UUID 命名临时文件而 reader 用 requestId 查找 → 永久不匹配 → 所有流式请求的 TTFT 都是 null、tokens_per_second 退化为按完整时长重算。修复后 handler 优先用 \`metadata.statsKey\` 命名文件(对齐 reader),TTFT 与真实速度恢复。</li></ul> |
|
|
96
97
|
| **v2.3.2412** | <ul><li>**修复用量/套餐接口在 node 版本不匹配时全部失效**: 当运行时 Node 的 ABI 与安装 better-sqlite3 时不同(如桌面应用注入自带 node),`ERR_DLOPEN_FAILED` 导致 `/api/usage*`、`/api/providers/quota` 全部 500,UI 用量页与套餐限额条消失。现在优先加载 better-sqlite3,加载失败自动回退 Node 内置 `node:sqlite`(Node ≥ 22.5),任意 node 版本下均可工作;CLI statusline 同步受益;回退时输出一次性显眼日志。</li><li>**修复 pi 模型条目自定义字段被刷新抹除**: `ensurePiCcrProvider` 此前整组替换 `models[]`,pi 的 `thinkingLevelMap` 等条目级自定义字段每次 CCR 启动/项目接管都被静默清掉(#69)。现在模型集合仍由 CCR 管理,但每个生成条目按同 id 与旧条目合并——受管字段以 CCR 为准,条目级自定义字段跨刷新保留。</li></ul> |
|
|
97
98
|
| **v2.3.2411** | <ul><li>**AMD Radeon Cloud 转换器**: 新增 `amd` 转换器:统一 reasoning 意图按目标模型族映射为 AMD 端点支持的 `reasoning_effort` 档位(GLM/Qwen/DeepSeek 分别适配,禁用拼写正确透传),响应侧把 `reasoning` 内容提升为 `thinking`(含 SSE 误标 JSON 边界处理);推荐 provider 链 `use:["OpenAI","amd"]`。</li><li>**Pi 会话粘连**: 识别 `x-session-affinity` 等会话标识头生成稳定会话 ID:并发优先模式的会话槽位跨请求稳定粘附,token-speed 统计与用量记录按稳定会话 ID 分组,兼容 LiteLLM `x-litellm-session-id`,接管刷新后自动写入 pi 配置。</li><li>**修复 token-speed 临时文件堆积导致服务卡死**: 修复按请求写时间戳临时文件且永不清理的问题(单机曾累积 323 万文件,每次请求全目录扫描阻塞事件循环约 33 秒)。写入改为精确文件名原子覆盖并迁移到 `token-speed-v2` 子目录(新旧版本可并存),读取 O(1);新增默认 1 小时保留期自动清理;升级后服务启动自愈,仅清理旧目录中文件名时间戳与修改时间均超过 1 小时的历史文件,不触碰用量库与配置。</li></ul> |
|
|
98
99
|
| **v2.3.2410** | <ul><li>**并发优先模式开关移至通用配置**: 开关从 Router 配置区移到全局设置页「通用配置」区(「去除 Claude Code Attribution 动态头」下方),作为全局开关;配置仍存于 Router 节点,项目 Router 可通过 JSON 覆盖;项目级编辑器不再展示该开关。</li></ul> |
|
|
@@ -102,7 +103,6 @@ npm install -g @wengine-ai/claude-code-router-next@latest && ccr restart
|
|
|
102
103
|
| **v2.3.2406** | <ul><li>**默认思考等级支持自定义值**: 除枚举外可填 token 预算或供应商私有字符串(如 `minimal`/`off`);数字在 Anthropic 端点按精确预算注入、OpenAI 系端点折叠为最接近档位,非枚举字符串在 OpenAI 系端点原样透传、Anthropic 端点按别名归一(min/minimal/light→low、xhigh/maximum/ultra→max);UI 新增「自定义」自由输入。</li><li>**思考深度按 effort 下发**: `convertToAnthropic` 现在同时下发 `output_config.effort`(当前 Anthropic 模型与 GLM 等兼容端点真正读取的字段),`thinking.budget_tokens` 保留以兼容旧模型与中转;客户端原始 effort 不再被丢弃、`thinking.type=adaptive` 不再被误判为关闭思考、预算不再被四舍五入到档位。</li><li>**ZCode 独立客户端归属**: 此前 ZCode 用 `ccr-*` 别名 + Claude Code 兼容 metadata 调用,日志一律记为 claude-code;现按请求头(`User-Agent: ZCode/…`、`X-ZCode-*`)识别并单独计入用量。</li><li>**release.sh 发布中断可续跑**: 重跑自动跳过已发布的包,只发剩余包。</li></ul> |
|
|
103
104
|
| **v2.3.2405** | <ul><li>**供应商级默认思考等级**: 客户端未携带思考配置时按供应商配置的默认等级注入,并按端点类型自动转义——Anthropic `/v1/messages` → `thinking.budget_tokens`、OpenAI `/v1/responses` → `reasoning.effort`、OpenAI 兼容 chat → `reasoning_effort`;客户端显式设置始终优先。附带修复客户端显式 thinking 在 Anthropic 端点被丢弃的问题。</li><li>**预置自引用 `ccr` 供应商(免接管)**: ZCode 等自配端点客户端不再需要接管——CCR 启动/保存配置时自动确保存在指向自身的 `ccr` 供应商(ccr-opus/sonnet/haiku);删除后记 tombstone 不复活。</li><li>**pi 项目 provider 命名可读化**: `ccr-project-<hash>` → `ccr-project-<项目名>-<hash>`,旧格式无需迁移。</li></ul> |
|
|
104
105
|
| **v2.3.2404** | <ul><li>**opencode provider 默认携带 x-opencode-session 会话头**: OpenCode Go 端点强制要求 `x-opencode-session`(缺失直接 400),而 CCR 非透传模式重建上游请求时只带 `Authorization`,客户端会话头全部丢弃,导致 opencode go 供应商(如 `omen-alpha`)全部 400。opencode transformer 现按优先级复用稳定会话 ID:客户端原生 `x-opencode-session` 头 → client adapter 提取的 Claude Code 会话 ID(`metadata.user_id`)→ 请求体兜底提取 → Codex 原生 `session_id` 头 → 回退每请求 UUID;同一会话内值稳定,命中 Go 的路由与 prompt cache 优化。</li></ul> |
|
|
105
|
-
| **v2.3.2403** | <ul><li>**修复 Pi 项目级路由未生效**: Pi 项目接管不再复用无法标识项目的全局 `ccr` provider;每个项目改用携带受管项目 ID 的独立 provider,服务端直接加载对应项目 Router。旧接管会自动迁移,关闭全局 Pi 接管不会破坏项目接管,无效映射也不会静默回落到全局模型。</li></ul> |
|
|
106
106
|
|
|
107
107
|
> 仅保留最近 10 个版本,更早版本的发布摘要见 [CHANGELOG-archive.md](./CHANGELOG-archive.md),完整详细变更记录见 [CHANGELOG.md](./CHANGELOG.md)。
|
|
108
108
|
|
package/dist/cjs/server.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";var Fc=Object.create;var sn=Object.defineProperty;var Uc=Object.getOwnPropertyDescriptor;var jc=Object.getOwnPropertyNames;var Hc=Object.getPrototypeOf,zc=Object.prototype.hasOwnProperty;var E=(n,e)=>()=>(n&&(e=n(n=0)),e);var an=(n,e)=>{for(var t in e)sn(n,t,{get:e[t],enumerable:!0})},hs=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of jc(e))!zc.call(n,r)&&r!==t&&sn(n,r,{get:()=>e[r],enumerable:!(o=Uc(e,r))||o.enumerable});return n};var Z=(n,e,t)=>(t=n!=null?Fc(Hc(n)):{},hs(e||!n||!n.__esModule?sn(t,"default",{value:n,enumerable:!0}):t,n)),ys=n=>hs(sn({},"__esModule",{value:!0}),n);function Jc(n){if(n==null)return{ok:!0};let e=String(n).trim();if(!e)return{ok:!0};if(Bc.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 bs(n){let e=[];for(let t of ks){let o=n[t];if(o==null)continue;let r=Jc(o);r.ok||e.push({key:t,error:r.error})}return e}function yt(n){for(let e of ks){let t=n.get(e);if(t==null)continue;let o=String(t).trim();if(o)return o}}function Mo(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 pe(n,e){let t=yt(n);if(t)return Mo(n.get("PROXY_GLOBAL_ENABLED"))||e?.proxyEnabled===!0||e?.proxy_enabled===!0?t:void 0}function Q(n){let e=Wc(n),t=cn.get(e);if(t)return t;let o=new _s.ProxyAgent(e);return cn.set(e,o),o}async function ln(){let n=Array.from(cn.values());cn.clear(),await Promise.allSettled(n.map(e=>e.close()))}function Wc(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 _s,ks,Bc,cn,ae=E(()=>{"use strict";_s=require("undici"),ks=["HTTPS_PROXY","https_proxy","httpsProxy","PROXY_URL"],Bc=/\$\{[^}]+\}|\$[A-Z_][A-Z0-9_]*/;cn=new Map});var _t,No,Ts,vs,De,$o=E(()=>{"use strict";_t=require("fs"),No=require("path"),Ts=require("dotenv"),vs=Z(require("json5"),1);ae();De=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:(0,No.join)(process.cwd(),this.options.jsonPath);if((0,_t.existsSync)(e))try{let t=(0,_t.readFileSync)(e,"utf-8"),o=vs.default.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:(0,No.join)(process.cwd(),this.options.envPath);if((0,_t.existsSync)(e))try{let t=(0,Ts.config)({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 G(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 xs(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 un=E(()=>{"use strict"});function dn(n){Lo=n}function kt(){return Lo}function pn(n){return Lo||n.get("DEBUG_LOG")===!0}function Rs(n){let e=n.get("DEBUG_LOG_OPTIONS");return!e||typeof e!="object"?Ge:{maxBodyLength:e.maxBodyLength??Ge.maxBodyLength,maxStreamChunks:e.maxStreamChunks??Ge.maxStreamChunks}}function fn(n){let e={};for(let[t,o]of Object.entries(n))Kc.has(t.toLowerCase())?e[t]="***MASKED***":e[t]=o;return e}function mn(n,e){return n.length<=e?n:n.slice(0,e)+`...[truncated, total ${n.length} bytes]`}function ws(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:fn(t.headers),body:mn(o,Ge.maxBodyLength)})}function Es(n,e,t){n.info({debug_log:!0,reqId:e,phase:"provider_response",status:t.status,headers:fn(t.headers),...t.body!==void 0?{body:mn(t.body,Ge.maxBodyLength)}:{}})}function Cs(n,e,t,o){let r=Gc(o);n.info({debug_log:!0,reqId:e,phase:"provider_stream_chunk",chunkIndex:t,...r?{usage_monitor:r}:{},data:mn(o,Ge.maxBodyLength)})}function Gc(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:mn(o,512)})}}if(e.length)return e.length===1?e[0]:e}function Ss(n,e,t){n.info({debug_log:!0,reqId:e,phase:"provider_stream_end",totalChunks:t})}function Ps(n,e,t,o){(async()=>{let r=n.pipeThrough(new TextDecoderStream).getReader(),s=0;try{let i="";for(;;){let{done:a,value:l}=await r.read();if(a)break;i+=l;let c=i.split(`
|
|
2
2
|
|
|
3
|
-
`);i=c.pop()||"";for(let u of c)u.trim()&&(s<o.maxStreamChunks?Cs(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&&Cs(e,t,s,i.trim()),s++),Ss(e,t,s)}catch(i){console.error(`[debug_log] Error reading debug stream for reqId=${t}:`,i),Ss(e,t,s)}finally{r.releaseLock()}})()}var Kc,Ge,Lo,bt=E(()=>{"use strict";Kc=new Set(["authorization","x-api-key","x-goog-api-key","cookie","set-cookie"]),Ge={maxBodyLength:4096,maxStreamChunks:100},Lo=!1});function Os(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,a=AbortSignal.timeout(t.TIMEOUT??60*1e3*60);if(t.signal){let c=new AbortController,u=()=>c.abort();t.signal.addEventListener("abort",u),a.addEventListener("abort",u),i=c.signal}else i=a;let l={method:"POST",headers:s,body:JSON.stringify(e),signal:i};return t.httpsProxy&&(l.dispatcher=Q(t.httpsProxy)),r?.debug({reqId:o.req.id,method:"POST",headers:fn(Object.fromEntries(s.entries())),requestUrl:typeof n=="string"?n:n.toString(),useProxy:Vc(t.httpsProxy)},"final request"),fetch(typeof n=="string"?n:n.toString(),l)}function Vc(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 As=E(()=>{ae();bt()});var gn,Do=E(()=>{gn="2.3.2412"});var Is={};an(Is,{getFallbackPromotionStore:()=>Ve,resetFallbackPromotionStore:()=>Xc});function Ve(n){return Fe||(Fe=new Fo,n&&Fe.configure(n)),Fe}function Xc(){Fe&&(Fe.clearAll(),Fe=null)}var Yc,Fo,Fe,hn=E(()=>{"use strict";ce();Yc=600*1e3,Fo=class{promotions=new Map;enabled=!0;ttlMs=Yc;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 a=this.getKey(e,t,o),l=`${r},${s}`;this.promotions.set(a,{promotedModel:l,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[l,...c]=i.promotedModel.split(","),u=c.join(",");if(!j().isAvailable(l,u))return this.promotions.delete(s),null;let p=r.find(h=>h.name.toLowerCase()===l.toLowerCase()),m=p?.models?.find(h=>String(h).toLowerCase()===u.toLowerCase());return!p||!m||p.enabled===!1?(this.promotions.delete(s),null):`${p.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}},Fe=null});function tl(n){try{if(!(0,he.existsSync)(Ho))return;let e=JSON.parse((0,he.readFileSync)(Ho,"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 Ns(n){try{let e=n.getAllStates();if(e.length===0)return;(0,he.existsSync)(jo)||(0,he.mkdirSync)(jo,{recursive:!0});let t=e.map(o=>({...o,updatedAt:Date.now()}));(0,he.writeFileSync)(Ho,JSON.stringify(t,null,2),"utf-8")}catch{}}function yn(){if(Ms)return;Ms=!0;let n=j();tl(n),el=setInterval(()=>Ns(n),6e4),process.on("exit",()=>Ns(n))}function j(n){return Uo||(Uo=new Tt(n)),Uo}var he,zo,$s,Zc,qc,Tt,jo,Ho,Ms,el,Uo,ce=E(()=>{"use strict";he=require("fs"),zo=require("path"),$s=require("@wengine-ai/claude-code-router-shared"),Zc=120,qc={enabled:!0,failureThreshold:3,probeIntervalMinutes:5,halfOpenSuccessThreshold:2},Tt=class{states=new Map;config;probeTimer;constructor(e){this.config={...qc,...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}=(hn(),ys(Is));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 a=(o??Zc)*1e3;i.rateLimitUntil=Date.now()+a}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)}},jo=(0,zo.join)($s.HOME_DIR,"runtime"),Ho=(0,zo.join)(jo,"provider-health.json"),Ms=!1,el=null;Uo=null});function vt(n,e,t){let o=a=>{if(t instanceof Headers)return t.get(a);let l=Object.keys(t).find(c=>c.toLowerCase()===a);return l?t[l]:null},r=Bo(o,nl),s=Bo(o,ol),i=Bo(o,rl);(r||s||i)&&Qe.set(n,{provider:n,remaining:Fs(r),limit:Fs(s),reset:sl(i),capturedAt:Date.now()})}function Hs(n){return Qe.get(n)}function _n(){return Array.from(Qe.values())}function Bo(n,e){for(let t of e){let o=n(t);if(o)return o}return null}function Fs(n){if(!n)return null;let e=Number(n.trim().replace(/,/g,""));return Number.isFinite(e)?e:null}function sl(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=il(e);return r===null?null:Math.floor((Date.now()+r)/1e3)}function il(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 al(){try{if(!(0,ye.existsSync)(Wo))return;let n=JSON.parse((0,ye.readFileSync)(Wo,"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;Qe.set(t.provider,t)}}catch{}}function Us(){try{if(Qe.size===0)return;(0,ye.existsSync)(Jo)||(0,ye.mkdirSync)(Jo,{recursive:!0}),(0,ye.writeFileSync)(Wo,JSON.stringify(Array.from(Qe.values()),null,2),"utf-8")}catch{}}function Ye(){Ls||(Ls=!0,al(),Ds=setInterval(Us,6e4),Ds.unref?.(),process.on("exit",Us))}var ye,Ko,js,Jo,Wo,Qe,Ls,Ds,nl,ol,rl,Xe=E(()=>{"use strict";ye=require("fs"),Ko=require("path"),js=require("@wengine-ai/claude-code-router-shared"),Jo=(0,Ko.join)(js.HOME_DIR,"runtime"),Wo=(0,Ko.join)(Jo,"rate-limit.json"),Qe=new Map,Ls=!1,Ds=null,nl=["x-ratelimit-remaining-tokens","x-ratelimit-remaining-requests","x-ratelimit-remaining"],ol=["x-ratelimit-limit-tokens","x-ratelimit-limit-requests","x-ratelimit-limit"],rl=["x-ratelimit-reset-tokens","x-ratelimit-reset-requests","x-ratelimit-reset"]});function bn(){return Go||(Go=new Qo),Go}function Xo(){return Vo||(Vo=new Yo),Vo}function cl(n){return n?.sessionId||n?.clientContext?.stableSessionId||void 0}function zs(n){let e=cl(n);if(!e)return"";let t=typeof n?.modelFamily=="string"?n.modelFamily:"",o=typeof n?.scenarioType=="string"&&n.scenarioType?n.scenarioType:"default";return`${e}:${t}:${o}`}function Bs(n,e){let t=bn(),o=n?.[kn];if(o&&!o.released){if(o.key===e)return;t.release(o)}n[kn]=t.acquire(e)}function Zo(n){let e=n?.[kn];e&&bn().release(e)}function Js(n,e){let t=zs(n),o=n?.[kn],r=t?Xo().get(t)!==void 0:!1;!o&&!r||(t&&Xo().bind(t,e),Bs(n,e))}function ll(n,e,t){let o=bn(),r=null,s=1/0;for(let i of e){if(!i||typeof i!="string")continue;let a=t(i);if(!a||a===n)continue;let l=o.count(a);l<s&&(r=a,s=l)}return r}function Ws(n,e,t){let o=zs(n),r=Xo(),s=bn(),i=Number.isFinite(t.threshold)&&t.threshold>0?Math.floor(t.threshold):3,a;if(o){let l=r.get(o);if(l&&l!==e){let c=t.resolve(l);c?(a=c,t.log?.(`Concurrency priority: session slot ${o} sticking to bound model ${c}`)):r.unbind(o)}else l&&(a=e)}if(!a){let l=s.count(e);if(l>=i){let c=ll(e,t.fallbackModels,t.resolve);c&&(a=c,t.log?.(`Concurrency priority: model ${e} has ${l} in-flight request(s) (>= ${i}); assigning ${o?`session slot ${o} `:"request "}to overflow model ${c}`))}a=a||e,o&&r.bind(o,a)}return Bs(n,a),a}var Qo,Yo,Go,Vo,kn,Tn=E(()=>{"use strict";Qo=class{leases=new Map;nextId=1;acquire(e){let t={id:this.nextId++,key:e,createdAt:Date.now(),released:!1};return this.leases.set(t.id,t),t}release(e){!e||e.released||(e.released=!0,this.leases.delete(e.id))}prune(){let e=Date.now();for(let[t,o]of this.leases)e-o.createdAt>18e5&&this.leases.delete(t)}count(e){this.prune();let t=0;for(let o of this.leases.values())o.key===e&&t++;return t}clear(){this.leases.clear()}},Yo=class{bindings=new Map;get(e){let t=this.bindings.get(e);if(t){if(Date.now()-t.updatedAt>864e5){this.bindings.delete(e);return}return t.updatedAt=Date.now(),this.bindings.delete(e),this.bindings.set(e,t),t.modelKey}}bind(e,t){for(this.bindings.delete(e),this.bindings.set(e,{modelKey:t,updatedAt:Date.now()});this.bindings.size>2e3;){let o=this.bindings.keys().next().value;if(o===void 0)break;this.bindings.delete(o)}}unbind(e){this.bindings.delete(e)}clear(){this.bindings.clear()}},Go=null,Vo=null;kn="__concurrencyLease"});async function U(n){let e=await n.text();return ul(e,n.status)}function ul(n,e){let t=n.replace(/^/,"").trim();try{return JSON.parse(t)}catch{let o=t.length>200?`${t.slice(0,200)}...`:t,r=e!==void 0?` (HTTP ${e})`:"";throw new Error(`Upstream returned a non-JSON response${r}: ${o||"(empty body)"}`)}}function Ks(n){return(n.headers.get("Content-Type")||"").includes("text/event-stream")}function xt(n){return/^\s*(event:|data:|:\s*[A-Z])/m.test(n)||n.startsWith("data:")}async function Ce(n){if(!n.body||n.body.locked)return null;let[e,t]=n.body.tee(),o=e.getReader(),r=new TextDecoder,s="";try{for(let i=0;i<8;i++){let{value:a,done:l}=await o.read();if(l||(a&&(s+=r.decode(a,{stream:!0})),xt(s))||/^\s*[\[{]/.test(s))break}s+=r.decode()}finally{o.releaseLock()}return e.cancel().catch(()=>{}),{body:t,isSSE:xt(s)}}async function Se(n){try{let e=await n.text();if(xt(e)){let o=new TextEncoder,r=new ReadableStream({start(s){s.enqueue(o.encode(e)),s.close()}});return{response:new Response(r,{status:n.status,statusText:n.statusText,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}}),isSSE:!0}}return{response:new Response(e,{status:n.status,statusText:n.statusText,headers:n.headers}),isSSE:!1}}catch{return{response:n,isSSE:!1}}}var q=E(()=>{"use strict"});var Ze,qo=E(()=>{"use strict";q();Ze=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 Ce(e);if(o?.isSSE&&o.body){let r=new Response(o.body,{status:e.status,statusText:e.statusText,headers:new Headers({...Object.fromEntries(e.headers.entries()),"content-type":"text/event-stream"})});return this.transformResponseOut(r)}if(o?.body)e=new Response(o.body,{status:e.status,statusText:e.statusText,headers:e.headers});else if(o===null){let r=await Se(e);if(r.isSSE)return this.transformResponseOut(r.response);e=r.response}}if(t.includes("application/json")){let o=await U(e);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,p="",m=!1,h=this,g=new ReadableStream({async start(f){let _=c.getReader(),k=-1,y="",b=T=>(T!==y&&(k++,y=T),k);try{for(;;){let{done:T,value:C}=await _.read();if(T){m||f.enqueue(d.encode(`data: [DONE]
|
|
3
|
+
`);i=c.pop()||"";for(let u of c)u.trim()&&(s<o.maxStreamChunks?Cs(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&&Cs(e,t,s,i.trim()),s++),Ss(e,t,s)}catch(i){console.error(`[debug_log] Error reading debug stream for reqId=${t}:`,i),Ss(e,t,s)}finally{r.releaseLock()}})()}var Kc,Ge,Lo,bt=E(()=>{"use strict";Kc=new Set(["authorization","x-api-key","x-goog-api-key","cookie","set-cookie"]),Ge={maxBodyLength:4096,maxStreamChunks:100},Lo=!1});function Os(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,a=AbortSignal.timeout(t.TIMEOUT??60*1e3*60);if(t.signal){let c=new AbortController,u=()=>c.abort();t.signal.addEventListener("abort",u),a.addEventListener("abort",u),i=c.signal}else i=a;let l={method:"POST",headers:s,body:JSON.stringify(e),signal:i};return t.httpsProxy&&(l.dispatcher=Q(t.httpsProxy)),r?.debug({reqId:o.req.id,method:"POST",headers:fn(Object.fromEntries(s.entries())),requestUrl:typeof n=="string"?n:n.toString(),useProxy:Vc(t.httpsProxy)},"final request"),fetch(typeof n=="string"?n:n.toString(),l)}function Vc(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 As=E(()=>{ae();bt()});var gn,Do=E(()=>{gn="2.3.2413"});var Is={};an(Is,{getFallbackPromotionStore:()=>Ve,resetFallbackPromotionStore:()=>Xc});function Ve(n){return Fe||(Fe=new Fo,n&&Fe.configure(n)),Fe}function Xc(){Fe&&(Fe.clearAll(),Fe=null)}var Yc,Fo,Fe,hn=E(()=>{"use strict";ce();Yc=600*1e3,Fo=class{promotions=new Map;enabled=!0;ttlMs=Yc;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 a=this.getKey(e,t,o),l=`${r},${s}`;this.promotions.set(a,{promotedModel:l,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[l,...c]=i.promotedModel.split(","),u=c.join(",");if(!j().isAvailable(l,u))return this.promotions.delete(s),null;let p=r.find(h=>h.name.toLowerCase()===l.toLowerCase()),m=p?.models?.find(h=>String(h).toLowerCase()===u.toLowerCase());return!p||!m||p.enabled===!1?(this.promotions.delete(s),null):`${p.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}},Fe=null});function tl(n){try{if(!(0,he.existsSync)(Ho))return;let e=JSON.parse((0,he.readFileSync)(Ho,"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 Ns(n){try{let e=n.getAllStates();if(e.length===0)return;(0,he.existsSync)(jo)||(0,he.mkdirSync)(jo,{recursive:!0});let t=e.map(o=>({...o,updatedAt:Date.now()}));(0,he.writeFileSync)(Ho,JSON.stringify(t,null,2),"utf-8")}catch{}}function yn(){if(Ms)return;Ms=!0;let n=j();tl(n),el=setInterval(()=>Ns(n),6e4),process.on("exit",()=>Ns(n))}function j(n){return Uo||(Uo=new Tt(n)),Uo}var he,zo,$s,Zc,qc,Tt,jo,Ho,Ms,el,Uo,ce=E(()=>{"use strict";he=require("fs"),zo=require("path"),$s=require("@wengine-ai/claude-code-router-shared"),Zc=120,qc={enabled:!0,failureThreshold:3,probeIntervalMinutes:5,halfOpenSuccessThreshold:2},Tt=class{states=new Map;config;probeTimer;constructor(e){this.config={...qc,...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}=(hn(),ys(Is));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 a=(o??Zc)*1e3;i.rateLimitUntil=Date.now()+a}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)}},jo=(0,zo.join)($s.HOME_DIR,"runtime"),Ho=(0,zo.join)(jo,"provider-health.json"),Ms=!1,el=null;Uo=null});function vt(n,e,t){let o=a=>{if(t instanceof Headers)return t.get(a);let l=Object.keys(t).find(c=>c.toLowerCase()===a);return l?t[l]:null},r=Bo(o,nl),s=Bo(o,ol),i=Bo(o,rl);(r||s||i)&&Qe.set(n,{provider:n,remaining:Fs(r),limit:Fs(s),reset:sl(i),capturedAt:Date.now()})}function Hs(n){return Qe.get(n)}function _n(){return Array.from(Qe.values())}function Bo(n,e){for(let t of e){let o=n(t);if(o)return o}return null}function Fs(n){if(!n)return null;let e=Number(n.trim().replace(/,/g,""));return Number.isFinite(e)?e:null}function sl(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=il(e);return r===null?null:Math.floor((Date.now()+r)/1e3)}function il(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 al(){try{if(!(0,ye.existsSync)(Wo))return;let n=JSON.parse((0,ye.readFileSync)(Wo,"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;Qe.set(t.provider,t)}}catch{}}function Us(){try{if(Qe.size===0)return;(0,ye.existsSync)(Jo)||(0,ye.mkdirSync)(Jo,{recursive:!0}),(0,ye.writeFileSync)(Wo,JSON.stringify(Array.from(Qe.values()),null,2),"utf-8")}catch{}}function Ye(){Ls||(Ls=!0,al(),Ds=setInterval(Us,6e4),Ds.unref?.(),process.on("exit",Us))}var ye,Ko,js,Jo,Wo,Qe,Ls,Ds,nl,ol,rl,Xe=E(()=>{"use strict";ye=require("fs"),Ko=require("path"),js=require("@wengine-ai/claude-code-router-shared"),Jo=(0,Ko.join)(js.HOME_DIR,"runtime"),Wo=(0,Ko.join)(Jo,"rate-limit.json"),Qe=new Map,Ls=!1,Ds=null,nl=["x-ratelimit-remaining-tokens","x-ratelimit-remaining-requests","x-ratelimit-remaining"],ol=["x-ratelimit-limit-tokens","x-ratelimit-limit-requests","x-ratelimit-limit"],rl=["x-ratelimit-reset-tokens","x-ratelimit-reset-requests","x-ratelimit-reset"]});function bn(){return Go||(Go=new Qo),Go}function Xo(){return Vo||(Vo=new Yo),Vo}function cl(n){return n?.sessionId||n?.clientContext?.stableSessionId||void 0}function zs(n){let e=cl(n);if(!e)return"";let t=typeof n?.modelFamily=="string"?n.modelFamily:"",o=typeof n?.scenarioType=="string"&&n.scenarioType?n.scenarioType:"default";return`${e}:${t}:${o}`}function Bs(n,e){let t=bn(),o=n?.[kn];if(o&&!o.released){if(o.key===e)return;t.release(o)}n[kn]=t.acquire(e)}function Zo(n){let e=n?.[kn];e&&bn().release(e)}function Js(n,e){let t=zs(n),o=n?.[kn],r=t?Xo().get(t)!==void 0:!1;!o&&!r||(t&&Xo().bind(t,e),Bs(n,e))}function ll(n,e,t){let o=bn(),r=null,s=1/0;for(let i of e){if(!i||typeof i!="string")continue;let a=t(i);if(!a||a===n)continue;let l=o.count(a);l<s&&(r=a,s=l)}return r}function Ws(n,e,t){let o=zs(n),r=Xo(),s=bn(),i=Number.isFinite(t.threshold)&&t.threshold>0?Math.floor(t.threshold):3,a;if(o){let l=r.get(o);if(l&&l!==e){let c=t.resolve(l);c?(a=c,t.log?.(`Concurrency priority: session slot ${o} sticking to bound model ${c}`)):r.unbind(o)}else l&&(a=e)}if(!a){let l=s.count(e);if(l>=i){let c=ll(e,t.fallbackModels,t.resolve);c&&(a=c,t.log?.(`Concurrency priority: model ${e} has ${l} in-flight request(s) (>= ${i}); assigning ${o?`session slot ${o} `:"request "}to overflow model ${c}`))}a=a||e,o&&r.bind(o,a)}return Bs(n,a),a}var Qo,Yo,Go,Vo,kn,Tn=E(()=>{"use strict";Qo=class{leases=new Map;nextId=1;acquire(e){let t={id:this.nextId++,key:e,createdAt:Date.now(),released:!1};return this.leases.set(t.id,t),t}release(e){!e||e.released||(e.released=!0,this.leases.delete(e.id))}prune(){let e=Date.now();for(let[t,o]of this.leases)e-o.createdAt>18e5&&this.leases.delete(t)}count(e){this.prune();let t=0;for(let o of this.leases.values())o.key===e&&t++;return t}clear(){this.leases.clear()}},Yo=class{bindings=new Map;get(e){let t=this.bindings.get(e);if(t){if(Date.now()-t.updatedAt>864e5){this.bindings.delete(e);return}return t.updatedAt=Date.now(),this.bindings.delete(e),this.bindings.set(e,t),t.modelKey}}bind(e,t){for(this.bindings.delete(e),this.bindings.set(e,{modelKey:t,updatedAt:Date.now()});this.bindings.size>2e3;){let o=this.bindings.keys().next().value;if(o===void 0)break;this.bindings.delete(o)}}unbind(e){this.bindings.delete(e)}clear(){this.bindings.clear()}},Go=null,Vo=null;kn="__concurrencyLease"});async function U(n){let e=await n.text();return ul(e,n.status)}function ul(n,e){let t=n.replace(/^/,"").trim();try{return JSON.parse(t)}catch{let o=t.length>200?`${t.slice(0,200)}...`:t,r=e!==void 0?` (HTTP ${e})`:"";throw new Error(`Upstream returned a non-JSON response${r}: ${o||"(empty body)"}`)}}function Ks(n){return(n.headers.get("Content-Type")||"").includes("text/event-stream")}function xt(n){return/^\s*(event:|data:|:\s*[A-Z])/m.test(n)||n.startsWith("data:")}async function Ce(n){if(!n.body||n.body.locked)return null;let[e,t]=n.body.tee(),o=e.getReader(),r=new TextDecoder,s="";try{for(let i=0;i<8;i++){let{value:a,done:l}=await o.read();if(l||(a&&(s+=r.decode(a,{stream:!0})),xt(s))||/^\s*[\[{]/.test(s))break}s+=r.decode()}finally{o.releaseLock()}return e.cancel().catch(()=>{}),{body:t,isSSE:xt(s)}}async function Se(n){try{let e=await n.text();if(xt(e)){let o=new TextEncoder,r=new ReadableStream({start(s){s.enqueue(o.encode(e)),s.close()}});return{response:new Response(r,{status:n.status,statusText:n.statusText,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}}),isSSE:!0}}return{response:new Response(e,{status:n.status,statusText:n.statusText,headers:n.headers}),isSSE:!1}}catch{return{response:n,isSSE:!1}}}var q=E(()=>{"use strict"});var Ze,qo=E(()=>{"use strict";q();Ze=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 Ce(e);if(o?.isSSE&&o.body){let r=new Response(o.body,{status:e.status,statusText:e.statusText,headers:new Headers({...Object.fromEntries(e.headers.entries()),"content-type":"text/event-stream"})});return this.transformResponseOut(r)}if(o?.body)e=new Response(o.body,{status:e.status,statusText:e.statusText,headers:e.headers});else if(o===null){let r=await Se(e);if(r.isSSE)return this.transformResponseOut(r.response);e=r.response}}if(t.includes("application/json")){let o=await U(e);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,p="",m=!1,h=this,g=new ReadableStream({async start(f){let _=c.getReader(),k=-1,y="",b=T=>(T!==y&&(k++,y=T),k);try{for(;;){let{done:T,value:C}=await _.read();if(T){m||f.enqueue(d.encode(`data: [DONE]
|
|
4
4
|
|
|
5
5
|
`));break}let v=u.decode(C,{stream:!0});p+=v;let S=p.split(/\r?\n/);p=S.pop()||"";for(let x of S)if(x.trim())try{if(x.startsWith("event: "))continue;if(x.startsWith("data: ")){let w=x.slice(5).trim();if(w==="[DONE]"){m=!0,f.enqueue(d.encode(`data: [DONE]
|
|
6
6
|
|
|
@@ -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 Ut,Ur=E(()=>{"use strict";Ut=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||{},a={data:e};return r&&(a.timestamp=new Date().toISOString()),s&&(a.prefix=s),i&&Object.keys(i).length>0&&(a.metadata=i),a}async sendRequest(e,t,o,r,s){let i=new AbortController,a=setTimeout(()=>i.abort(),s);try{let l=await fetch(e,{method:t,headers:o,body:JSON.stringify(r),signal:i.signal});if(clearTimeout(a),!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText}`);return l}catch(l){throw clearTimeout(a),l}}delay(e){return new Promise(t=>setTimeout(t,e))}async sendWithRetry(e,t,o,r,s,i){let a=null;for(let l=1;l<=i.maxAttempts;l++)try{return await this.sendRequest(e,t,o,r,s)}catch(c){if(a=c,l===i.maxAttempts)break;let u=i.backoffMs*Math.pow(2,l-1);console.warn(`[WebhookOutputHandler] Request failed (attempt ${l}/${i.maxAttempts}), retrying in ${u}ms...`,c.message),await this.delay(u)}throw a}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}`)}}}});async function ko(n,e){let t=(0,We.resolve)(n),o=_o.get(t),r,s=new Promise(i=>{r=i});_o.set(t,s);try{return await o,await e()}finally{r(),_o.get(t)===s&&_o.delete(t)}}function Ra(n,e){return n.dev===e.dev&&n.ino===e.ino}async function Ca(n,e){try{let t=await(0,ve.lstat)(n);return t.isDirectory()&&!t.isSymbolicLink()&&Ra(e,t)}catch{return!1}}function Ku(){return new Promise(n=>{setTimeout(n,10).unref()})}async function wa(n,e,t,o){let r=(0,We.resolve)(n);if(o?.aborted||jr.has(r))return 0;jr.add(r);let s=0;try{let i=await(0,ve.lstat)(r);if(!i.isDirectory()||i.isSymbolicLink()||o?.aborted)return 0;let a=await(0,ve.opendir)(r,{bufferSize:32});try{let l=0,c=!0;for await(let u of a){if(o?.aborted||!c)break;try{if(!u.isFile()||u.isSymbolicLink()||!t(u.name))continue;let d=(0,We.join)(r,u.name);try{let p=await(0,ve.lstat)(d);if(!p.isFile()||p.isSymbolicLink()||p.mtimeMs>=e)continue;await ko(d,async()=>{if(o?.aborted||!await Ca(r,i))return!1;let h=await(0,ve.lstat)(d);return!h.isFile()||h.isSymbolicLink()||!Ra(p,h)||h.mtimeMs!==p.mtimeMs||h.mtimeMs>=e||o?.aborted?!1:(await(0,ve.unlink)(d),!0)})&&s++}catch{}}finally{++l%64===0&&(await Ku(),c=!o?.aborted&&await Ca(r,i))}}}finally{await a.close().catch(()=>{})}}catch{}finally{jr.delete(r)}return s}function Ea(n,e,t,o,r){if(!Number.isFinite(o)||o<=0)return Promise.resolve(0);let s=`${e}-`,i=t?`.${t}`:"";return wa(n,Date.now()-o,a=>Wu.test(a)?!0:!a.endsWith(".tmp")&&a.startsWith(s)&&a.endsWith(i),r)}function Gu(n,e){let t=Date.now()-zu;return wa(n,t,o=>{let r=Ju.exec(o);return r!==null&&Number(r[1])<t},e)}function zr(n,e,t){let o=Hr.get(n);if(!o){let s=new AbortController,i,a=()=>{s.signal.aborted||Promise.resolve().then(()=>e(s.signal)).catch(()=>{})},l=setTimeout(()=>{s.signal.aborted||(a(),i=setInterval(a,Bu),i.unref())},t);l.unref(),o={users:0,stop:()=>{s.abort(),clearTimeout(l),i&&clearInterval(i)}},Hr.set(n,o)}o.users++;let r=!1;return()=>{r||(r=!0,--o.users===0&&(o.stop(),Hr.delete(n)))}}function Pa(n=(0,We.join)((0,Sa.tmpdir)(),"claude-code-router")){return zr(`legacy:${(0,We.resolve)(n)}`,e=>Gu(n,e),1e3)}var ve,We,Sa,zu,Bu,Ju,Wu,jr,_o,Hr,Br=E(()=>{"use strict";ve=require("node:fs/promises"),We=require("node:path"),Sa=require("node:os"),zu=3600*1e3,Bu=600*1e3,Ju=/^session-[A-Za-z0-9_.-]+-(\d{13})\.json$/,Wu=/^\.ccr-tmp-[1-9]\d*-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.tmp$/,jr=new Set,_o=new Map,Hr=new Map});var ge,Oa,Aa,Pe,Ia,jt,Jr=E(()=>{"use strict";ge=require("node:fs/promises"),Oa=require("node:crypto"),Aa=require("@wengine-ai/claude-code-router-shared"),Pe=require("node:path"),Ia=require("node:os");Br();jt=class{type="temp-file";config;baseDir;controller=new AbortController;stopSchedule;constructor(e={}){if(this.config={subdirectory:"claude-code-router",extension:"json",includeTimestamp:!1,prefix:"session",retentionMs:36e5,...e},this.baseDir=(0,Pe.resolve)((0,Pe.join)((0,Ia.tmpdir)(),this.config.subdirectory)),Number.isFinite(this.config.retentionMs)&&this.config.retentionMs>0){let t=JSON.stringify([this.baseDir,this.config.prefix,this.config.extension,this.config.retentionMs]);this.stopSchedule=zr(`handler:${t}`,o=>this.pruneOldFiles(o),6e4)}}async ensureDir(){await(0,ge.mkdir)(this.baseDir,{recursive:!0});let e=await(0,ge.lstat)(this.baseDir);if(!e.isDirectory()||e.isSymbolicLink())throw new Error("Unsafe temp output directory")}getFilePath(e){let t=this.config.prefix||"session",o=this.config.extension?`.${this.config.extension}`:"",r=this.config.includeTimestamp?`-${Date.now()}`:"",s=`${t}-${(0,Aa.sanitizeTempFileKey)(e)}${r}${o}`;if((0,Pe.basename)(s)!==s||s.includes("\\"))throw new Error("Temp file configuration must not contain path separators");return(0,Pe.join)(this.baseDir,s)}async output(e,t={}){try{let o=t.metadata?.sessionId;if(!o)return!1;let r=JSON.stringify({...e,timestamp:Date.now(),sessionId:o},null,2),s=this.getFilePath(o);return await ko(s,async()=>{await this.ensureDir();let i=(0,Pe.join)(this.baseDir,`.ccr-tmp-${process.pid}-${(0,Oa.randomUUID)()}.tmp`);return ko(i,async()=>{let a=!1;try{let l=await(0,ge.open)(i,"wx");a=!0;try{await l.writeFile(r,"utf-8")}finally{await l.close()}return await(0,ge.rename)(i,s),!0}finally{a&&await(0,ge.unlink)(i).catch(()=>{})}})})}catch{return!1}}pruneOldFiles(e=this.controller.signal){return Ea(this.baseDir,this.config.prefix||"session",this.config.extension||"",this.config.retentionMs,e)}dispose(){this.controller.abort(),this.stopSchedule?.()}getBaseDir(){return this.baseDir}}});var Wr,pt,Ma=E(()=>{"use strict";Fr();Ur();Jr();Wr=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 Ft(e.config);case"webhook":return new Ut(e.config);case"temp-file":return new jt(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,a])=>{try{await a.output(e,o)?r.success.push(i):r.failed.push(i)}catch(l){console.error(`[OutputManager] Handler ${i} failed:`,l),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 a=>{let l=this.handlers.get(a);if(!l){console.warn(`[OutputManager] Handler ${a} not found`),s.failed.push(a);return}try{await l.output(t,r)?s.success.push(a):s.failed.push(a)}catch(c){console.error(`[OutputManager] Handler ${a} failed:`,c),s.failed.push(a)}});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)}},pt=new Wr});var Kr=E(()=>{"use strict";xa();Fr();Ur();Jr();Ma()});function bo(){return{subdirectory:Da.TOKEN_SPEED_TEMP_SUBDIRECTORY,extension:"json",includeTimestamp:!1,prefix:"session"}}function Na(n,e,t=0){if(n<=0)return 0;let o=Math.max((e-t)/1e3,Vu);return Math.round(n/o)}function zt(n){let e=(n.match(/[\u4e00-\u9fa5]/g)||[]).length,t=n.length-e;return Math.ceil(e/1.5+t/4)}async function $a(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,statsKey:n.statsKey},...t};for(let a of e)try{await pt.outputToType(a,s,i)}catch(l){console.error(`[TokenSpeedPlugin] Failed to output to ${a}:`,l)}}var La,Da,Ht,Gr,Vu,Bt,Fa=E(()=>{"use strict";La=Z(require("fastify-plugin"),1);Dr();Kr();nt();Da=require("@wengine-ai/claude-code-router-shared");Ht=new Map,Gr=new Map,Vu=1,Bt={name:"token-speed",version:"1.0.0",description:"Statistics for streaming response token generation speed",register:(0,La.default)(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)pt.registerHandlers(t.outputHandlers);else{let i=[];for(let a of o)a==="console"?i.push({type:"console",enabled:!0,config:{colors:!0,level:"log"}}):a==="temp-file"?i.push({type:"temp-file",enabled:!0,config:bo()}):a==="webhook"&&console.warn("[TokenSpeedPlugin] Webhook reporter requires explicit configuration in outputHandlers");i.length>0&&pt.registerHandlers(i)}t.outputOptions&&pt.setDefaultOptions(t.outputOptions);let r=async i=>{let a=n.tokenizerService;if(!a)return n.log?.warn("TokenizerService not available"),null;if(!i.provider||!i.model)return null;let l=i.provider,c=i.model,u=`${l}:${c}`;if(Gr.has(u))return Gr.get(u);let d=a.getTokenizerConfigForModel(l,c);if(!d)return n.log?.debug(`No tokenizer config for ${l}:${c}, using fallback`),null;try{let p=await a.getTokenizer(d,l);return Gr.set(u,p),n.log?.info(`Created tokenizer for ${l}:${c} - ${p.name}`),p}catch(p){return n.log?.warn(`Failed to create tokenizer for ${l}:${c}: ${p.message}`),null}},s=i=>{let a=new URL(`http://127.0.0.1${i}`).pathname;return a.endsWith("/v1/messages")||a.endsWith("/v1/responses")};n.addHook("onRequest",async i=>{s(i.url)&&(i.requestStartTime=performance.now())}),n.addHook("onSend",async(i,a,l)=>{let c=i.requestStartTime;if(!c)return;let u=i.id||Date.now().toString(),d=i.usageSessionId||u,p=i.sessionId;if(!p)try{p=be(i.body?.metadata?.user_id)||d}catch{p=d}let m=await r(i);if(l instanceof ReadableStream){Ht.set(u,{requestId:u,sessionId:p,statsKey:d,startTime:c,lastTokenTime:c,tokenCount:0,tokensPerSecond:0,stream:!0});let[_,k]=l.tee(),y=async()=>{let b=null,T=async C=>{let v=Ht.get(u);if(!v)return;let S=v.firstTokenTime?v.firstTokenTime-v.startTime:0,w=(C?v.lastTokenTime:performance.now())-v.startTime;v.tokensPerSecond=Na(v.tokenCount,w,S),await $a(v,o,t.outputOptions,C).catch(R=>{n.log?.warn(`Failed to output streaming stats: ${R.message}`)})};try{let v=k.pipeThrough(new TextDecoderStream).pipeThrough(new de).getReader();for(b=setInterval(async()=>{Ht.get(u)&&await T(!1)},1e3);;){let{done:S,value:x}=await v.read();if(S)break;let w=x,R=Ht.get(u);if(!R)continue;let A=performance.now(),P=w.event||w.data?.type,N=w.event==="content_block_start"||w.event==="content_block_delta"||w.event==="text_block"||w.event==="content_block"||P==="response.output_text.delta"||P==="response.function_call_arguments.delta"||P==="response.reasoning_summary_text.delta";!R.firstTokenTime&&N&&(R.firstTokenTime=A,R.timeToFirstToken=Math.round(A-R.startTime));let L="";if(w.event==="content_block_delta"&&w.data?.delta){let D=w.data.delta.type;D==="text_delta"?L=w.data.delta.text||"":D==="input_json_delta"?L=w.data.delta.partial_json||"":D==="thinking_delta"&&(L=w.data.delta.thinking||"")}if((P==="response.output_text.delta"||P==="response.function_call_arguments.delta"||P==="response.reasoning_summary_text.delta")&&(L=typeof w.data?.delta=="string"?w.data.delta:""),L){let D=m&&m.encodeText?m.encodeText(L).length:zt(L);R.tokenCount+=D,R.lastTokenTime=A}(w.event==="message_stop"||P==="response.completed"||P==="response.failed")&&(b&&(clearInterval(b),b=null),await T(!0),Ht.delete(u))}}catch(C){b&&clearInterval(b),C.name!=="AbortError"&&C.code!=="ERR_STREAM_PREMATURE_CLOSE"&&n.log?.warn(`Error processing token stats: ${C.message}`)}};return i.tokenSpeedCapturePromise=y().catch(b=>{console.log(b),n.log?.warn(`Background stats processing failed: ${b.message}`)}),_}let h=performance.now(),g=0,f=!1;if(l&&typeof l=="string")try{let _=JSON.parse(l);if(typeof _.usage?.output_tokens=="number")g=_.usage.output_tokens,f=!0;else{let k=_.content??_.message?.content;if(k!==void 0)if(f=!0,m)Array.isArray(k)?g=k.reduce((y,b)=>{if(b.type==="text"){let T=b.text||"";return y+(m.encodeText?m.encodeText(T).length:zt(T))}return y},0):typeof k=="string"&&(g=m.encodeText?m.encodeText(k).length:zt(k));else{let y=Array.isArray(k)?k.map(b=>b.text).join(""):typeof k=="string"?k:"";g=zt(y)}}}catch{}if(f){let _=h-c,k={requestId:u,sessionId:p,statsKey:d,startTime:c,lastTokenTime:h,tokenCount:g,tokensPerSecond:Na(g,_),stream:!1};await $a(k,o,t.outputOptions,!0)}return l})})}});var Vr=E(()=>{"use strict";Ta();va();Fa();Kr()});function Ua(){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 oe,Yr,Oe,W,Qr,Jt,Wt,To,ie,Kt,xe,Qu,vo,xo=E(()=>{"use strict";oe=Z(require("node:fs/promises"),1),Yr=Z(require("json5"),1),Oe=Z(require("node:path"),1),W=require("@wengine-ai/claude-code-router-shared"),Qr=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(Qr);if(n!==null&&typeof n=="object"){let e={};for(let[t,o]of Object.entries(n))e[t]=Qr(o);return e}return n},Jt=async n=>{try{await oe.default.access(n)}catch{await oe.default.mkdir(n,{recursive:!0})}},Wt=async()=>{await Jt(W.HOME_DIR),await Jt(W.PLUGINS_DIR),await Jt(Oe.default.join(W.HOME_DIR,"logs"))},To=async()=>{let n=await oe.default.readFile(W.CONFIG_FILE,"utf-8");return Yr.default.parse(n)},ie=async()=>{try{let n=await oe.default.readFile(W.CONFIG_FILE,"utf-8");try{let e=Yr.default.parse(n);return Qr(e)}catch(e){console.error(`Failed to parse config file at ${W.CONFIG_FILE}`),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 Wt();let e=await Kt();e&&console.log(`Backed up existing configuration file to ${e}`);let t={PORT:3456,Providers:[],Router:{}};return await xe(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 ${W.CONFIG_FILE}`),console.error("Error details:",n.message),process.exit(1)}};Kt=async()=>{Ua();try{if(await oe.default.access(W.CONFIG_FILE).then(()=>!0).catch(()=>!1)){let n=new Date().toISOString().replace(/[:.]/g,"-"),e=`${W.CONFIG_FILE}.${n}.bak`;await oe.default.copyFile(W.CONFIG_FILE,e);try{let t=Oe.default.dirname(W.CONFIG_FILE),o=Oe.default.basename(W.CONFIG_FILE),s=(await oe.default.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 a=Oe.default.join(t,s[i]);await oe.default.unlink(a)}}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},xe=async n=>{Ua(),await Jt(W.HOME_DIR),await Qu();let e=`${JSON.stringify(n,null,2)}`;await oe.default.writeFile(W.CONFIG_FILE,e)},Qu=async()=>{if(!await oe.default.access(W.CONFIG_FILE).then(()=>!0).catch(()=>!1))return;let e=Oe.default.join(W.HOME_DIR,"config-history");await Jt(e);let t=new Date().toISOString().replace(/[:.]/g,"-"),o=Oe.default.join(e,`config-${t}.json`);await oe.default.copyFile(W.CONFIG_FILE,o);try{let s=(await oe.default.readdir(e)).filter(i=>i.startsWith("config-")&&i.endsWith(".json")).sort().reverse();if(s.length>50)for(let i of s.slice(50))await oe.default.unlink(Oe.default.join(e,i))}catch(r){console.warn("Failed to prune config-history:",r)}},vo=async()=>{let n=await ie();return Object.assign(process.env,n),n}});function Yu(n){return n?.cache_read_input_tokens??n?.input_tokens_details?.cached_tokens??n?.prompt_tokens_details?.cached_tokens??0}function Xu(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 Ke(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:Yu(n),cache_creation_input_tokens:Xu(n)}}function Gt(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 Xr=E(()=>{"use strict"});function Co(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(Zr(r,s))}return}if(Array.isArray(n)){for(let o of n)Co(o,e,t);return}if(typeof n=="object")for(let o of Object.values(n))Co(o,e,t)}}function qr(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 a of i)a&&o.add(Zr(s,a))}return Co(n?.Router,t,o),Co(n?.fallback,t,o),o}function ft(n,e){try{let t=j();if(!t?.getAllStates||!t?.recover)return 0;let o=qr(n),r=0;for(let s of t.getAllStates()||[]){let i=s?.provider,a=s?.model;!i||!a||o.has(Zr(i,a))||(t.recover(i,a),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 Vt(n,e){try{if(!n)return 0;let t=j();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 Zu,Zr,So=E(()=>{"use strict";ce();Zu="\0",Zr=(n,e)=>`${n}${Zu}${e}`});function qu(n){return/\[1m\]/i.test(n)?1e6:2e5}function ed(n){let e=n.toLowerCase();return e.includes("haiku")||e.includes("mini")?8192:32e3}function td(n,e=n){let t=qu(n),o=ed(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 Qt(n){let e=new Map,t=(o,r=o)=>{!o||e.has(o)||e.set(o,td(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 es=E(()=>{"use strict"});function nd(n){let e=n.ip||n.connection?.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}var Yt,ts=E(()=>{"use strict";Yt=n=>async(e,t,o)=>{if(["/","/health"].includes(e.url)||e.url.startsWith("/ui")||nd(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 a=e.headers.authorization||e.headers["x-api-key"],l=Array.isArray(a)?a[0]:a||"";if(!l){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(l.startsWith("Bearer")?c=l.split(" ")[1]:c=l,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 as={};an(as,{append:()=>nn,clear:()=>ss,close:()=>_d,getOldestRecordTimestamp:()=>kd,query:()=>rs,querySummary:()=>on,readTokenSpeedStats:()=>is});function ad(){(0,Me.existsSync)(wo)||(0,Me.mkdirSync)(wo,{recursive:!0})}function tn(){if(Ie)return Ie;ad();let n=(0,Ba.openSqliteDatabase)(od),e=n.db;n.driver==="node:sqlite"&&console.error(`[usage] better-sqlite3 unavailable, using built-in node:sqlite fallback. Reason: ${n.fallbackReason}`),e.pragma("journal_mode = WAL"),e.pragma("synchronous = NORMAL"),e.pragma("busy_timeout = 5000");let t=e.pragma("user_version",{simple:!0})||0;return t<1&&(cd(e),e.pragma("user_version = 1")),t<2&&(e.prepare("PRAGMA table_info(usage_records)").all().some(r=>r.name==="upstream_model")||e.exec("ALTER TABLE usage_records ADD COLUMN upstream_model TEXT"),e.pragma("user_version = 2")),ud(e),Ka(e,!0),os=e.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 Ut,Ur=E(()=>{"use strict";Ut=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||{},a={data:e};return r&&(a.timestamp=new Date().toISOString()),s&&(a.prefix=s),i&&Object.keys(i).length>0&&(a.metadata=i),a}async sendRequest(e,t,o,r,s){let i=new AbortController,a=setTimeout(()=>i.abort(),s);try{let l=await fetch(e,{method:t,headers:o,body:JSON.stringify(r),signal:i.signal});if(clearTimeout(a),!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText}`);return l}catch(l){throw clearTimeout(a),l}}delay(e){return new Promise(t=>setTimeout(t,e))}async sendWithRetry(e,t,o,r,s,i){let a=null;for(let l=1;l<=i.maxAttempts;l++)try{return await this.sendRequest(e,t,o,r,s)}catch(c){if(a=c,l===i.maxAttempts)break;let u=i.backoffMs*Math.pow(2,l-1);console.warn(`[WebhookOutputHandler] Request failed (attempt ${l}/${i.maxAttempts}), retrying in ${u}ms...`,c.message),await this.delay(u)}throw a}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}`)}}}});async function ko(n,e){let t=(0,We.resolve)(n),o=_o.get(t),r,s=new Promise(i=>{r=i});_o.set(t,s);try{return await o,await e()}finally{r(),_o.get(t)===s&&_o.delete(t)}}function Ra(n,e){return n.dev===e.dev&&n.ino===e.ino}async function Ca(n,e){try{let t=await(0,ve.lstat)(n);return t.isDirectory()&&!t.isSymbolicLink()&&Ra(e,t)}catch{return!1}}function Ku(){return new Promise(n=>{setTimeout(n,10).unref()})}async function wa(n,e,t,o){let r=(0,We.resolve)(n);if(o?.aborted||jr.has(r))return 0;jr.add(r);let s=0;try{let i=await(0,ve.lstat)(r);if(!i.isDirectory()||i.isSymbolicLink()||o?.aborted)return 0;let a=await(0,ve.opendir)(r,{bufferSize:32});try{let l=0,c=!0;for await(let u of a){if(o?.aborted||!c)break;try{if(!u.isFile()||u.isSymbolicLink()||!t(u.name))continue;let d=(0,We.join)(r,u.name);try{let p=await(0,ve.lstat)(d);if(!p.isFile()||p.isSymbolicLink()||p.mtimeMs>=e)continue;await ko(d,async()=>{if(o?.aborted||!await Ca(r,i))return!1;let h=await(0,ve.lstat)(d);return!h.isFile()||h.isSymbolicLink()||!Ra(p,h)||h.mtimeMs!==p.mtimeMs||h.mtimeMs>=e||o?.aborted?!1:(await(0,ve.unlink)(d),!0)})&&s++}catch{}}finally{++l%64===0&&(await Ku(),c=!o?.aborted&&await Ca(r,i))}}}finally{await a.close().catch(()=>{})}}catch{}finally{jr.delete(r)}return s}function Ea(n,e,t,o,r){if(!Number.isFinite(o)||o<=0)return Promise.resolve(0);let s=`${e}-`,i=t?`.${t}`:"";return wa(n,Date.now()-o,a=>Wu.test(a)?!0:!a.endsWith(".tmp")&&a.startsWith(s)&&a.endsWith(i),r)}function Gu(n,e){let t=Date.now()-zu;return wa(n,t,o=>{let r=Ju.exec(o);return r!==null&&Number(r[1])<t},e)}function zr(n,e,t){let o=Hr.get(n);if(!o){let s=new AbortController,i,a=()=>{s.signal.aborted||Promise.resolve().then(()=>e(s.signal)).catch(()=>{})},l=setTimeout(()=>{s.signal.aborted||(a(),i=setInterval(a,Bu),i.unref())},t);l.unref(),o={users:0,stop:()=>{s.abort(),clearTimeout(l),i&&clearInterval(i)}},Hr.set(n,o)}o.users++;let r=!1;return()=>{r||(r=!0,--o.users===0&&(o.stop(),Hr.delete(n)))}}function Pa(n=(0,We.join)((0,Sa.tmpdir)(),"claude-code-router")){return zr(`legacy:${(0,We.resolve)(n)}`,e=>Gu(n,e),1e3)}var ve,We,Sa,zu,Bu,Ju,Wu,jr,_o,Hr,Br=E(()=>{"use strict";ve=require("node:fs/promises"),We=require("node:path"),Sa=require("node:os"),zu=3600*1e3,Bu=600*1e3,Ju=/^session-[A-Za-z0-9_.-]+-(\d{13})\.json$/,Wu=/^\.ccr-tmp-[1-9]\d*-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.tmp$/,jr=new Set,_o=new Map,Hr=new Map});var ge,Oa,Aa,Pe,Ia,jt,Jr=E(()=>{"use strict";ge=require("node:fs/promises"),Oa=require("node:crypto"),Aa=require("@wengine-ai/claude-code-router-shared"),Pe=require("node:path"),Ia=require("node:os");Br();jt=class{type="temp-file";config;baseDir;controller=new AbortController;stopSchedule;constructor(e={}){if(this.config={subdirectory:"claude-code-router",extension:"json",includeTimestamp:!1,prefix:"session",retentionMs:36e5,...e},this.baseDir=(0,Pe.resolve)((0,Pe.join)((0,Ia.tmpdir)(),this.config.subdirectory)),Number.isFinite(this.config.retentionMs)&&this.config.retentionMs>0){let t=JSON.stringify([this.baseDir,this.config.prefix,this.config.extension,this.config.retentionMs]);this.stopSchedule=zr(`handler:${t}`,o=>this.pruneOldFiles(o),6e4)}}async ensureDir(){await(0,ge.mkdir)(this.baseDir,{recursive:!0});let e=await(0,ge.lstat)(this.baseDir);if(!e.isDirectory()||e.isSymbolicLink())throw new Error("Unsafe temp output directory")}getFilePath(e){let t=this.config.prefix||"session",o=this.config.extension?`.${this.config.extension}`:"",r=this.config.includeTimestamp?`-${Date.now()}`:"",s=`${t}-${(0,Aa.sanitizeTempFileKey)(e)}${r}${o}`;if((0,Pe.basename)(s)!==s||s.includes("\\"))throw new Error("Temp file configuration must not contain path separators");return(0,Pe.join)(this.baseDir,s)}async output(e,t={}){try{let o=typeof t.metadata?.statsKey=="string"&&t.metadata.statsKey?t.metadata.statsKey:t.metadata?.sessionId;if(!o)return!1;let r=t.metadata?.sessionId??o,s=JSON.stringify({...e,timestamp:Date.now(),sessionId:r},null,2),i=this.getFilePath(o);return await ko(i,async()=>{await this.ensureDir();let a=(0,Pe.join)(this.baseDir,`.ccr-tmp-${process.pid}-${(0,Oa.randomUUID)()}.tmp`);return ko(a,async()=>{let l=!1;try{let c=await(0,ge.open)(a,"wx");l=!0;try{await c.writeFile(s,"utf-8")}finally{await c.close()}return await(0,ge.rename)(a,i),!0}finally{l&&await(0,ge.unlink)(a).catch(()=>{})}})})}catch{return!1}}pruneOldFiles(e=this.controller.signal){return Ea(this.baseDir,this.config.prefix||"session",this.config.extension||"",this.config.retentionMs,e)}dispose(){this.controller.abort(),this.stopSchedule?.()}getBaseDir(){return this.baseDir}}});var Wr,pt,Ma=E(()=>{"use strict";Fr();Ur();Jr();Wr=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 Ft(e.config);case"webhook":return new Ut(e.config);case"temp-file":return new jt(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,a])=>{try{await a.output(e,o)?r.success.push(i):r.failed.push(i)}catch(l){console.error(`[OutputManager] Handler ${i} failed:`,l),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 a=>{let l=this.handlers.get(a);if(!l){console.warn(`[OutputManager] Handler ${a} not found`),s.failed.push(a);return}try{await l.output(t,r)?s.success.push(a):s.failed.push(a)}catch(c){console.error(`[OutputManager] Handler ${a} failed:`,c),s.failed.push(a)}});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)}},pt=new Wr});var Kr=E(()=>{"use strict";xa();Fr();Ur();Jr();Ma()});function bo(){return{subdirectory:Da.TOKEN_SPEED_TEMP_SUBDIRECTORY,extension:"json",includeTimestamp:!1,prefix:"session"}}function Na(n,e,t=0){if(n<=0)return 0;let o=Math.max((e-t)/1e3,Vu);return Math.round(n/o)}function zt(n){let e=(n.match(/[\u4e00-\u9fa5]/g)||[]).length,t=n.length-e;return Math.ceil(e/1.5+t/4)}async function $a(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,statsKey:n.statsKey},...t};for(let a of e)try{await pt.outputToType(a,s,i)}catch(l){console.error(`[TokenSpeedPlugin] Failed to output to ${a}:`,l)}}var La,Da,Ht,Gr,Vu,Bt,Fa=E(()=>{"use strict";La=Z(require("fastify-plugin"),1);Dr();Kr();nt();Da=require("@wengine-ai/claude-code-router-shared");Ht=new Map,Gr=new Map,Vu=1,Bt={name:"token-speed",version:"1.0.0",description:"Statistics for streaming response token generation speed",register:(0,La.default)(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)pt.registerHandlers(t.outputHandlers);else{let i=[];for(let a of o)a==="console"?i.push({type:"console",enabled:!0,config:{colors:!0,level:"log"}}):a==="temp-file"?i.push({type:"temp-file",enabled:!0,config:bo()}):a==="webhook"&&console.warn("[TokenSpeedPlugin] Webhook reporter requires explicit configuration in outputHandlers");i.length>0&&pt.registerHandlers(i)}t.outputOptions&&pt.setDefaultOptions(t.outputOptions);let r=async i=>{let a=n.tokenizerService;if(!a)return n.log?.warn("TokenizerService not available"),null;if(!i.provider||!i.model)return null;let l=i.provider,c=i.model,u=`${l}:${c}`;if(Gr.has(u))return Gr.get(u);let d=a.getTokenizerConfigForModel(l,c);if(!d)return n.log?.debug(`No tokenizer config for ${l}:${c}, using fallback`),null;try{let p=await a.getTokenizer(d,l);return Gr.set(u,p),n.log?.info(`Created tokenizer for ${l}:${c} - ${p.name}`),p}catch(p){return n.log?.warn(`Failed to create tokenizer for ${l}:${c}: ${p.message}`),null}},s=i=>{let a=new URL(`http://127.0.0.1${i}`).pathname;return a.endsWith("/v1/messages")||a.endsWith("/v1/responses")};n.addHook("onRequest",async i=>{s(i.url)&&(i.requestStartTime=performance.now())}),n.addHook("onSend",async(i,a,l)=>{let c=i.requestStartTime;if(!c)return;let u=i.id||Date.now().toString(),d=i.usageSessionId||u,p=i.sessionId;if(!p)try{p=be(i.body?.metadata?.user_id)||d}catch{p=d}let m=await r(i);if(l instanceof ReadableStream){Ht.set(u,{requestId:u,sessionId:p,statsKey:d,startTime:c,lastTokenTime:c,tokenCount:0,tokensPerSecond:0,stream:!0});let[_,k]=l.tee(),y=async()=>{let b=null,T=async C=>{let v=Ht.get(u);if(!v)return;let S=v.firstTokenTime?v.firstTokenTime-v.startTime:0,w=(C?v.lastTokenTime:performance.now())-v.startTime;v.tokensPerSecond=Na(v.tokenCount,w,S),await $a(v,o,t.outputOptions,C).catch(R=>{n.log?.warn(`Failed to output streaming stats: ${R.message}`)})};try{let v=k.pipeThrough(new TextDecoderStream).pipeThrough(new de).getReader();for(b=setInterval(async()=>{Ht.get(u)&&await T(!1)},1e3);;){let{done:S,value:x}=await v.read();if(S)break;let w=x,R=Ht.get(u);if(!R)continue;let A=performance.now(),P=w.event||w.data?.type,N=w.event==="content_block_start"||w.event==="content_block_delta"||w.event==="text_block"||w.event==="content_block"||P==="response.output_text.delta"||P==="response.function_call_arguments.delta"||P==="response.reasoning_summary_text.delta";!R.firstTokenTime&&N&&(R.firstTokenTime=A,R.timeToFirstToken=Math.round(A-R.startTime));let L="";if(w.event==="content_block_delta"&&w.data?.delta){let D=w.data.delta.type;D==="text_delta"?L=w.data.delta.text||"":D==="input_json_delta"?L=w.data.delta.partial_json||"":D==="thinking_delta"&&(L=w.data.delta.thinking||"")}if((P==="response.output_text.delta"||P==="response.function_call_arguments.delta"||P==="response.reasoning_summary_text.delta")&&(L=typeof w.data?.delta=="string"?w.data.delta:""),L){let D=m&&m.encodeText?m.encodeText(L).length:zt(L);R.tokenCount+=D,R.lastTokenTime=A}(w.event==="message_stop"||P==="response.completed"||P==="response.failed")&&(b&&(clearInterval(b),b=null),await T(!0),Ht.delete(u))}}catch(C){b&&clearInterval(b),C.name!=="AbortError"&&C.code!=="ERR_STREAM_PREMATURE_CLOSE"&&n.log?.warn(`Error processing token stats: ${C.message}`)}};return i.tokenSpeedCapturePromise=y().catch(b=>{console.log(b),n.log?.warn(`Background stats processing failed: ${b.message}`)}),_}let h=performance.now(),g=0,f=!1;if(l&&typeof l=="string")try{let _=JSON.parse(l);if(typeof _.usage?.output_tokens=="number")g=_.usage.output_tokens,f=!0;else{let k=_.content??_.message?.content;if(k!==void 0)if(f=!0,m)Array.isArray(k)?g=k.reduce((y,b)=>{if(b.type==="text"){let T=b.text||"";return y+(m.encodeText?m.encodeText(T).length:zt(T))}return y},0):typeof k=="string"&&(g=m.encodeText?m.encodeText(k).length:zt(k));else{let y=Array.isArray(k)?k.map(b=>b.text).join(""):typeof k=="string"?k:"";g=zt(y)}}}catch{}if(f){let _=h-c,k={requestId:u,sessionId:p,statsKey:d,startTime:c,lastTokenTime:h,tokenCount:g,tokensPerSecond:Na(g,_),stream:!1};await $a(k,o,t.outputOptions,!0)}return l})})}});var Vr=E(()=>{"use strict";Ta();va();Fa();Kr()});function Ua(){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 oe,Yr,Oe,W,Qr,Jt,Wt,To,ie,Kt,xe,Qu,vo,xo=E(()=>{"use strict";oe=Z(require("node:fs/promises"),1),Yr=Z(require("json5"),1),Oe=Z(require("node:path"),1),W=require("@wengine-ai/claude-code-router-shared"),Qr=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(Qr);if(n!==null&&typeof n=="object"){let e={};for(let[t,o]of Object.entries(n))e[t]=Qr(o);return e}return n},Jt=async n=>{try{await oe.default.access(n)}catch{await oe.default.mkdir(n,{recursive:!0})}},Wt=async()=>{await Jt(W.HOME_DIR),await Jt(W.PLUGINS_DIR),await Jt(Oe.default.join(W.HOME_DIR,"logs"))},To=async()=>{let n=await oe.default.readFile(W.CONFIG_FILE,"utf-8");return Yr.default.parse(n)},ie=async()=>{try{let n=await oe.default.readFile(W.CONFIG_FILE,"utf-8");try{let e=Yr.default.parse(n);return Qr(e)}catch(e){console.error(`Failed to parse config file at ${W.CONFIG_FILE}`),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 Wt();let e=await Kt();e&&console.log(`Backed up existing configuration file to ${e}`);let t={PORT:3456,Providers:[],Router:{}};return await xe(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 ${W.CONFIG_FILE}`),console.error("Error details:",n.message),process.exit(1)}};Kt=async()=>{Ua();try{if(await oe.default.access(W.CONFIG_FILE).then(()=>!0).catch(()=>!1)){let n=new Date().toISOString().replace(/[:.]/g,"-"),e=`${W.CONFIG_FILE}.${n}.bak`;await oe.default.copyFile(W.CONFIG_FILE,e);try{let t=Oe.default.dirname(W.CONFIG_FILE),o=Oe.default.basename(W.CONFIG_FILE),s=(await oe.default.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 a=Oe.default.join(t,s[i]);await oe.default.unlink(a)}}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},xe=async n=>{Ua(),await Jt(W.HOME_DIR),await Qu();let e=`${JSON.stringify(n,null,2)}`;await oe.default.writeFile(W.CONFIG_FILE,e)},Qu=async()=>{if(!await oe.default.access(W.CONFIG_FILE).then(()=>!0).catch(()=>!1))return;let e=Oe.default.join(W.HOME_DIR,"config-history");await Jt(e);let t=new Date().toISOString().replace(/[:.]/g,"-"),o=Oe.default.join(e,`config-${t}.json`);await oe.default.copyFile(W.CONFIG_FILE,o);try{let s=(await oe.default.readdir(e)).filter(i=>i.startsWith("config-")&&i.endsWith(".json")).sort().reverse();if(s.length>50)for(let i of s.slice(50))await oe.default.unlink(Oe.default.join(e,i))}catch(r){console.warn("Failed to prune config-history:",r)}},vo=async()=>{let n=await ie();return Object.assign(process.env,n),n}});function Yu(n){return n?.cache_read_input_tokens??n?.input_tokens_details?.cached_tokens??n?.prompt_tokens_details?.cached_tokens??0}function Xu(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 Ke(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:Yu(n),cache_creation_input_tokens:Xu(n)}}function Gt(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 Xr=E(()=>{"use strict"});function Co(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(Zr(r,s))}return}if(Array.isArray(n)){for(let o of n)Co(o,e,t);return}if(typeof n=="object")for(let o of Object.values(n))Co(o,e,t)}}function qr(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 a of i)a&&o.add(Zr(s,a))}return Co(n?.Router,t,o),Co(n?.fallback,t,o),o}function ft(n,e){try{let t=j();if(!t?.getAllStates||!t?.recover)return 0;let o=qr(n),r=0;for(let s of t.getAllStates()||[]){let i=s?.provider,a=s?.model;!i||!a||o.has(Zr(i,a))||(t.recover(i,a),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 Vt(n,e){try{if(!n)return 0;let t=j();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 Zu,Zr,So=E(()=>{"use strict";ce();Zu="\0",Zr=(n,e)=>`${n}${Zu}${e}`});function qu(n){return/\[1m\]/i.test(n)?1e6:2e5}function ed(n){let e=n.toLowerCase();return e.includes("haiku")||e.includes("mini")?8192:32e3}function td(n,e=n){let t=qu(n),o=ed(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 Qt(n){let e=new Map,t=(o,r=o)=>{!o||e.has(o)||e.set(o,td(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 es=E(()=>{"use strict"});function nd(n){let e=n.ip||n.connection?.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}var Yt,ts=E(()=>{"use strict";Yt=n=>async(e,t,o)=>{if(["/","/health"].includes(e.url)||e.url.startsWith("/ui")||nd(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 a=e.headers.authorization||e.headers["x-api-key"],l=Array.isArray(a)?a[0]:a||"";if(!l){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(l.startsWith("Bearer")?c=l.split(" ")[1]:c=l,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 as={};an(as,{append:()=>nn,clear:()=>ss,close:()=>_d,getOldestRecordTimestamp:()=>kd,query:()=>rs,querySummary:()=>on,readTokenSpeedStats:()=>is});function ad(){(0,Me.existsSync)(wo)||(0,Me.mkdirSync)(wo,{recursive:!0})}function tn(){if(Ie)return Ie;ad();let n=(0,Ba.openSqliteDatabase)(od),e=n.db;n.driver==="node:sqlite"&&console.error(`[usage] better-sqlite3 unavailable, using built-in node:sqlite fallback. Reason: ${n.fallbackReason}`),e.pragma("journal_mode = WAL"),e.pragma("synchronous = NORMAL"),e.pragma("busy_timeout = 5000");let t=e.pragma("user_version",{simple:!0})||0;return t<1&&(cd(e),e.pragma("user_version = 1")),t<2&&(e.prepare("PRAGMA table_info(usage_records)").all().some(r=>r.name==="upstream_model")||e.exec("ALTER TABLE usage_records ADD COLUMN upstream_model TEXT"),e.pragma("user_version = 2")),ud(e),Ka(e,!0),os=e.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,
|