@washanhanzi/claude-code-router 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +1 -1
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -579,7 +579,7 @@ https://cloud.google.com/compute/docs/metadata/predefined-metadata-keys`};var m=
579
579
  ${this.toMarkdown(n,t+1)}`:`${r}- ${n}`).join(`
580
580
  `):typeof e=="object"&&e!==null?Object.entries(e).map(([n,i])=>typeof i=="object"&&i!==null?`${r}${n}:
581
581
  ${this.toMarkdown(i,t+1)}`:`${r}${n}: ${i}`).join(`
582
- `):`${r}${e}`}async output(e,t={}){try{let r=this.formatData(e,t);switch(this.config.level||"log"){case"info":console.info(r);break;case"warn":console.warn(r);break;case"error":console.error(r);break;case"debug":console.debug(r);break;case"log":default:console.log(r);break}return!0}catch(r){return console.error("[ConsoleOutputHandler] Output failed:",r),!1}}}}),vy,Sy=Ur(()=>{"use strict";vy=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:r="json",timestamp:n=!0,prefix:i,metadata:o}=t||{},s={data:e};return n&&(s.timestamp=new Date().toISOString()),i&&(s.prefix=i),o&&Object.keys(o).length>0&&(s.metadata=o),s}async sendRequest(e,t,r,n,i){let o=new AbortController,s=setTimeout(()=>o.abort(),i);try{let a=await fetch(e,{method:t,headers:r,body:JSON.stringify(n),signal:o.signal});if(clearTimeout(s),!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);return a}catch(a){throw clearTimeout(s),a}}delay(e){return new Promise(t=>setTimeout(t,e))}async sendWithRetry(e,t,r,n,i,o){let s=null;for(let a=1;a<=o.maxAttempts;a++)try{return await this.sendRequest(e,t,r,n,i)}catch(u){if(s=u,a===o.maxAttempts)break;let l=o.backoffMs*Math.pow(2,a-1);console.warn(`[WebhookOutputHandler] Request failed (attempt ${a}/${o.maxAttempts}), retrying in ${l}ms...`,u.message),await this.delay(l)}throw s}async output(e,t={}){let r=t.timeout||this.defaultTimeout;try{let n=this.buildHeaders(),i=this.buildBody(e,t),o=await this.sendWithRetry(this.config.url,this.config.method,n,i,r,this.config.retry);return!0}catch(n){let i=n instanceof Error?n.message:String(n);if(this.config.silent)return console.error(`[WebhookOutputHandler] Failed to send data: ${i}`),!1;throw new Error(`Webhook output failed: ${i}`)}}}}),_y,Qy=Ur(()=>{"use strict";_y=class{type="temp-file";config;baseDir;constructor(e={}){this.config={subdirectory:"claude-code-router",extension:"json",includeTimestamp:!1,prefix:"session",...e};let t=(0,eN.tmpdir)();this.baseDir=(0,pE.join)(t,this.config.subdirectory),this.ensureDir()}ensureDir(){try{(0,n0.existsSync)(this.baseDir)||(0,n0.mkdirSync)(this.baseDir,{recursive:!0})}catch{}}extractSessionId(e){try{let t=e.match(/_session_([a-f0-9-]+)/i);return t?t[1]:null}catch{return null}}getFilePath(e){let t=this.config.prefix||"session",r=this.config.extension?`.${this.config.extension}`:"",n;if(this.config.includeTimestamp){let i=Date.now();n=`${t}-${e}-${i}${r}`}else n=`${t}-${e}${r}`;return(0,pE.join)(this.baseDir,n)}async output(e,t={}){try{let r=t.metadata?.sessionId;if(!r)return!1;let n={...e,timestamp:Date.now(),sessionId:r},i=this.getFilePath(r);return(0,n0.writeFileSync)(i,JSON.stringify(n,null,2),"utf-8"),!0}catch{return!1}}getBaseDir(){return this.baseDir}}}),PE,Bu,vk=Ur(()=>{"use strict";Fy(),Sy(),Qy(),PE=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 r=this.createHandler(t),n=t.type+"_"+Date.now();this.registerHandler(n,r)}catch(r){console.error(`[OutputManager] Failed to register ${t.type} handler:`,r)}}createHandler(e){switch(e.type){case"console":return new xy(e.config);case"webhook":return new vy(e.config);case"temp-file":return new _y(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 r={...this.defaultOptions,...t},n={success:[],failed:[]},i=Array.from(this.handlers.entries()).map(async([o,s])=>{try{await s.output(e,r)?n.success.push(o):n.failed.push(o)}catch(a){console.error(`[OutputManager] Handler ${o} failed:`,a),n.failed.push(o)}});return await Promise.all(i),n}async outputTo(e,t,r){let n={...this.defaultOptions,...r},i={success:[],failed:[]},o=e.map(async s=>{let a=this.handlers.get(s);if(!a){console.warn(`[OutputManager] Handler ${s} not found`),i.failed.push(s);return}try{await a.output(t,n)?i.success.push(s):i.failed.push(s)}catch(u){console.error(`[OutputManager] Handler ${s} failed:`,u),i.failed.push(s)}});return await Promise.all(o),i}async outputToType(e,t,r){let n=Array.from(this.handlers.entries()).filter(([i,o])=>o.type===e).map(([i])=>i);return this.outputTo(n,t,r)}},Bu=new PE}),Sk=Ns(gC(),1),UE=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,gE.join)(process.cwd(),this.options.jsonPath);if((0,i0.existsSync)(e))try{let t=(0,i0.readFileSync)(e,"utf-8"),r=Sk.default.parse(t);this.config={...this.config,...r},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,gE.join)(process.cwd(),this.options.envPath);if((0,i0.existsSync)(e))try{let t=(0,nN.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 r=this.config[e];return r!==void 0?r:t}getAll(){return{...this.config}}getHttpsProxy(){return this.get("HTTPS_PROXY")||this.get("https_proxy")||this.get("httpsProxy")||this.get("PROXY_URL")}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 Zn(e,t=500,r="internal_error",n="api_error"){let i=new Error(e);return i.statusCode=t,i.code=r,i.type=n,i}async function _k(e,t,r){t.log.error(e);let n=e.statusCode||500,i={error:{message:e.message+e.stack||"Internal Server Error",type:e.type||"api_error",code:e.code||"internal_error"}};return r.code(n).send(i)}function Qk(e,t,r,n,i){let o=new Headers({"Content-Type":"application/json"});r.headers&&Object.entries(r.headers).forEach(([l,c])=>{c&&o.set(l,c)});let s,a=AbortSignal.timeout(r.TIMEOUT??60*1e3*60);if(r.signal){let l=new AbortController,c=()=>l.abort();r.signal.addEventListener("abort",c),a.addEventListener("abort",c),s=l.signal}else s=a;let u={method:"POST",headers:o,body:JSON.stringify(t),signal:s};return r.httpsProxy&&(u.dispatcher=new iN.ProxyAgent(new URL(r.httpsProxy).toString())),i?.debug({reqId:n.req.id,request:u,headers:Object.fromEntries(o.entries()),requestUrl:typeof e=="string"?e:e.toString(),useProxy:r.httpsProxy},"final request"),fetch(typeof e=="string"?e:e.toString(),u)}var Rk="1.0.51";async function Tk(e,t,r,n){let i=e.body,o=e.provider,s=r.providerService.getProvider(o);if(!s)throw Zn(`Provider '${o}' not found`,404,"provider_not_found");try{let{requestBody:a,config:u,bypass:l}=await Ry(i,s,n,e.headers,{req:e}),c=await Ty(a,u,s,r,l,n,{req:e}),A=await Ny(a,c,s,n,l,{req:e});return ky(A,t,i)}catch(a){if(a.code==="provider_response_error"){let u=await Nk(e,t,r,n,a);if(u)return u}throw a}}async function Nk(e,t,r,n,i){let o=e.scenarioType||"default",s=r.configService.get("fallback");if(!s||!s[o])return null;let a=s[o];if(!Array.isArray(a)||a.length===0)return null;e.log.warn(`Request failed for ${e.scenarioType}, trying ${a.length} fallback models`);for(let u of a)try{e.log.info(`Trying fallback model: ${u}`);let l={...e.body},[c,...A]=u.split(",");l.model=A.join(",");let p={...e,provider:c,body:l},h=r.providerService.getProvider(c);if(!h){e.log.warn(`Fallback provider '${c}' not found, skipping`);continue}let{requestBody:d,config:f,bypass:g}=await Ry(l,h,n,e.headers,{req:p}),E=await Ty(d,f,h,r,g,n,{req:p}),C=await Ny(d,E,h,n,g,{req:p});return e.log.info(`Fallback model ${u} succeeded`),ky(C,t,l)}catch(l){e.log.warn(`Fallback model ${u} failed: ${l.message}`);continue}return e.log.error(`All fallback models failed for yichu ${o}`),null}async function Ry(e,t,r,n,i){let o=e,s={},a=!1;if(a=kk(t,r,e),a&&(n instanceof Headers?n.delete("content-length"):delete n["content-length"],s.headers=n),!a&&typeof r.transformRequestOut=="function"){let u=await r.transformRequestOut(o);u.body?(o=u.body,s=u.config||{}):o=u}if(!a&&t.transformer?.use?.length)for(let u of t.transformer.use){if(!u||typeof u.transformRequestIn!="function")continue;let l=await u.transformRequestIn(o,t,i);l.body?(o=l.body,s={...s,...l.config}):o=l}if(!a&&t.transformer?.[e.model]?.use?.length)for(let u of t.transformer[e.model].use)!u||typeof u.transformRequestIn!="function"||(o=await u.transformRequestIn(o,t,i));return{requestBody:o,config:s,bypass:a}}function kk(e,t,r){return e.transformer?.use?.length===1&&e.transformer.use[0].name===t.name&&(!e.transformer?.[r.model]?.use.length||e.transformer?.[r.model]?.use.length===1&&e.transformer?.[r.model]?.use[0].name===t.name)}async function Ty(e,t,r,n,i,o,s){let a=t.url||new URL(r.baseUrl);if(i&&typeof o.auth=="function"){let c=await o.auth(e,r);if(c.body){e=c.body;let A=t.headers||{};c.config?.headers&&(A={...A,...c.config.headers},delete A.host,delete c.config.headers),t={...t,...c.config,headers:A}}else e=c}let u={Authorization:`Bearer ${r.apiKey}`,...t?.headers||{}};for(let c in u)(u[c]==="undefined"||["authorization","Authorization"].includes(c)&&u[c]?.includes("undefined"))&&delete u[c];let l=await Qk(a,e,{httpsProxy:n.configService.getHttpsProxy(),...t,headers:JSON.parse(JSON.stringify(u))},s,n.log);if(!l.ok){let c=await l.text();throw n.log.error(`[provider_response_error] Error from provider(${r.name},${e.model}: ${l.status}): ${c}`),Zn(`Error from provider(${r.name},${e.model}: ${l.status}): ${c}`,l.status,"provider_response_error")}return l}async function Ny(e,t,r,n,i,o){let s=t;if(!i&&r.transformer?.use?.length)for(let a of Array.from(r.transformer.use).reverse())!a||typeof a.transformResponseOut!="function"||(s=await a.transformResponseOut(s,o));if(!i&&r.transformer?.[e.model]?.use?.length)for(let a of Array.from(r.transformer[e.model].use).reverse())!a||typeof a.transformResponseOut!="function"||(s=await a.transformResponseOut(s,o));return!i&&n.transformResponseIn&&(s=await n.transformResponseIn(s,o)),s}function ky(e,t,r){return e.ok||t.code(e.status),r.stream===!0?(t.header("Content-Type","text/event-stream"),t.header("Cache-Control","no-cache"),t.header("Connection","keep-alive"),t.send(e.body)):e.json()}var ME=async e=>{e.get("/",async()=>({message:"LLMs API",version:Rk})),e.get("/health",async()=>({status:"ok",timestamp:new Date().toISOString()}));let t=e.transformerService.getTransformersWithEndpoint();for(let{transformer:r}of t)r.endPoint&&e.post(r.endPoint,async(n,i)=>Tk(n,i,e,r));e.post("/providers",{schema:{body:{type:"object",properties:{id:{type:"string"},name:{type:"string"},type:{type:"string",enum:["openai","anthropic"]},baseUrl:{type:"string"},apiKey:{type:"string"},models:{type:"array",items:{type:"string"}}},required:["id","name","type","baseUrl","apiKey","models"]}}},async(r,n)=>{let{name:i,baseUrl:o,apiKey:s,models:a}=r.body;if(!i?.trim())throw Zn("Provider name is required",400,"invalid_request");if(!o||!Ok(o))throw Zn("Valid base URL is required",400,"invalid_request");if(!s?.trim())throw Zn("API key is required",400,"invalid_request");if(!a||!Array.isArray(a)||a.length===0)throw Zn("At least one model is required",400,"invalid_request");if(e.providerService.getProvider(r.body.name))throw Zn(`Provider with name '${r.body.name}' already exists`,400,"provider_exists");return e.providerService.registerProvider(r.body)}),e.get("/providers",async()=>e.providerService.getProviders()),e.get("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]}}},async r=>{let n=e.providerService.getProvider(r.params.id);if(!n)throw Zn("Provider not found",404,"provider_not_found");return n}),e.put("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]},body:{type:"object",properties:{name:{type:"string"},type:{type:"string",enum:["openai","anthropic"]},baseUrl:{type:"string"},apiKey:{type:"string"},models:{type:"array",items:{type:"string"}},enabled:{type:"boolean"}}}}},async(r,n)=>{let i=e.providerService.updateProvider(r.params.id,r.body);if(!i)throw Zn("Provider not found",404,"provider_not_found");return i}),e.delete("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]}}},async r=>{if(!e.providerService.deleteProvider(r.params.id))throw Zn("Provider not found",404,"provider_not_found");return{message:"Provider deleted successfully"}}),e.patch("/providers/:id/toggle",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]},body:{type:"object",properties:{enabled:{type:"boolean"}},required:["enabled"]}}},async(r,n)=>{if(!e.providerService.toggleProvider(r.params.id,r.body.enabled))throw Zn("Provider not found",404,"provider_not_found");return{message:`Provider ${r.body.enabled?"enabled":"disabled"} successfully`}})};function Ok(e){try{return new URL(e),!0}catch{return!1}}var $E=class{constructor(e,t,r){this.configService=e,this.transformerService=t,this.logger=r,this.initializeCustomProviders()}providers=new Map;modelRoutes=new Map;initializeCustomProviders(){let e=this.configService.get("providers");if(e&&Array.isArray(e)){this.initializeFromProvidersArray(e);return}}initializeFromProvidersArray(e){e.forEach(t=>{try{if(!t.name||!t.api_base_url||!t.api_key)return;let r={};t.transformer&&Object.keys(t.transformer).forEach(n=>{n==="use"?Array.isArray(t.transformer.use)&&(r.use=t.transformer.use.map(i=>{if(Array.isArray(i)&&typeof i[0]=="string"){let o=this.transformerService.getTransformer(i[0]);if(o)return new o(i[1])}if(typeof i=="string"){let o=this.transformerService.getTransformer(i);return typeof o=="function"?new o:o}}).filter(i=>typeof i<"u")):Array.isArray(t.transformer[n]?.use)&&(r[n]={use:t.transformer[n].use.map(i=>{if(Array.isArray(i)&&typeof i[0]=="string"){let o=this.transformerService.getTransformer(i[0]);if(o)return new o(i[1])}if(typeof i=="string"){let o=this.transformerService.getTransformer(i);return typeof o=="function"?new o:o}}).filter(i=>typeof i<"u")})}),this.registerProvider({name:t.name,baseUrl:t.api_base_url,apiKey:t.api_key,models:t.models||[],transformer:t.transformer?r:void 0}),this.logger.info(`${t.name} provider registered`)}catch(r){this.logger.error(`${t.name} provider registered error: ${r}`)}})}registerProvider(e){let t={...e};return this.providers.set(t.name,t),e.models.forEach(r=>{let n=`${t.name},${r}`,i={provider:t.name,model:r,fullModel:n};this.modelRoutes.set(n,i),this.modelRoutes.has(r)||this.modelRoutes.set(r,i)}),t}getProviders(){return Array.from(this.providers.values())}getProvider(e){return this.providers.get(e)}updateProvider(e,t){let r=this.providers.get(e);if(!r)return null;let n={...r,...t,updatedAt:new Date};return this.providers.set(e,n),t.models&&(r.models.forEach(i=>{let o=`${r.name},${i}`;this.modelRoutes.delete(o),this.modelRoutes.delete(i)}),t.models.forEach(i=>{let o=`${r.name},${i}`,s={provider:r.name,model:i,fullModel:o};this.modelRoutes.set(o,s),this.modelRoutes.has(i)||this.modelRoutes.set(i,s)})),n}deleteProvider(e){let t=this.providers.get(e);return t?(t.models.forEach(r=>{let n=`${t.name},${r}`;this.modelRoutes.delete(n),this.modelRoutes.delete(r)}),this.providers.delete(e),!0):!1}toggleProvider(e,t){return!!this.providers.get(e)}resolveModelRoute(e){let t=this.modelRoutes.get(e);if(!t)return null;let r=this.providers.get(t.provider);return r?{provider:r,originalModel:e,targetModel:t.model}:null}getAvailableModelNames(){let e=[];return this.providers.forEach(t=>{t.models.forEach(r=>{e.push(r),e.push(`${t.name},${r}`)})}),e}getModelRoutes(){return Array.from(this.modelRoutes.values())}parseTransformerConfig(e){return e?Array.isArray(e)?e.reduce((t,r)=>{if(Array.isArray(r)){let[n,i={}]=r;t[n]=i}else t[r]={};return t},{}):e:{}}async getAvailableModels(){let e=[];return this.providers.forEach(t=>{t.models.forEach(r=>{e.push({id:r,object:"model",owned_by:t.name,provider:t.name}),e.push({id:`${t.name},${r}`,object:"model",owned_by:t.name,provider:t.name})})}),{object:"list",data:e}}},un=[];for(let e=0;e<256;++e)un.push((e+256).toString(16).slice(1));function Lk(e,t=0){return(un[e[t+0]]+un[e[t+1]]+un[e[t+2]]+un[e[t+3]]+"-"+un[e[t+4]]+un[e[t+5]]+"-"+un[e[t+6]]+un[e[t+7]]+"-"+un[e[t+8]]+un[e[t+9]]+"-"+un[e[t+10]]+un[e[t+11]]+un[e[t+12]]+un[e[t+13]]+un[e[t+14]]+un[e[t+15]]).toLowerCase()}var mc=new Uint8Array(256),sc=mc.length;function Pk(){return sc>mc.length-16&&((0,sN.randomFillSync)(mc),sc=0),mc.slice(sc,sc+=16)}var HE={randomUUID:oN.randomUUID};function Uk(e,t,r){if(HE.randomUUID&&!t&&!e)return HE.randomUUID();e=e||{};let n=e.random??e.rng?.()??Pk();if(n.length<16)throw new Error("Random bytes length must be >= 16");if(n[6]=n[6]&15|64,n[8]=n[8]&63|128,t){if(r=r||0,r<0||r+16>t.length)throw new RangeError(`UUID byte range ${r}:${r+15} is out of buffer bounds`);for(let i=0;i<16;++i)t[r+i]=n[i];return t}return Lk(n)}var xu=Uk,Mk=e=>e<=0?"none":e<=1024?"low":e<=8192?"medium":"high",$k=(e,t)=>(e.includes("base64")&&(e=e.split("base64").pop(),e.startsWith(",")&&(e=e.slice(1))),`data:${t};base64,${e}`),Hk=class{constructor(e){this.options=e,this.useBearer=this.options?.UseBearer??!1}name="Anthropic";endPoint="/v1/messages";useBearer;logger;async auth(e,t){let r={};return this.useBearer?(r.authorization=`Bearer ${t.apiKey}`,r["x-api-key"]=void 0):(r["x-api-key"]=t.apiKey,r.authorization=void 0),{body:e,config:{headers:r}}}async transformRequestOut(e){let t=[];if(e.system){if(typeof e.system=="string")t.push({role:"system",content:e.system});else if(Array.isArray(e.system)&&e.system.length){let n=e.system.filter(i=>i.type==="text"&&i.text).map(i=>({type:"text",text:i.text,cache_control:i.cache_control}));t.push({role:"system",content:n})}}JSON.parse(JSON.stringify(e.messages||[]))?.forEach(n=>{if(n.role==="user"||n.role==="assistant"){if(typeof n.content=="string"){t.push({role:n.role,content:n.content});return}if(Array.isArray(n.content)){if(n.role==="user"){let i=n.content.filter(s=>s.type==="tool_result"&&s.tool_use_id);i.length&&i.forEach(s=>{let a={role:"tool",content:typeof s.content=="string"?s.content:JSON.stringify(s.content),tool_call_id:s.tool_use_id,cache_control:s.cache_control};t.push(a)});let o=n.content.filter(s=>s.type==="text"&&s.text||s.type==="image"&&s.source);o.length&&t.push({role:"user",content:o.map(s=>s?.type==="image"?{type:"image_url",image_url:{url:s.source?.type==="base64"?$k(s.source.data,s.source.media_type):s.source.url},media_type:s.source.media_type}:s)})}else if(n.role==="assistant"){let i={role:"assistant",content:""},o=n.content.filter(u=>u.type==="text"&&u.text);o.length&&(i.content=o.map(u=>u.text).join(`
582
+ `):`${r}${e}`}async output(e,t={}){try{let r=this.formatData(e,t);switch(this.config.level||"log"){case"info":console.info(r);break;case"warn":console.warn(r);break;case"error":console.error(r);break;case"debug":console.debug(r);break;case"log":default:console.log(r);break}return!0}catch(r){return console.error("[ConsoleOutputHandler] Output failed:",r),!1}}}}),vy,Sy=Ur(()=>{"use strict";vy=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:r="json",timestamp:n=!0,prefix:i,metadata:o}=t||{},s={data:e};return n&&(s.timestamp=new Date().toISOString()),i&&(s.prefix=i),o&&Object.keys(o).length>0&&(s.metadata=o),s}async sendRequest(e,t,r,n,i){let o=new AbortController,s=setTimeout(()=>o.abort(),i);try{let a=await fetch(e,{method:t,headers:r,body:JSON.stringify(n),signal:o.signal});if(clearTimeout(s),!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);return a}catch(a){throw clearTimeout(s),a}}delay(e){return new Promise(t=>setTimeout(t,e))}async sendWithRetry(e,t,r,n,i,o){let s=null;for(let a=1;a<=o.maxAttempts;a++)try{return await this.sendRequest(e,t,r,n,i)}catch(u){if(s=u,a===o.maxAttempts)break;let l=o.backoffMs*Math.pow(2,a-1);console.warn(`[WebhookOutputHandler] Request failed (attempt ${a}/${o.maxAttempts}), retrying in ${l}ms...`,u.message),await this.delay(l)}throw s}async output(e,t={}){let r=t.timeout||this.defaultTimeout;try{let n=this.buildHeaders(),i=this.buildBody(e,t),o=await this.sendWithRetry(this.config.url,this.config.method,n,i,r,this.config.retry);return!0}catch(n){let i=n instanceof Error?n.message:String(n);if(this.config.silent)return console.error(`[WebhookOutputHandler] Failed to send data: ${i}`),!1;throw new Error(`Webhook output failed: ${i}`)}}}}),_y,Qy=Ur(()=>{"use strict";_y=class{type="temp-file";config;baseDir;constructor(e={}){this.config={subdirectory:"claude-code-router",extension:"json",includeTimestamp:!1,prefix:"session",...e};let t=(0,eN.tmpdir)();this.baseDir=(0,pE.join)(t,this.config.subdirectory),this.ensureDir()}ensureDir(){try{(0,n0.existsSync)(this.baseDir)||(0,n0.mkdirSync)(this.baseDir,{recursive:!0})}catch{}}extractSessionId(e){try{let t=e.match(/_session_([a-f0-9-]+)/i);return t?t[1]:null}catch{return null}}getFilePath(e){let t=this.config.prefix||"session",r=this.config.extension?`.${this.config.extension}`:"",n;if(this.config.includeTimestamp){let i=Date.now();n=`${t}-${e}-${i}${r}`}else n=`${t}-${e}${r}`;return(0,pE.join)(this.baseDir,n)}async output(e,t={}){try{let r=t.metadata?.sessionId;if(!r)return!1;let n={...e,timestamp:Date.now(),sessionId:r},i=this.getFilePath(r);return(0,n0.writeFileSync)(i,JSON.stringify(n,null,2),"utf-8"),!0}catch{return!1}}getBaseDir(){return this.baseDir}}}),PE,Bu,vk=Ur(()=>{"use strict";Fy(),Sy(),Qy(),PE=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 r=this.createHandler(t),n=t.type+"_"+Date.now();this.registerHandler(n,r)}catch(r){console.error(`[OutputManager] Failed to register ${t.type} handler:`,r)}}createHandler(e){switch(e.type){case"console":return new xy(e.config);case"webhook":return new vy(e.config);case"temp-file":return new _y(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 r={...this.defaultOptions,...t},n={success:[],failed:[]},i=Array.from(this.handlers.entries()).map(async([o,s])=>{try{await s.output(e,r)?n.success.push(o):n.failed.push(o)}catch(a){console.error(`[OutputManager] Handler ${o} failed:`,a),n.failed.push(o)}});return await Promise.all(i),n}async outputTo(e,t,r){let n={...this.defaultOptions,...r},i={success:[],failed:[]},o=e.map(async s=>{let a=this.handlers.get(s);if(!a){console.warn(`[OutputManager] Handler ${s} not found`),i.failed.push(s);return}try{await a.output(t,n)?i.success.push(s):i.failed.push(s)}catch(u){console.error(`[OutputManager] Handler ${s} failed:`,u),i.failed.push(s)}});return await Promise.all(o),i}async outputToType(e,t,r){let n=Array.from(this.handlers.entries()).filter(([i,o])=>o.type===e).map(([i])=>i);return this.outputTo(n,t,r)}},Bu=new PE}),Sk=Ns(gC(),1),UE=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,gE.join)(process.cwd(),this.options.jsonPath);if((0,i0.existsSync)(e))try{let t=(0,i0.readFileSync)(e,"utf-8"),r=Sk.default.parse(t);this.config={...this.config,...r},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,gE.join)(process.cwd(),this.options.envPath);if((0,i0.existsSync)(e))try{let t=(0,nN.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 r=this.config[e];return r!==void 0?r:t}getAll(){return{...this.config}}getHttpsProxy(){return this.get("HTTPS_PROXY")||this.get("https_proxy")||this.get("httpsProxy")||this.get("PROXY_URL")}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 Zn(e,t=500,r="internal_error",n="api_error"){let i=new Error(e);return i.statusCode=t,i.code=r,i.type=n,i}async function _k(e,t,r){t.log.error(e);let n=e.statusCode||500,i={error:{message:e.message+e.stack||"Internal Server Error",type:e.type||"api_error",code:e.code||"internal_error"}};return r.code(n).send(i)}function Qk(e,t,r,n,i){let o=new Headers({"Content-Type":"application/json"});r.headers&&Object.entries(r.headers).forEach(([l,c])=>{c&&o.set(l,c)});let s,a=AbortSignal.timeout(r.TIMEOUT??60*1e3*60);if(r.signal){let l=new AbortController,c=()=>l.abort();r.signal.addEventListener("abort",c),a.addEventListener("abort",c),s=l.signal}else s=a;let u={method:"POST",headers:o,body:JSON.stringify(t),signal:s};return r.httpsProxy&&(u.dispatcher=new iN.ProxyAgent(new URL(r.httpsProxy).toString())),i?.debug({reqId:n.req.id,request:u,headers:Object.fromEntries(o.entries()),requestUrl:typeof e=="string"?e:e.toString(),useProxy:r.httpsProxy},"final request"),fetch(typeof e=="string"?e:e.toString(),u)}var Rk="1.0.51";async function Tk(e,t,r,n){let i=e.body,o=e.provider,s=r.providerService.getProvider(o);if(!s)throw Zn(`Provider '${o}' not found`,404,"provider_not_found");try{let{requestBody:a,config:u,bypass:l}=await Ry(i,s,n,e.headers,{req:e}),c=await Ty(a,u,s,r,l,n,{req:e}),A=await Ny(a,c,s,n,l,{req:e});return ky(A,t,i)}catch(a){if(a.code==="provider_response_error"){let u=await Nk(e,t,r,n,a);if(u)return u}throw a}}async function Nk(e,t,r,n,i){let o=e.scenarioType||"default",s=r.configService.get("fallback");if(!s||!s[o])return null;let a=s[o];if(!Array.isArray(a)||a.length===0)return null;e.log.warn(`Request failed for ${e.scenarioType}, trying ${a.length} fallback models`);for(let u of a)try{e.log.info(`Trying fallback model: ${u}`);let l={...e.body},[c,...A]=u.split(",");l.model=A.join(",");let p={...e,provider:c,body:l},h=r.providerService.getProvider(c);if(!h){e.log.warn(`Fallback provider '${c}' not found, skipping`);continue}let{requestBody:d,config:f,bypass:g}=await Ry(l,h,n,e.headers,{req:p}),E=await Ty(d,f,h,r,g,n,{req:p}),C=await Ny(d,E,h,n,g,{req:p});return e.log.info(`Fallback model ${u} succeeded`),ky(C,t,l)}catch(l){e.log.warn(`Fallback model ${u} failed: ${l.message}`);continue}return e.log.error(`All fallback models failed for yichu ${o}`),null}async function Ry(e,t,r,n,i){let o=e,s={},a=!1;if(a=kk(t,r,e),a&&(n instanceof Headers?n.delete("content-length"):delete n["content-length"],s.headers=n),!a&&typeof r.transformRequestOut=="function"){let u=await r.transformRequestOut(o);u.body?(o=u.body,s=u.config||{}):o=u}if(!a&&t.transformer?.use?.length)for(let u of t.transformer.use){if(!u||typeof u.transformRequestIn!="function")continue;let l=await u.transformRequestIn(o,t,i);l.body?(o=l.body,s={...s,...l.config}):o=l}if(!a&&t.transformer?.[e.model]?.use?.length)for(let u of t.transformer[e.model].use)!u||typeof u.transformRequestIn!="function"||(o=await u.transformRequestIn(o,t,i));return{requestBody:o,config:s,bypass:a}}function kk(e,t,r){return e.transformer?.use?.length===1&&e.transformer.use[0].name===t.name&&(!e.transformer?.[r.model]?.use.length||e.transformer?.[r.model]?.use.length===1&&e.transformer?.[r.model]?.use[0].name===t.name)}async function Ty(e,t,r,n,i,o,s){let a=t.url||new URL(r.baseUrl);if(i&&typeof o.auth=="function"){let c=await o.auth(e,r);if(c.body){e=c.body;let A=t.headers||{};c.config?.headers&&(A={...A,...c.config.headers},delete A.host,delete c.config.headers),t={...t,...c.config,headers:A}}else e=c}let u={Authorization:`Bearer ${r.apiKey}`,...t?.headers||{},...r.headers||{}};for(let c in u)(u[c]==="undefined"||["authorization","Authorization"].includes(c)&&u[c]?.includes("undefined"))&&delete u[c];let l=await Qk(a,e,{httpsProxy:n.configService.getHttpsProxy(),...t,headers:JSON.parse(JSON.stringify(u))},s,n.log);if(!l.ok){let c=await l.text();throw n.log.error(`[provider_response_error] Error from provider(${r.name},${e.model}: ${l.status}): ${c}`),Zn(`Error from provider(${r.name},${e.model}: ${l.status}): ${c}`,l.status,"provider_response_error")}return l}async function Ny(e,t,r,n,i,o){let s=t;if(!i&&r.transformer?.use?.length)for(let a of Array.from(r.transformer.use).reverse())!a||typeof a.transformResponseOut!="function"||(s=await a.transformResponseOut(s,o));if(!i&&r.transformer?.[e.model]?.use?.length)for(let a of Array.from(r.transformer[e.model].use).reverse())!a||typeof a.transformResponseOut!="function"||(s=await a.transformResponseOut(s,o));return!i&&n.transformResponseIn&&(s=await n.transformResponseIn(s,o)),s}function ky(e,t,r){return e.ok||t.code(e.status),r.stream===!0?(t.header("Content-Type","text/event-stream"),t.header("Cache-Control","no-cache"),t.header("Connection","keep-alive"),t.send(e.body)):e.json()}var ME=async e=>{e.get("/",async()=>({message:"LLMs API",version:Rk})),e.get("/health",async()=>({status:"ok",timestamp:new Date().toISOString()}));let t=e.transformerService.getTransformersWithEndpoint();for(let{transformer:r}of t)r.endPoint&&e.post(r.endPoint,async(n,i)=>Tk(n,i,e,r));e.post("/providers",{schema:{body:{type:"object",properties:{id:{type:"string"},name:{type:"string"},type:{type:"string",enum:["openai","anthropic"]},baseUrl:{type:"string"},apiKey:{type:"string"},models:{type:"array",items:{type:"string"}}},required:["id","name","type","baseUrl","apiKey","models"]}}},async(r,n)=>{let{name:i,baseUrl:o,apiKey:s,models:a}=r.body;if(!i?.trim())throw Zn("Provider name is required",400,"invalid_request");if(!o||!Ok(o))throw Zn("Valid base URL is required",400,"invalid_request");if(!s?.trim())throw Zn("API key is required",400,"invalid_request");if(!a||!Array.isArray(a)||a.length===0)throw Zn("At least one model is required",400,"invalid_request");if(e.providerService.getProvider(r.body.name))throw Zn(`Provider with name '${r.body.name}' already exists`,400,"provider_exists");return e.providerService.registerProvider(r.body)}),e.get("/providers",async()=>e.providerService.getProviders()),e.get("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]}}},async r=>{let n=e.providerService.getProvider(r.params.id);if(!n)throw Zn("Provider not found",404,"provider_not_found");return n}),e.put("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]},body:{type:"object",properties:{name:{type:"string"},type:{type:"string",enum:["openai","anthropic"]},baseUrl:{type:"string"},apiKey:{type:"string"},models:{type:"array",items:{type:"string"}},enabled:{type:"boolean"}}}}},async(r,n)=>{let i=e.providerService.updateProvider(r.params.id,r.body);if(!i)throw Zn("Provider not found",404,"provider_not_found");return i}),e.delete("/providers/:id",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]}}},async r=>{if(!e.providerService.deleteProvider(r.params.id))throw Zn("Provider not found",404,"provider_not_found");return{message:"Provider deleted successfully"}}),e.patch("/providers/:id/toggle",{schema:{params:{type:"object",properties:{id:{type:"string"}},required:["id"]},body:{type:"object",properties:{enabled:{type:"boolean"}},required:["enabled"]}}},async(r,n)=>{if(!e.providerService.toggleProvider(r.params.id,r.body.enabled))throw Zn("Provider not found",404,"provider_not_found");return{message:`Provider ${r.body.enabled?"enabled":"disabled"} successfully`}})};function Ok(e){try{return new URL(e),!0}catch{return!1}}var $E=class{constructor(e,t,r){this.configService=e,this.transformerService=t,this.logger=r,this.initializeCustomProviders()}providers=new Map;modelRoutes=new Map;initializeCustomProviders(){let e=this.configService.get("providers");if(e&&Array.isArray(e)){this.initializeFromProvidersArray(e);return}}initializeFromProvidersArray(e){e.forEach(t=>{try{if(!t.name||!t.api_base_url||!t.api_key)return;let r={};t.transformer&&Object.keys(t.transformer).forEach(n=>{n==="use"?Array.isArray(t.transformer.use)&&(r.use=t.transformer.use.map(i=>{if(Array.isArray(i)&&typeof i[0]=="string"){let o=this.transformerService.getTransformer(i[0]);if(o)return new o(i[1])}if(typeof i=="string"){let o=this.transformerService.getTransformer(i);return typeof o=="function"?new o:o}}).filter(i=>typeof i<"u")):Array.isArray(t.transformer[n]?.use)&&(r[n]={use:t.transformer[n].use.map(i=>{if(Array.isArray(i)&&typeof i[0]=="string"){let o=this.transformerService.getTransformer(i[0]);if(o)return new o(i[1])}if(typeof i=="string"){let o=this.transformerService.getTransformer(i);return typeof o=="function"?new o:o}}).filter(i=>typeof i<"u")})}),this.registerProvider({name:t.name,baseUrl:t.api_base_url,apiKey:t.api_key,models:t.models||[],headers:t.headers,transformer:t.transformer?r:void 0}),this.logger.info(`${t.name} provider registered`)}catch(r){this.logger.error(`${t.name} provider registered error: ${r}`)}})}registerProvider(e){let t={...e};return this.providers.set(t.name,t),e.models.forEach(r=>{let n=`${t.name},${r}`,i={provider:t.name,model:r,fullModel:n};this.modelRoutes.set(n,i),this.modelRoutes.has(r)||this.modelRoutes.set(r,i)}),t}getProviders(){return Array.from(this.providers.values())}getProvider(e){return this.providers.get(e)}updateProvider(e,t){let r=this.providers.get(e);if(!r)return null;let n={...r,...t,updatedAt:new Date};return this.providers.set(e,n),t.models&&(r.models.forEach(i=>{let o=`${r.name},${i}`;this.modelRoutes.delete(o),this.modelRoutes.delete(i)}),t.models.forEach(i=>{let o=`${r.name},${i}`,s={provider:r.name,model:i,fullModel:o};this.modelRoutes.set(o,s),this.modelRoutes.has(i)||this.modelRoutes.set(i,s)})),n}deleteProvider(e){let t=this.providers.get(e);return t?(t.models.forEach(r=>{let n=`${t.name},${r}`;this.modelRoutes.delete(n),this.modelRoutes.delete(r)}),this.providers.delete(e),!0):!1}toggleProvider(e,t){return!!this.providers.get(e)}resolveModelRoute(e){let t=this.modelRoutes.get(e);if(!t)return null;let r=this.providers.get(t.provider);return r?{provider:r,originalModel:e,targetModel:t.model}:null}getAvailableModelNames(){let e=[];return this.providers.forEach(t=>{t.models.forEach(r=>{e.push(r),e.push(`${t.name},${r}`)})}),e}getModelRoutes(){return Array.from(this.modelRoutes.values())}parseTransformerConfig(e){return e?Array.isArray(e)?e.reduce((t,r)=>{if(Array.isArray(r)){let[n,i={}]=r;t[n]=i}else t[r]={};return t},{}):e:{}}async getAvailableModels(){let e=[];return this.providers.forEach(t=>{t.models.forEach(r=>{e.push({id:r,object:"model",owned_by:t.name,provider:t.name}),e.push({id:`${t.name},${r}`,object:"model",owned_by:t.name,provider:t.name})})}),{object:"list",data:e}}},un=[];for(let e=0;e<256;++e)un.push((e+256).toString(16).slice(1));function Lk(e,t=0){return(un[e[t+0]]+un[e[t+1]]+un[e[t+2]]+un[e[t+3]]+"-"+un[e[t+4]]+un[e[t+5]]+"-"+un[e[t+6]]+un[e[t+7]]+"-"+un[e[t+8]]+un[e[t+9]]+"-"+un[e[t+10]]+un[e[t+11]]+un[e[t+12]]+un[e[t+13]]+un[e[t+14]]+un[e[t+15]]).toLowerCase()}var mc=new Uint8Array(256),sc=mc.length;function Pk(){return sc>mc.length-16&&((0,sN.randomFillSync)(mc),sc=0),mc.slice(sc,sc+=16)}var HE={randomUUID:oN.randomUUID};function Uk(e,t,r){if(HE.randomUUID&&!t&&!e)return HE.randomUUID();e=e||{};let n=e.random??e.rng?.()??Pk();if(n.length<16)throw new Error("Random bytes length must be >= 16");if(n[6]=n[6]&15|64,n[8]=n[8]&63|128,t){if(r=r||0,r<0||r+16>t.length)throw new RangeError(`UUID byte range ${r}:${r+15} is out of buffer bounds`);for(let i=0;i<16;++i)t[r+i]=n[i];return t}return Lk(n)}var xu=Uk,Mk=e=>e<=0?"none":e<=1024?"low":e<=8192?"medium":"high",$k=(e,t)=>(e.includes("base64")&&(e=e.split("base64").pop(),e.startsWith(",")&&(e=e.slice(1))),`data:${t};base64,${e}`),Hk=class{constructor(e){this.options=e,this.useBearer=this.options?.UseBearer??!1}name="Anthropic";endPoint="/v1/messages";useBearer;logger;async auth(e,t){let r={};return this.useBearer?(r.authorization=`Bearer ${t.apiKey}`,r["x-api-key"]=void 0):(r["x-api-key"]=t.apiKey,r.authorization=void 0),{body:e,config:{headers:r}}}async transformRequestOut(e){let t=[];if(e.system){if(typeof e.system=="string")t.push({role:"system",content:e.system});else if(Array.isArray(e.system)&&e.system.length){let n=e.system.filter(i=>i.type==="text"&&i.text).map(i=>({type:"text",text:i.text,cache_control:i.cache_control}));t.push({role:"system",content:n})}}JSON.parse(JSON.stringify(e.messages||[]))?.forEach(n=>{if(n.role==="user"||n.role==="assistant"){if(typeof n.content=="string"){t.push({role:n.role,content:n.content});return}if(Array.isArray(n.content)){if(n.role==="user"){let i=n.content.filter(s=>s.type==="tool_result"&&s.tool_use_id);i.length&&i.forEach(s=>{let a={role:"tool",content:typeof s.content=="string"?s.content:JSON.stringify(s.content),tool_call_id:s.tool_use_id,cache_control:s.cache_control};t.push(a)});let o=n.content.filter(s=>s.type==="text"&&s.text||s.type==="image"&&s.source);o.length&&t.push({role:"user",content:o.map(s=>s?.type==="image"?{type:"image_url",image_url:{url:s.source?.type==="base64"?$k(s.source.data,s.source.media_type):s.source.url},media_type:s.source.media_type}:s)})}else if(n.role==="assistant"){let i={role:"assistant",content:""},o=n.content.filter(u=>u.type==="text"&&u.text);o.length&&(i.content=o.map(u=>u.text).join(`
583
583
  `));let s=n.content.filter(u=>u.type==="tool_use"&&u.id);s.length&&(i.tool_calls=s.map(u=>({id:u.id,type:"function",function:{name:u.name,arguments:JSON.stringify(u.input||{})}})));let a=n.content.find(u=>u.type==="thinking"&&u.signature);a&&(i.thinking={content:a.thinking,signature:a.signature}),t.push(i)}return}}});let r={messages:t,model:e.model,max_tokens:e.max_tokens,temperature:e.temperature,stream:e.stream,tools:e.tools?.length?this.convertAnthropicToolsToUnified(e.tools):void 0,tool_choice:e.tool_choice};return e.thinking&&(r.reasoning={effort:Mk(e.thinking.budget_tokens),enabled:e.thinking.type==="enabled"}),e.tool_choice&&(e.tool_choice.type==="tool"?r.tool_choice={type:"function",function:{name:e.tool_choice.name}}:r.tool_choice=e.tool_choice.type),r}async transformResponseIn(e,t){if(e.headers.get("Content-Type")?.includes("text/event-stream")){if(!e.body)throw new Error("Stream response body is null");let r=await this.convertOpenAIStreamToAnthropic(e.body,t);return new Response(r,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}else{let r=await e.json(),n=this.convertOpenAIResponseToAnthropic(r,t);return new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json"}})}}convertAnthropicToolsToUnified(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description||"",parameters:t.input_schema}}))}async convertOpenAIStreamToAnthropic(e,t){return new ReadableStream({start:async r=>{let n=new TextEncoder,i=`msg_${Date.now()}`,o=null,s="unknown",a=!1,u=!1,l=!1,c=new Map,A=new Map,p=0,h=0,d=0,f=!1,g=!1,E=0,C=-1,m=()=>{let y=E;return E++,y},D=y=>{if(!f)try{r.enqueue(y);let b=new TextDecoder().decode(y);this.logger.debug({reqId:t.req.id,data:b,type:"send data"})}catch(b){if(b instanceof TypeError&&b.message.includes("Controller is already closed"))f=!0;else throw this.logger.debug({reqId:t.req.id,error:b instanceof Error?b.message:String(b),type:"send data error"}),b}},B=()=>{if(!f)try{if(C>=0){let b={type:"content_block_stop",index:C};D(n.encode(`event: content_block_stop
584
584
  data: ${JSON.stringify(b)}
585
585
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@washanhanzi/claude-code-router",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Use Claude Code without an Anthropics account and route it to another LLM provider",
5
5
  "scripts": {
6
6
  "build": "pnpm build:shared && pnpm build:core && pnpm build:server && pnpm build:cli && pnpm build:ui",