@juspay/neurolink 10.7.0 → 10.7.1
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/CHANGELOG.md +6 -0
- package/dist/browser/neurolink.min.js +1 -1
- package/dist/cli/commands/proxyAnalyze.js +1 -1
- package/dist/lib/proxy/proxyAnalysis.js +27 -9
- package/dist/lib/server/routes/claudeProxyRoutes.d.ts +16 -2
- package/dist/lib/server/routes/claudeProxyRoutes.js +15 -9
- package/dist/lib/types/proxy.d.ts +3 -0
- package/dist/proxy/proxyAnalysis.js +27 -9
- package/dist/server/routes/claudeProxyRoutes.d.ts +16 -2
- package/dist/server/routes/claudeProxyRoutes.js +15 -9
- package/dist/types/proxy.d.ts +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [10.7.1](https://github.com/juspay/neurolink/compare/v10.7.0...v10.7.1) (2026-07-29)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **(proxy):** make routing evidence non-fatal and bounded ([0347365](https://github.com/juspay/neurolink/commit/0347365963f502f2662eb0690fbeecef192f05de))
|
|
6
|
+
|
|
1
7
|
## [10.7.0](https://github.com/juspay/neurolink/compare/v10.6.5...v10.7.0) (2026-07-29)
|
|
2
8
|
|
|
3
9
|
### Features
|
|
@@ -2466,7 +2466,7 @@ data: ${t}
|
|
|
2466
2466
|
`))}catch{}},u);try{for(let R=0;R<s.length&&!f;R++){let P=s[R];S=P.label??"translation",g.always(`[proxy:${t}] attempt ${R+1}/${s.length}: ${P.label}`),uw(S,"translation");let A="";try{let I=RJ(o,P.provider?{provider:P.provider,model:P.model}:{}),M=await kt(e.neurolink.stream(I),kJ,`Translation attempt ${P.label} timed out after ${kJ}ms`);for(T=M.stream[Symbol.asyncIterator]();!f;){let{value:z,done:$}=await T.next();if($||f)break;let U=CJ(z);if(U){A+=U;for(let B of l.pushDelta(U))C.enqueue(d.encode(B))}}if(f)return;let F=M.toolCalls??[];if(!gF(A,F)){b=`Translated provider ${P.label} returned no content or tool calls`,g.debug(`${c} translation attempt ${P.label} returned no content or tool calls`),ao(S,"translation",502);continue}if(!f&&F.length)for(let z of F){let $=z.toolName??z.name??"unknown",U=z.toolCallId||$in(t);for(let B of l.pushToolUse(U,$,sve(z)))C.enqueue(d.encode(B))}if(!f){let z=M.finishReason??dnt(t),$=dw(M.usage);for(let U of l.finish(z,$))C.enqueue(d.encode(U))}let N=dw(M.usage);i?.setUsage({inputTokens:N.input,outputTokens:N.output,cacheCreationTokens:0,cacheReadTokens:0}),i?.recordMetrics(),x=M.model,h=!0;return}catch(I){if(f)return;if(b=I instanceof Error?I.message:String(I),A.trim().length>0){y=!0,ao(S,"translation",502),g.always(`${c} mid-stream error: ${b}`);for(let M of l.emitError(`Upstream stream interrupted: ${b}`))C.enqueue(d.encode(M));return}g.debug(`${c} translation attempt ${P.label} failed: ${b}`),ao(S,"translation",500)}}if(!f){g.always(`${c} all translation attempts failed: ${b}`);for(let R of l.emitError(b))C.enqueue(d.encode(R))}}finally{p&&clearInterval(p),f||C.close(),i&&x&&x!==n&&i.setModelSubstitution(n,x);let R=f?499:h?200:y?502:500,P=f?"client_cancelled":y?"stream_error":h?void 0:"generation_error",A=f?"Client cancelled the streaming response":h?void 0:b;P&&A?(i?.setError(P,A.slice(0,500)),gA(R,S,"translation",{requestId:e.requestId,errorType:P,terminalOutcome:P,message:A})):fF(S,"translation"),i?.end(R,Date.now()-a);let I=i?.getTraceContext();zf({timestamp:new Date().toISOString(),requestId:e.requestId,method:e.method,path:e.path,model:n,stream:!0,toolCount:Object.keys(o.tools).length,account:"translation",accountType:"translation",responseStatus:R,responseTimeMs:Date.now()-a,...P?{errorType:P}:{},...A?{errorMessage:A.slice(0,500)}:{},...I?.traceId?{traceId:I.traceId}:{},...I?.spanId?{spanId:I.spanId}:{}})}},cancel(){f=!0,p&&(clearInterval(p),p=void 0),T?.return&&T.return(void 0).catch(C=>{g.debug(`${c} upstream cancel error: ${C instanceof Error?C.message:String(C)}`)})}});return new Response(E,{headers:{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"}})}async function IJ(r){let{ctx:e,format:t,requestModel:n,parsed:o,attempts:s,tracer:i,requestStartTime:a,terminalFailureStatus:c=500}=r,l=pnt(t),u="No translation providers succeeded",d="translation";for(let f=0;f<s.length;f++){let h=s[f];d=h.label??"translation",g.always(`[proxy:${t}] attempt ${f+1}/${s.length}: ${h.label}`),uw(d,"translation");try{let y=RJ(o,h.provider?{provider:h.provider,model:h.model}:{}),x=await kt(e.neurolink.stream(y),kJ,`Translation attempt ${h.label} timed out after ${kJ}ms`),b="";for await(let C of x.stream){let R=CJ(C);R&&(b+=R)}if(!gF(b,x.toolCalls)){u=`Translated provider ${h.label} returned no content or tool calls`,g.debug(`${l} translation attempt ${h.label} returned no content or tool calls`),ao(d,"translation",502);continue}let T={content:b,model:x.model,finishReason:x.finishReason??dnt(t),reasoning:void 0,usage:x.usage?dw(x.usage):void 0,toolCalls:x.toolCalls},S=dw(x.usage);i?.setUsage({inputTokens:S.input,outputTokens:S.output,cacheCreationTokens:0,cacheReadTokens:0}),i?.recordMetrics(),i&&x.model&&x.model!==n&&i.setModelSubstitution(n,x.model),i?.end(200,Date.now()-a),fF(d,"translation");let E=i?.getTraceContext();return zf({timestamp:new Date().toISOString(),requestId:e.requestId,method:e.method,path:e.path,model:n,stream:!1,toolCount:Object.keys(o.tools).length,account:"translation",accountType:"translation",responseStatus:200,responseTimeMs:Date.now()-a,inputTokens:S.input,outputTokens:S.output,...E?.traceId?{traceId:E.traceId}:{},...E?.spanId?{spanId:E.spanId}:{}}),t==="claude"?yJ(T,n):Xbe(T,n)}catch(y){u=y instanceof Error?y.message:String(y),g.debug(`${l} translation attempt ${h.label} failed: ${u}`),ao(d,"translation",500)}}gA(c,d,"translation",{requestId:e.requestId,errorType:"generation_error",terminalOutcome:"handler_error",message:u}),i?.setError("generation_error",u.slice(0,500)),i?.end(c,Date.now()-a);let p=i?.getTraceContext();throw zf({timestamp:new Date().toISOString(),requestId:e.requestId,method:e.method,path:e.path,model:n,stream:!1,toolCount:Object.keys(o.tools).length,account:"translation",accountType:"translation",responseStatus:c,responseTimeMs:Date.now()-a,errorType:"generation_error",errorMessage:u.slice(0,500),...p?.traceId?{traceId:p.traceId}:{},...p?.spanId?{spanId:p.spanId}:{}}),new Ue({code:ut.PROVIDER_NOT_AVAILABLE,message:u,category:"execution",severity:"high",retriable:!1,context:{attemptLabel:d,format:t}})}function mnt(r){let e=[];if(r){let t=r.getModelMappings?.()??[];for(let o of t)e.push({id:o.from,object:"model",created:0,owned_by:"neurolink"});let n=r.getPassthroughModels?.()??[];for(let o of n)e.push({id:o,object:"model",created:0,owned_by:"neurolink"})}if(e.length===0)for(let t of fnt)e.push({id:t,object:"model",created:0,owned_by:"neurolink"});return{object:"list",data:e}}var fnt=["claude-opus-4-6","claude-sonnet-4-6","claude-haiku-4-5","claude-sonnet-4-20250514","claude-3-5-sonnet-20241022","claude-3-5-haiku-20241022","gpt-4o","gemini-2.5-pro","gemini-2.5-flash"];function gnt(r){let e=[];if(r){let s=r.getModelMappings?.()??[];for(let a of s)a.from&&e.push(a.from);let i=r.getPassthroughModels?.()??[];for(let a of i)e.push(a)}e.length===0&&e.push(...fnt);let t=new Set,o=e.filter(s=>t.has(s)?!1:(t.add(s),!0)).map(s=>({type:"model",id:s,display_name:Bin(s),created_at:new Date(0).toISOString()}));return{data:o,first_id:o[0]?.id??null,last_id:o[o.length-1]?.id??null,has_more:!1}}function Bin(r){let t=r.replace(/-\d{8}$/,"").split("-"),n=[],o=[];for(let i of t)/^\d+$/.test(i)&&o.length>0&&o[0].toLowerCase()==="claude"?n.push(i):o.push(i.charAt(0).toUpperCase()+i.slice(1));let s=n.length>0?` ${n.join(".")}`:"";return o.length>0?`${o[0]}${s}${o.slice(1).length?" "+o.slice(1).join(" "):""}`:r}Hr();An();Lr();Kg();See();Cd();x_();J();var zin="[ProxyTracer]",ive=null;function hF(){if(ive)return ive;let r=Kf.getMeter("neurolink.proxy","1.0.0"),e={requestsTotal:r.createCounter("proxy_requests_total",{description:"Total number of proxy requests",unit:"{request}"}),requestDuration:r.createHistogram("proxy_request_duration_ms",{description:"Proxy request duration in milliseconds",unit:"ms"}),tokensInput:r.createCounter("proxy_tokens_input",{description:"Total input tokens consumed via proxy",unit:"{token}"}),tokensOutput:r.createCounter("proxy_tokens_output",{description:"Total output tokens produced via proxy",unit:"{token}"}),tokensCacheRead:r.createCounter("proxy_tokens_cache_read",{description:"Total cache-read tokens via proxy",unit:"{token}"}),tokensCacheCreation:r.createCounter("proxy_tokens_cache_creation",{description:"Total cache-creation tokens via proxy",unit:"{token}"}),tokensReasoning:r.createCounter("proxy_tokens_reasoning",{description:"Total reasoning tokens via proxy",unit:"{token}"}),costTotal:r.createCounter("proxy_cost_usd_total",{description:"Total estimated cost in USD",unit:"USD"}),errorsTotal:r.createCounter("proxy_errors_total",{description:"Total proxy errors",unit:"{error}"}),retriesTotal:r.createCounter("proxy_retries_total",{description:"Total upstream retry attempts",unit:"{retry}"}),modelSubstitutionTotal:r.createCounter("proxy_model_substitution_total",{description:"Total proxy requests where the response model differs from the requested model",unit:"{substitution}"}),requestBodySize:r.createHistogram("proxy_request_body_bytes",{description:"Request body size in bytes sent upstream",unit:"By"}),responseBodySize:r.createHistogram("proxy_response_body_bytes",{description:"Response body size in bytes received from upstream",unit:"By"}),fallbackAttemptsTotal:r.createCounter("proxy_fallback_attempts_total",{description:"Total fallback provider attempts",unit:"{attempt}"}),fallbackSuccessTotal:r.createCounter("proxy_fallback_success_total",{description:"Total successful fallback provider responses",unit:"{success}"}),fallbackFailureTotal:r.createCounter("proxy_fallback_failure_total",{description:"Total failed fallback provider responses",unit:"{failure}"})};return ive=e,e}var jin=new Set(["authorization","proxy-authorization","x-api-key","cookie","set-cookie"]),Gin=/token|secret|key|password|credential/i;function ave(r){let e={};for(let[t,n]of Object.entries(r)){let o=t.toLowerCase();jin.has(o)||Gin.test(o)?e[t]="[REDACTED]":e[t]=n}return e}var Vin=/api[_-]?key|token|secret|password|credential|authorization/i,PJ=process.env.NEUROLINK_PROXY_TRACE_BODY_LOGGING==="true",lve=Number.parseInt(process.env.NEUROLINK_PROXY_TRACE_BODY_LOG_BYTES??"8192",10),hnt=200;function ynt(r,e=8192){let t=r.length>e?r.slice(0,e)+"\u2026[truncated]":r;try{let s=function(i){if(i===null||typeof i!="object")return i;if(Array.isArray(i))return i.map(s);let a={};for(let[c,l]of Object.entries(i))a[c]=Vin.test(c)?"[REDACTED]":s(l);return a};var n=s;let o=JSON.parse(t);return JSON.stringify(s(o))}catch{return t}}function cve(r){return{"proxy.body":ynt(r,lve),"proxy.body.size":r.length,"proxy.body.logged":!0,"proxy.body.truncated":r.length>lve}}function qin(r){return r?r.startsWith("claude-cli/")?"cli":r.startsWith("ai/")?"sdk":"unknown":"unknown"}var hA=class r{rootSpan;proxyTracer=IN("neurolink.proxy");bridge=new pg;requestId;model;startTime;isStream;accountEmail;usage;mode="full";constructor(e,t,n,o){this.rootSpan=e,this.requestId=t,this.model=n,this.startTime=Date.now(),this.isStream=o}static startRequest(e,t){let n=IN("neurolink.proxy"),o=wr.active();if(t){let p=new pg().extractContext(t);p&&(o=_t.setSpanContext(wr.active(),p))}let s=e.clientApp??qin(e.userAgent),i=n.startSpan("proxy.request",{attributes:{"proxy.request_id":e.requestId,"http.method":e.method,"http.target":e.path,"gen_ai.request.model":e.model,"proxy.stream":e.stream,"proxy.tool_count":e.toolCount,"proxy.client_app":s}},o);e.sessionId&&i.setAttribute("session.id",e.sessionId),e.userAgent&&i.setAttribute("http.user_agent",e.userAgent),e.toolNames&&e.toolNames.length>0&&i.setAttribute("gen_ai.request.tool_names",JSON.stringify(e.toolNames));let a=t?.["x-neurolink-session-id"],c=t?.["x-neurolink-user-id"],l=t?.["x-neurolink-conversation-id"];a&&i.setAttribute("neurolink.session_id",a),c&&i.setAttribute("neurolink.user_id",c),l&&i.setAttribute("neurolink.conversation_id",l);let u=new r(i,e.requestId,e.model,e.stream);return Mx({sessionId:a??e.sessionId,userId:c,conversationId:l,requestId:e.requestId,traceName:`proxy:${e.model}`,operationName:"proxy.request",metadata:{clientApp:s,stream:e.stream,toolCount:e.toolCount}}).catch(d=>{g.debug(`${zin} Failed to set Langfuse context`,{error:d instanceof Error?d.message:String(d)})}),u}startReceive(){return this.proxyTracer.startSpan("proxy.receive",{attributes:{"proxy.request_id":this.requestId}},_t.setSpan(wr.active(),this.rootSpan))}startAccountSelection(){return this.proxyTracer.startSpan("proxy.account_selection",{attributes:{"proxy.request_id":this.requestId}},_t.setSpan(wr.active(),this.rootSpan))}startUpstreamAttempt(e){return this.proxyTracer.startSpan("proxy.upstream",{attributes:{"proxy.request_id":this.requestId,"proxy.upstream.attempt":e.attempt,"proxy.upstream.account":e.account,"proxy.upstream.polyfill_headers":e.polyfillHeaders,"proxy.upstream.polyfill_body":e.polyfillBody,"http.url":e.upstreamUrl}},_t.setSpan(wr.active(),this.rootSpan))}startStream(){return this.proxyTracer.startSpan("proxy.stream",{attributes:{"proxy.request_id":this.requestId,"gen_ai.request.model":this.model}},_t.setSpan(wr.active(),this.rootSpan))}setAccountSelection(e){this.accountEmail=e.selectedAccount,this.rootSpan.setAttributes({"proxy.account.strategy":e.strategy,"proxy.account.total":e.accountsTotal,"proxy.account.healthy":e.accountsHealthy,"proxy.account.selected":e.selectedAccount,"proxy.account.type":e.accountType}),e.rateLimitBefore5h!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.before.5h",e.rateLimitBefore5h),e.rateLimitBefore7d!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.before.7d",e.rateLimitBefore7d),Mx({userId:e.selectedAccount}).catch(()=>{})}setUsage(e){this.usage=e;let t=e.inputTokens+e.outputTokens+e.cacheCreationTokens+e.cacheReadTokens+(e.reasoningTokens??0);this.rootSpan.setAttributes({"ai.tokens.input":e.inputTokens,"ai.tokens.output":e.outputTokens,"ai.tokens.total":t,"ai.tokens.cache_creation":e.cacheCreationTokens,"ai.tokens.cache_read":e.cacheReadTokens}),e.reasoningTokens!==void 0&&this.rootSpan.setAttribute("ai.tokens.reasoning",e.reasoningTokens),this.rootSpan.setAttributes({"gen_ai.usage.input_tokens":e.inputTokens,"gen_ai.usage.output_tokens":e.outputTokens,"gen_ai.usage.total_tokens":t});let n=us("anthropic",this.model,{input:e.inputTokens,output:e.outputTokens,total:t,cacheCreationTokens:e.cacheCreationTokens,cacheReadTokens:e.cacheReadTokens});n>0&&this.rootSpan.setAttributes({"ai.cost.total":n,"ai.cost.currency":"USD"}),e.rateLimitAfter5h!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.after.5h",e.rateLimitAfter5h),e.rateLimitAfter7d!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.after.7d",e.rateLimitAfter7d)}setResponseInfo(e){e.responseModel&&this.rootSpan.setAttribute("gen_ai.response.model",e.responseModel),e.finishReason&&this.rootSpan.setAttribute("gen_ai.response.finish_reason",e.finishReason),e.stopSequence&&this.rootSpan.setAttribute("gen_ai.response.stop_sequence",e.stopSequence),e.toolCalls&&e.toolCalls.length>0&&(this.rootSpan.setAttributes({"gen_ai.response.tool_calls":JSON.stringify(e.toolCalls),"gen_ai.response.tool_call_count":e.toolCalls.length}),this.rootSpan.addEvent("proxy.response.tool_calls",{"gen_ai.response.tool_calls":JSON.stringify(e.toolCalls)}))}setError(e,t){this.rootSpan.setAttributes({"error.type":e,"error.message":t,error:!0})}setMode(e){this.mode=e,this.rootSpan.setAttribute("proxy.mode",e)}setModelSubstitution(e,t){this.rootSpan.setAttributes({"proxy.model_substituted":!0,"proxy.original_model":e,"proxy.actual_model":t,"gen_ai.response.model":t}),hF().modelSubstitutionTotal.add(1,{requested_model:e,actual_model:t})}setFallbackInfo(e){this.rootSpan&&this.rootSpan.setAttributes({"proxy.fallback.triggered":e.triggered,...e.provider?{"proxy.fallback.provider":e.provider}:{},...e.model?{"proxy.fallback.model":e.model}:{},"proxy.fallback.attempt_count":e.attemptCount,"proxy.fallback.reason":e.reason})}logRequestBody(e){if(!PJ){this.rootSpan.addEvent("proxy.client.request_body",{"proxy.body.size":e.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.client.request_body",{...cve(e)})}logRequestHeaders(e){this.rootSpan.addEvent("proxy.client.request_headers",{"proxy.headers":JSON.stringify(ave(e))})}logUpstreamRequestBody(e){if(!PJ){this.rootSpan.addEvent("proxy.upstream.request_body",{"proxy.body.size":e.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.upstream.request_body",{...cve(e)})}logUpstreamRequestHeaders(e){this.rootSpan.addEvent("proxy.upstream.request_headers",{"proxy.headers":JSON.stringify(ave(e))})}logUpstreamResponseHeaders(e){this.rootSpan.addEvent("proxy.upstream.response_headers",{"proxy.headers":JSON.stringify(ave(e))})}logUpstreamResponseBody(e){if(!PJ){this.rootSpan.addEvent("proxy.upstream.response_body",{"proxy.body.size":e.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.upstream.response_body",{...cve(e)})}logStreamEvents(e){if(!PJ){this.rootSpan.addEvent("proxy.stream.events",{"proxy.stream.event_count":e.length,"proxy.body.logged":!1});return}let t=e.length>hnt,n=e.slice(0,hnt).map(o=>({...o,data:o.data?ynt(o.data,lve):""}));t&&n.push({type:"truncated",timestamp:Date.now(),data:"\u2026[truncated]"}),this.rootSpan.addEvent("proxy.stream.events",{"proxy.stream.event_count":e.length,"proxy.stream.events":JSON.stringify(n),"proxy.body.logged":!0,"proxy.body.truncated":t})}recordRetry(e,t){hF().retriesTotal.add(1,{model:this.model,account:e,reason:t})}recordBodySizes(e,t){let n=hF(),o={model:this.model,account:this.accountEmail??"unknown"};e!==void 0&&e>0&&n.requestBodySize.record(e,o),t!==void 0&&t>0&&n.responseBodySize.record(t,o)}getTraceContext(){let e=this.rootSpan.spanContext();return{traceId:e.traceId,spanId:e.spanId}}getUsage(){return this.usage}end(e,t){this.rootSpan.setAttributes({"http.status_code":e,"proxy.duration_ms":t,"proxy.mode":this.mode,...this.accountEmail?{"proxy.account":this.accountEmail}:void 0}),e>=400?this.rootSpan.setStatus({code:Fe.ERROR,message:`HTTP ${e}`}):this.rootSpan.setStatus({code:Fe.OK}),this.rootSpan.end();let n=hF(),o={model:this.model,account:this.accountEmail??"unknown",status:String(e),stream:String(this.isStream),mode:this.mode};if(n.requestsTotal.add(1,o),n.requestDuration.record(t,o),this.usage){let s={model:this.model,account:this.accountEmail??"unknown"};n.tokensInput.add(this.usage.inputTokens,s),n.tokensOutput.add(this.usage.outputTokens,s),n.tokensCacheRead.add(this.usage.cacheReadTokens,s),n.tokensCacheCreation.add(this.usage.cacheCreationTokens,s),this.usage.reasoningTokens&&n.tokensReasoning.add(this.usage.reasoningTokens,s);let i=this.usage.inputTokens+this.usage.outputTokens+this.usage.cacheCreationTokens+this.usage.cacheReadTokens+(this.usage.reasoningTokens??0),a=us("anthropic",this.model,{input:this.usage.inputTokens,output:this.usage.outputTokens,total:i,cacheCreationTokens:this.usage.cacheCreationTokens,cacheReadTokens:this.usage.cacheReadTokens});a>0&&n.costTotal.add(a,s)}if(e>=400){let s=e===429?"rate_limit":e===401?"auth":e>=500?"server":"client";n.errorsTotal.add(1,{model:this.model,account:this.accountEmail??"unknown",error_type:s,status:String(e)})}}recordMetrics(){if(!this.usage)return;let e=this.usage.inputTokens+this.usage.outputTokens+this.usage.cacheCreationTokens+this.usage.cacheReadTokens+(this.usage.reasoningTokens??0),t=Date.now()-this.startTime,n=us("anthropic",this.model,{input:this.usage.inputTokens,output:this.usage.outputTokens,total:e,cacheCreationTokens:this.usage.cacheCreationTokens,cacheReadTokens:this.usage.cacheReadTokens});Lm.getInstance().recordAIRequest("anthropic",this.model,e,t,n>0?n:void 0)}getTraceHeaders(){return this.bridge.injectContext({},_t.setSpan(wr.active(),this.rootSpan))}};function yF(r){try{let e=hF(),t={provider:r.provider,model:r.model};e.fallbackAttemptsTotal.add(1,t),r.status==="success"?e.fallbackSuccessTotal.add(1,t):e.fallbackFailureTotal.add(1,{...t,error:r.errorMessage?.slice(0,100)??"unknown"})}catch{}}var uve=`
|
|
2467
2467
|
...[TRUNCATED]`;function dve(){let r=new TextDecoder,e=[],t=0,n=0,o=!1,s=!1,i,a=new Promise(y=>{i=y});function c(){if(s)return;s=!0;let y=r.decode();if(y)if(n<1048576){let x=1048576-n;e.push(y.slice(0,x)),n+=Math.min(y.length,x)}else o||(e.push(uve),o=!0);i({totalBytes:t,text:e.join(""),truncated:o})}let l=new TransformStream({transform(y,x){if(x.enqueue(y),t+=y.byteLength,n<1048576){let b=r.decode(y,{stream:!0}),T=1048576-n,S=b.slice(0,T);e.push(S),n+=Math.min(b.length,T),b.length>T&&!o&&(e.push(uve),o=!0)}else o||(e.push(uve),o=!0)},flush(){c()}}),u=l.writable.getWriter(),d,p=new WritableStream({start(y){d=y},write(y){return u.write(y)},close(){return u.close()},abort(y){return c(),u.abort(y)}});u.closed.catch(y=>{c();try{d.error(y)}catch{}});let f=l.readable.getReader();return{stream:{readable:new ReadableStream({async pull(y){try{let{done:x,value:b}=await f.read();x?y.close():y.enqueue(b)}catch(x){y.error(x)}},async cancel(y){c();try{d.error(y)}catch{}await Promise.allSettled([f.cancel(y),u.abort(y)])}}),writable:p},capture:a}}cde();var ey="...[TRUNCATED]";function xF(r){let e=[],t=0;for(;t<r.length;){let n=/\r\n\r\n|\n\n|\r\r/.exec(r.slice(t));if(!n||n.index===void 0)break;let o=t+n.index,s=r.slice(t,o);t=o+n[0].length;let i="",a="",c=s.split(/\r\n|\n|\r/);for(let l of c)l.startsWith("event: ")?i=l.slice(7).trim():l.startsWith("data: ")?a=l.slice(6):l.startsWith("data:")&&(a=l.slice(5));(i||a)&&e.push({event:i,data:a})}return{events:e,remainder:r.slice(t)}}function Hin(r){return{messageId:"",model:"",inputTokens:0,outputTokens:0,cacheCreationInputTokens:0,cacheReadInputTokens:0,contentBlocks:[],blockByteCounts:new Map,stopReason:null,stopSequence:null,eventCount:0,startTime:Date.now(),totalBytesReceived:0,events:[],rawTextChunks:r?[]:void 0,rawTextBytes:0,rawTextTruncated:!1,eventLogTruncated:!1}}function yA(r){return Buffer.byteLength(r,"utf8")}function fve(r,e){if(yA(r)<=e)return r;let t=yA(ey);if(e<=0||e<t)return"";let n="",o=0;for(let s of r){let i=yA(s);if(o+i+t>e)break;n+=s,o+=i}return`${n}${ey}`}function pve(r,e){return fve(r,e)}function mve(r,e,t,n){let o=yA(e);if(t>=n)return{value:r&&r.endsWith(ey)?r:`${r??""}${ey}`,nextBytes:t+o};let s=n-t,i=t+o;return o<=s?{value:`${r??""}${e}`,nextBytes:i}:{value:`${r??""}${fve(e,s)}`,nextBytes:i}}function xnt(r,e){if(!r.rawTextChunks||r.rawTextTruncated)return;let t=1048576-r.rawTextBytes;if(t<=0){r.rawTextChunks.push(ey),r.rawTextTruncated=!0;return}let n=yA(e);if(n<=t){r.rawTextChunks.push(e),r.rawTextBytes+=n;return}r.rawTextChunks.push(fve(e,t)),r.rawTextBytes=1048576,r.rawTextTruncated=!0}function Win(r){return yA(r.text??r.thinking??r.toolInput??"")}function Kin(r){let e=r.inputTokens+r.outputTokens;return{messageId:r.messageId,model:r.model,usage:{inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreationInputTokens:r.cacheCreationInputTokens,cacheReadInputTokens:r.cacheReadInputTokens,totalTokens:e},contentBlocks:r.contentBlocks,stopReason:r.stopReason,stopSequence:r.stopSequence,eventCount:r.eventCount,streamDurationMs:Date.now()-r.startTime,totalBytesReceived:r.totalBytesReceived,events:r.events,...r.streamErrorMessage?{streamErrorMessage:r.streamErrorMessage}:{},...r.rawTextChunks?{rawText:r.rawTextChunks.join("")}:{}}}function Jin(r,e){let t=e.message;if(!t)return;r.messageId=t.id??"",r.model=t.model??"";let n=t.usage;n&&(r.inputTokens+=n.input_tokens??0,r.outputTokens+=n.output_tokens??0,r.cacheCreationInputTokens+=n.cache_creation_input_tokens??0,r.cacheReadInputTokens+=n.cache_read_input_tokens??0)}function Yin(r,e){let t=e.index??0,n=e.content_block;if(!n)return;let o=n.type,s={index:t,type:o};o==="text"?s.text=n.text??"":o==="thinking"?s.thinking=n.thinking??"":o==="tool_use"&&(s.toolName=n.name??"",s.toolId=n.id??"",s.toolInput=""),r.contentBlocks.push(s),r.blockByteCounts.set(t,Win(s))}function Xin(r,e){let t=e.index??0,n=e.delta;if(!n)return;let o=r.contentBlocks.find(a=>a.index===t);if(!o)return;let s=r.blockByteCounts.get(t)??0,i=s>=102400;if(n.type==="text_delta"&&n.text!==null){let a=n.text,c=mve(o.text,a,s,102400);r.blockByteCounts.set(t,c.nextBytes),(!i||!o.text?.endsWith(ey))&&(o.text=c.value)}else if(n.type==="thinking_delta"&&n.thinking!==null){let a=n.thinking,c=mve(o.thinking,a,s,102400);r.blockByteCounts.set(t,c.nextBytes),(!i||!o.thinking?.endsWith(ey))&&(o.thinking=c.value)}else if(n.type==="input_json_delta"&&n.partial_json!==null){let a=n.partial_json,c=mve(o.toolInput,a,s,102400);r.blockByteCounts.set(t,c.nextBytes),(!i||!o.toolInput?.endsWith(ey))&&(o.toolInput=c.value)}}function Zin(r,e){let t=e.delta;t&&(r.stopReason=t.stop_reason??r.stopReason,r.stopSequence=t.stop_sequence??r.stopSequence);let n=e.usage;n&&(r.outputTokens+=n.output_tokens??0)}function bnt(r,e){r.eventCount++;let t=Date.now();if(r.events.length<4999?e.event==="content_block_delta"?r.events.push({type:e.event,timestamp:t,data:""}):r.events.push({type:e.event,timestamp:t,data:pve(e.data,2048)}):r.eventLogTruncated||(r.events.push({type:"truncated",timestamp:t,data:ey}),r.eventLogTruncated=!0),!e.data)return;let n;try{n=JSON.parse(e.data)}catch{return}if(e.event==="error"){let o=n&&typeof n=="object"?n:{},i=(o.error&&typeof o.error=="object"?o.error:void 0)?.message??o.message;r.streamErrorMessage=typeof i=="string"&&i.trim()?pve(i.trim(),2048):pve(e.data,2048)}switch(e.event){case"message_start":Jin(r,n);break;case"content_block_start":Yin(r,n);break;case"content_block_delta":Xin(r,n);break;case"message_delta":Zin(r,n);break;default:break}}function bF(r={}){let e=r.captureRawText??!1,t=Hin(e),n="",o=!1,s=new TextDecoder,i,a=new Promise(x=>{i=x});function c(){o||(o=!0,i(Kin(t)))}let l=new TransformStream({transform(x,b){b.enqueue(x),t.totalBytesReceived+=x.byteLength;let T=s.decode(x,{stream:!0});xnt(t,T),n+=T;let{events:S,remainder:E}=xF(n);n=E;for(let C of S)bnt(t,C)},flush(){let x=s.decode();if(x&&(xnt(t,x),n+=x),n.trim()){let{events:b}=xF(n+`
|
|
2468
2468
|
|
|
2469
|
-
`);for(let T of b)bnt(t,T)}c()}}),u=l.writable.getWriter(),d,p=new WritableStream({start(x){d=x},write(x){return u.write(x)},close(){return u.close()},abort(x){return c(),u.abort(x)}});u.closed.catch(x=>{c();try{d.error(x)}catch{}});let f=l.readable.getReader();return{stream:{readable:new ReadableStream({async pull(x){try{let{done:b,value:T}=await f.read();b?x.close():x.enqueue(T)}catch(b){x.error(b)}},async cancel(x){c();try{d.error(x)}catch{}await Promise.allSettled([f.cancel(x),u.abort(x)])}}),writable:p},telemetry:a}}var Qin=64*1024,ean=32;function vnt(r){try{let e=JSON.parse(r);return{errorType:e.error?.type??e.type??"stream_error",message:e.error?.message??e.message??"Upstream SSE error"}}catch{return{errorType:"stream_error",message:r.trim()||"Upstream SSE error"}}}function Tnt(r){if(r.event==="error")return!0;try{let e=JSON.parse(r.data);return e.type==="error"||e.error!==void 0}catch{return!1}}async function Snt(r){let e=new TextDecoder,t=[],n="",o=0;for(;o<Qin&&t.length<ean;){let s;try{s=await r.read()}catch(a){return{kind:"transport_error",chunks:t,error:a}}if(s.done){n+=e.decode();let{events:a}=xF(n),c=a.find(Tnt);return c?{kind:"sse_error",chunks:t,...vnt(c.data)}:t.length>0?{kind:"ready",chunks:t}:{kind:"empty",chunks:t}}if(!s.value||s.value.length===0)continue;t.push(s.value),o+=s.value.byteLength,n+=e.decode(s.value,{stream:!0});let i=xF(n);n=i.remainder;for(let a of i.events){if(Tnt(a))return{kind:"sse_error",chunks:t,...vnt(a.data)};if(a.event!=="ping"&&(a.event||a.data))return{kind:"ready",chunks:t}}}return t.length>0?{kind:"ready",chunks:t}:{kind:"empty",chunks:t}}function gve(){let r=!1,e,t=new Promise(o=>{e=o}),n=o=>{r||(r=!0,e(o))};return{outcome:t,complete:()=>n({kind:"completed"}),fail:o=>n({kind:"upstream_error",message:o}),cancel:()=>n({kind:"client_cancelled"})}}function vF(r,e){return r.kind==="completed"&&e?{kind:"upstream_error",message:e}:r}J();OJ();BD();cs();ln();var ian=300*1e3,aan=6e4,xve=2e3,Gf=new Map;function bve(r){return!!(r.expiresAt&&r.expiresAt<=Date.now()+ian&&r.refreshToken)}function knt(r){return r===400||r===401||r===403||r===404}function pw(r){return knt(r.status)}async function can(r){if(!r.refreshToken)return{success:!1,error:"No refresh token available"};let e=new URLSearchParams({grant_type:"refresh_token",refresh_token:r.refreshToken,client_id:J3}).toString(),t={"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json","User-Agent":Jx},n=[cC,Z4e],o;for(let s of n)try{let i=await fetch(s,{method:"POST",headers:t,body:e,signal:AbortSignal.timeout(1e4)});if(!i.ok){let c=await i.text();g.warn(`[token-refresh] failed for ${r.label} at ${xi(s)}`,{status:i.status,error:c.slice(0,500)});let l={success:!1,error:c,status:i.status};if(knt(i.status)&&(o=l),s===cC)continue;return o??l}let a=await i.json();return r.token=a.access_token,r.expiresAt=a.expires_in!==void 0?Date.now()+a.expires_in*1e3:Date.now()+3300*1e3,a.refresh_token&&(r.refreshToken=a.refresh_token),g.debug(`[token-refresh] refreshed for ${r.label}`),{success:!0}}catch(i){if(g.warn(`[token-refresh] exception for ${r.label} at ${xi(s)}`,{error:String(i)}),s===cC)continue;return o??{success:!1,error:String(i)}}return o??{success:!1,error:"No refresh URLs available"}}async function vve(r){if(!r.refreshToken)return{success:!1,error:"No refresh token available"};let e=r.refreshToken,t=Gf.get(e);if(!t){let o={...r},s=can(o).then(i=>{let a={result:i,token:o.token,refreshToken:o.refreshToken,expiresAt:o.expiresAt};if(i.success){let c=new Set([e]),l=o.refreshToken;l&&l!==e&&!Gf.has(l)&&(Gf.set(l,s),c.add(l)),setTimeout(()=>{for(let d of c)Gf.get(d)===s&&Gf.delete(d)},aan).unref?.()}else Gf.get(e)===s&&Gf.delete(e);return a},i=>{throw Gf.get(e)===s&&Gf.delete(e),i});Gf.set(e,s),t=s}let n=await t;return n.result.success&&(r.token=n.token,r.refreshToken=n.refreshToken,r.expiresAt=n.expiresAt),n.result}async function _nt(r,e){if(!e||typeof e=="string"||!("providerKey"in e))return!1;let t;try{t=await kt(xA.peekTokens(e.providerKey),xve,"[token-refresh] peekTokens reconciliation timed out")}catch(n){return g.debug("[token-refresh] skipping persisted-state reconciliation (peek failed)",{error:n instanceof Error?n.message:String(n)}),!1}return!t||t.expiresAt<=(r.expiresAt??0)||t.accessToken===r.token&&t.refreshToken===r.refreshToken&&t.expiresAt===r.expiresAt?!1:(r.token=t.accessToken,r.refreshToken=t.refreshToken,r.expiresAt=t.expiresAt,!0)}async function NJ(r,e){if(await _nt(r,e)&&!bve(r))return{success:!0};let n=await vve(r);return n.success?n:await _nt(r,e)?{success:!0}:n}async function DJ(r,e){if(typeof r!="string"&&"providerKey"in r){await uan(r.providerKey,e);return}let t=typeof r=="string"?r:r.credPath;await lan(t,e)}async function lan(r,e){try{let t=await Promise.resolve().then(()=>(Nu(),wg)),n=JSON.parse(await t.readFile(r,"utf8"));n.oauth={...n.oauth,accessToken:e.token,expiresAt:e.expiresAt,refreshToken:e.refreshToken},n.updatedAt=Date.now(),await ep(r,n,384)}catch(t){g.warn("[token-refresh] Failed to persist legacy credentials",{error:t instanceof Error?t.message:String(t)})}}async function uan(r,e){try{let t=await kt(xA.peekTokens(r),xve,"[token-refresh] peekTokens for persistence timed out"),n={accessToken:e.token,refreshToken:e.refreshToken??t?.refreshToken,expiresAt:e.expiresAt??t?.expiresAt??Date.now()+3300*1e3,tokenType:t?.tokenType??"Bearer",...t?.scope?{scope:t.scope}:{}};await kt(xA.saveTokens(r,n),xve,"[token-refresh] saveTokens timed out")}catch(t){g.warn("[token-refresh] Failed to persist TokenStore credentials",{error:t instanceof Error?t.message:String(t)})}}function dan(r){let e=r.toLowerCase();return e.includes("opus")?"opus":e.includes("sonnet")?"sonnet":e.includes("haiku")?"haiku":"other"}function bA(r,e,t,n){let o=[{provider:r.provider,model:r.model,label:`${r.provider}/${r.model??"unknown"}`}];for(let s of e)s.provider===r.provider&&s.model===r.model||o.push({provider:s.provider,model:s.model,label:`${s.provider}/${s.model}`});return(e.length===0||o.length===1)&&o.push({label:"auto-provider"}),{requestedModel:t,modelTier:dan(t),attempts:o,skipped:[]}}function LJ(r){if(!r)return 0;let e=parseInt(r,10);if(!Number.isNaN(e))return Math.max(1,e)*1e3;let t=new Date(r);return Number.isNaN(t.getTime())?0:Math.max(1e3,t.getTime()-Date.now())}J();cs();pb();var jJ=new Set(["cookie","proxy-authorization","host","connection","content-length","transfer-encoding"]),wve="proxy/internal",Eve="internal",Nb=0,Cnt=0,TF=5,FJ=2,_ve=[250,1e3],Tve=1,UJ=120*1e3,kve=2,Rnt=3e4,pan=11520*60*1e3,Dnt=5e3,man=900*1e3,Lnt=900*1e3,fan=3e4,gan=300*1e3,Rve=900*1e3,SF=new Map,Ant=new Map,Int=new Map,Pnt=!1,Sve=6e4,han=9e4,yan=12e4,xan=250,ban=15e3;function vA(r,e,t){e<=1||r===t&&(Nb=(Nb+1)%e)}function Fnt(r,e){if(!e)return 0;let t=r.findIndex(n=>jrt(n.key,e));return t>=0?t:0}function van(r,e){if(r.length<=1)return;let t=Fnt(r,e);if(Nb===t)return;let n=r[t],o=SF.get(n.key);if((!o||!o.coolingUntil||Date.now()>=o.coolingUntil)&&(Nb=t,o?.coolingUntil)){let s=o.coolingUntil;o.coolingUntil=void 0,o.coolingReason=void 0,mJ(n.key,s).catch(()=>{}),g.always(`[proxy] home primary account=${n.label} cooling expired, resetting primaryAccountIndex to ${t}`)}}function Unt(r){let e=SF.get(r);return!!e?.coolingUntil&&Date.now()<e.coolingUntil}function Tan(r,e,t=Date.now()){let n=Ant.get(r);if(!n||t>=n.coolingUntil?(n={coolingUntil:e,retriesClaimed:0},Ant.set(r,n)):e>n.coolingUntil&&(n.coolingUntil=e),!(n.retriesClaimed>=kve))return n.retriesClaimed+=1,n.retriesClaimed}function San(r,e,t=Date.now()){if(e<=t)return 0;if(e-t>han)return;let n=Int.get(r);!n||t>=n.coolingUntil?(n={coolingUntil:e,nextAdmissionAt:e},Int.set(r,n)):e>n.coolingUntil&&(n.coolingUntil=e,n.nextAdmissionAt=Math.max(n.nextAdmissionAt,e));let o=Math.max(t,n.coolingUntil,n.nextAdmissionAt);if(!(o-n.coolingUntil>ban))return n.nextAdmissionAt=o+xan,o-t}async function wan(r){let e=Date.now()+yan;for(;Date.now()<e;){let t=r.filter(i=>!Unt(i.key));if(t.length>0)return t;let n=Date.now(),o=r.map(i=>({account:i,state:Vf(i.key)})).filter(({state:i})=>i.coolingReason==="transient"&&i.coolingUntil!==void 0&&i.coolingUntil>n).sort((i,a)=>(i.state.coolingUntil??Number.POSITIVE_INFINITY)-(a.state.coolingUntil??Number.POSITIVE_INFINITY))[0];if(!o?.state.coolingUntil)return[];let s=San(o.account.key,o.state.coolingUntil,n);if(s===void 0||n+s>e)return[];g.always(`[proxy] all usable accounts are transiently cooling; queueing request for account=${o.account.label} in ${s}ms`),await TA(s)}return[]}function SA(r,e){if(!r||r<=0)return;let t=r>4102444800?r:r*1e3;return t>e?t:void 0}function BJ(r,e){return Math.min(Math.max(r,e+Dnt),e+pan)}function Ave(r,e,t,n=r?.unifiedStatus){if(r&&r.weeklyStatus==="rejected"){let s=SA(r.weeklyResetAt,t)??(e>0?t+e:t+Sve);return{reason:"weekly",coolingUntil:BJ(s,t),rotateImmediately:!0}}if(r&&r.sessionStatus==="rejected"){let s=SA(r.sessionResetAt,t)??(e>0?t+e:t+Sve);return{reason:"session",coolingUntil:BJ(s,t),rotateImmediately:!0}}if(n?.trim().toLowerCase()==="rejected"){let s=e>0?t+e:t+Lnt;return{reason:"unified",coolingUntil:BJ(s,t),rotateImmediately:!0}}let o=e>0?e:Sve;return{reason:"transient",coolingUntil:t+Math.max(Dnt,Math.min(o,man)),rotateImmediately:!1}}function Ive(r,e){return Math.max(0,Math.round((r-e)/6e4))}function $nt(r,e,t){let n,o;if(e.weeklyStatus==="rejected"?(n=SA(e.weeklyResetAt,t),o="weekly"):e.sessionStatus==="rejected"?(n=SA(e.sessionResetAt,t),o="session"):e.unifiedStatus==="rejected"&&(n=t+Lnt,o="unified"),n===void 0)return!1;let s=BJ(n,t);return!r.coolingUntil||s>r.coolingUntil?(r.coolingUntil=s,r.coolingReason=o,g.always(`[proxy] proactively cooling account (${o}) ~${Ive(s,t)}m from success-response quota (status rejected)`),!0):!1}async function Ean(r){try{let[e,t]=await Promise.all([Hrt(),pJ()]),n=Date.now();for(let o of r){let s=Vf(o.key);!s.quota&&e[o.label]&&(s.quota=e[o.label]);let i=t[o.key];i?.coolingUntil>n&&(!s.coolingUntil||i.coolingUntil>s.coolingUntil)&&(s.coolingUntil=i.coolingUntil,s.coolingReason=i.reason)}}catch{}}function Pve(){let r=(process.env.NEUROLINK_PROXY_QUOTA_ROUTING??"").toLowerCase();return r!=="off"&&r!=="false"&&r!=="0"}function Mve(){let r=Number(process.env.NEUROLINK_PROXY_SESSION_SOFT_LIMIT??"");return Number.isFinite(r)&&r>0&&r<=1?r:.97}function Ove(){let r=Number(process.env.NEUROLINK_PROXY_SESSION_RESET_TOLERANCE_MS??"");return Number.isInteger(r)&&r>0?r:900*1e3}function Bnt(r,e,t,n){let o=SF.get(r),s=o?.quota,i=!!o?.coolingUntil&&e<o.coolingUntil,a=SA(s?.weeklyResetAt,e),c=SA(s?.sessionResetAt,e),l=c!==void 0,u=a!==void 0,d=s?l?s.sessionUsed??0:0:null,p=s?u?s.weeklyUsed??null:0:null,f=s?l?s.sessionStatus??"unknown":"allowed":null,h=s?u?s.weeklyStatus??"unknown":"allowed":null,y=f==="throttled"||l&&(d??0)>=t,x=s&&Number.isFinite(s.lastUpdated)?s.lastUpdated:null;return{usable:!i&&h!=="rejected"&&f!=="rejected",saturated:y,hasQuota:!!s,quotaLastUpdated:x,quotaAgeMs:x===null?null:Math.max(0,e-x),coolingActive:i,coolingReason:o?.coolingReason??null,coolingUntil:o?.coolingUntil??0,unifiedStatus:s?.unifiedStatus??null,overageStatus:s?.overageStatus??null,sessionStatus:f,sessionUsed:d,sessionResetBucket:l?Math.floor(c/n):Number.POSITIVE_INFINITY,sessionReset:c??Number.POSITIVE_INFINITY,weeklyStatus:h,weeklyReset:a??Number.POSITIVE_INFINITY,weeklyUsed:p,weeklyUsedForSort:p??-1}}function znt(r,e,t,n){let o=t.get(r.key),s=t.get(e.key);if(!o||!s)return[0,"insertion_order"];if(o.usable!==s.usable)return[o.usable?-1:1,"availability"];if(!o.usable&&!s.usable){let i=o.coolingUntil||Number.POSITIVE_INFINITY,a=s.coolingUntil||Number.POSITIVE_INFINITY;return[i===a?0:i-a,i===a?"insertion_order":"cooldown_recovery"]}if(o.hasQuota!==s.hasQuota)return[o.hasQuota?1:-1,"quota_probe"];if(o.saturated!==s.saturated)return[o.saturated?1:-1,"session_headroom"];if(o.saturated&&s.saturated){if(o.sessionResetBucket!==s.sessionResetBucket)return[o.sessionResetBucket-s.sessionResetBucket,"session_reset"];if(o.weeklyReset!==s.weeklyReset)return[o.weeklyReset-s.weeklyReset,"weekly_reset"]}else{if(o.weeklyReset!==s.weeklyReset)return[o.weeklyReset-s.weeklyReset,"weekly_reset"];if(o.sessionResetBucket!==s.sessionResetBucket)return[o.sessionResetBucket-s.sessionResetBucket,"session_reset"]}return o.weeklyUsedForSort!==s.weeklyUsedForSort?[s.weeklyUsedForSort-o.weeklyUsedForSort,"weekly_utilization"]:n&&r.key===n!=(e.key===n)?[r.key===n?-1:1,"configured_primary"]:[0,"insertion_order"]}function _an(r,e,t,n,o){let s=new Map(r.map(i=>[i.key,Bnt(i.key,e,n,o)]));return{orderedAccounts:[...r].sort((i,a)=>znt(i,a,s,t)[0]),metricsByKey:s}}function kan(r){let{accounts:e,orderedAccounts:t,metricsByKey:n,evaluatedAt:o,strategy:s,primaryKey:i,quotaRoutingEnabled:a,quotaOrdered:c,sessionSoftLimit:l,sessionResetToleranceMs:u,rotationOffset:d}=r,p=new Map(e.map((T,S)=>[T.key,S])),f=!!i&&e.some(T=>T.key===i),h=t.map((T,S)=>{let E=n.get(T.key);if(!E)throw new Error(`Missing precomputed routing metrics for account ${T.label}`);return{account:T.label,accountType:T.type,sourceIndex:p.get(T.key)??S,rank:S,configuredPrimary:!!i&&T.key===i,usable:E.usable,saturated:E.saturated,quotaObserved:E.hasQuota,quotaLastUpdated:E.quotaLastUpdated,quotaAgeMs:E.quotaAgeMs,coolingActive:E.coolingActive,coolingReason:E.coolingReason,coolingUntil:E.coolingUntil>0&&Number.isFinite(E.coolingUntil)?E.coolingUntil:null,unifiedStatus:E.unifiedStatus,overageStatus:E.overageStatus,sessionStatus:E.sessionStatus,sessionUsed:E.sessionUsed,sessionResetAt:Number.isFinite(E.sessionReset)?E.sessionReset:null,sessionResetBucket:Number.isFinite(E.sessionResetBucket)?E.sessionResetBucket:null,weeklyStatus:E.weeklyStatus,weeklyUsed:E.weeklyUsed,weeklyResetAt:Number.isFinite(E.weeklyReset)?E.weeklyReset:null}}),y=t[0],x,b;return t.length===1?(x="single_account",b="single_account"):c?(x="quota",b=znt(t[0],t[1],n,i)[1]):s==="round-robin"?(x="round_robin",b="round_robin"):(x="primary",b=f&&y?.key===i?"configured_primary":"insertion_order"),{schemaVersion:1,evaluatedAt:new Date(o).toISOString(),strategy:s,mode:x,selectionReason:b,quotaRoutingEnabled:a,quotaInputsUsed:c,sessionSoftLimit:l,sessionResetToleranceMs:u,configuredPrimaryAccount:i??null,configuredPrimaryMatched:f,rotationOffset:d,initialAccount:y?.label??"",candidates:h}}function Can(r){let{enabledAccounts:e,accountStrategy:t,primaryAccountKey:n,quotaRoutingEnabled:o,sessionSoftLimit:s,sessionResetToleranceMs:i,setRoutingDecision:a}=r,c=[...e],l=Date.now(),u,d=0,p=t==="fill-first"&&c.length>1&&o;if(!p&&t==="fill-first"&&van(e,n),p){let f=_an(e,l,n,s,i);c=f.orderedAccounts,u=f.metricsByKey,g.shouldLog("debug")&&g.debug(`[proxy] quota-ordered fill sequence: ${c.map(h=>h.label).join(" \u2192 ")}`)}else{if(t==="round-robin"&&c.length!==Cnt&&(Nb=Fnt(c,n),Cnt=c.length),c.length>1&&(d=Nb%c.length,t==="round-robin"&&(Nb=(Nb+1)%c.length),d>0)){let f=c.splice(0,d);c.push(...f)}u=new Map(e.map(f=>[f.key,Bnt(f.key,l,s,i)]))}return a(kan({accounts:e,orderedAccounts:c,metricsByKey:u,evaluatedAt:l,strategy:t,primaryKey:n,quotaRoutingEnabled:o,quotaOrdered:p,sessionSoftLimit:s,sessionResetToleranceMs:i,rotationOffset:d})),c}var zJ=new Map,Ran=300*1e3,Aan=new Set(["accept","accept-encoding","accept-language","anthropic-beta","anthropic-dangerous-direct-browser-access","anthropic-version","sec-fetch-mode","user-agent","x-app","x-stainless-arch","x-stainless-lang","x-stainless-os","x-stainless-package-version","x-stainless-retry-count","x-stainless-runtime","x-stainless-runtime-version","x-stainless-timeout","x-subscription-tier"]),Ian=["oauth-2025-04-20","claude-code-20250219","fine-grained-tool-streaming-2025-05-14"];function GJ(r){return r.replace(/[^a-zA-Z0-9._@-]/g,"_")}function jnt(r){return Xt(xH(),".neurolink","header-snapshots",`anthropic_${GJ(r)}.json`)}function Pan(r,e){if(e?.headers)for(let[t,n]of Object.entries(e.headers)){let o=t.toLowerCase();typeof n=="string"&&!r[o]&&!jJ.has(o)&&o!=="authorization"&&o!=="x-api-key"&&o!=="x-claude-code-session-id"&&(r[o]=n)}}async function Man(r){try{let e=GJ(r),t=zJ.get(e);if(t&&Date.now()-t.loadedAt<Ran)return t.snapshot;let n=jnt(r);try{await vM(n)}catch{return null}let o=JSON.parse(await Bn(n,"utf8"));if(!o||typeof o!="object")return null;let s={accountKey:"accountKey"in o&&typeof o.accountKey=="string"?o.accountKey:`anthropic:${r}`,capturedAt:"capturedAt"in o&&typeof o.capturedAt=="string"?o.capturedAt:new Date(0).toISOString(),source:"claude-code",headers:"headers"in o&&o.headers?o.headers:{},...o.body?{body:o.body}:{}};return Object.keys(s.headers).length===0&&Object.keys(s.body??{}).length===0?null:(zJ.set(e,{snapshot:s,loadedAt:Date.now()}),s)}catch{return null}}function Oan(r,e){let t={...e??{}};for(let[n,o]of Object.entries(r)){let s=n.toLowerCase();typeof o=="string"&&Aan.has(s)&&!jJ.has(s)&&s!=="authorization"&&s!=="x-api-key"&&s!=="x-claude-code-session-id"&&(t[s]=o)}return t}function Gnt(r){if(!r||typeof r!="object")return;let e=r,t=sde(e.metadata?.user_id),n=Array.isArray(e.system)?e.system:typeof e.system=="string"?[{type:"text",text:e.system}]:[],o=n.find(i=>typeof i?.text=="string"&&i.text.includes("x-anthropic-billing-header"))?.text,s=n.find(i=>typeof i?.text=="string"&&i.text.includes("Claude Agent SDK"))?.text;if(!(!t&&!o&&!s))return{...t?{metadataUserId:t.metadataUserId}:{},...t?{sessionId:t.sessionId}:{},...o?{billingHeader:o}:{},...s?{agentBlock:s}:{}}}function Vnt(r,e){return typeof r["x-claude-code-session-id"]=="string"||r["user-agent"]?.startsWith("claude-cli/")||!!e?.metadataUserId||!!e?.billingHeader||!!e?.agentBlock}function Nan(r,e){return r?JSON.stringify(r.headers??{})===JSON.stringify(e.headers??{})&&JSON.stringify(r.body??{})===JSON.stringify(e.body??{}):!1}async function Dan(r,e){let t=jnt(r);await ep(t,e,384),zJ.set(GJ(r),{snapshot:e,loadedAt:Date.now()})}async function Lan(r,e,t,n){let o=await Man(r),s;try{s=JSON.parse(n)}catch{return o}let i=Gnt(s);if(!Vnt(t,i))return o;let a={accountKey:e,capturedAt:new Date().toISOString(),source:"claude-code",headers:Oan(t,o?.headers),body:{...o?.body??{},...i??{},...typeof t["x-claude-code-session-id"]=="string"?{sessionId:t["x-claude-code-session-id"]}:{}}};if(Nan(o,a))return o;try{await Dan(r,a)}catch(c){g.warn("[proxy] failed to persist Claude snapshot",{accountLabel:r,error:c instanceof Error?c.message:String(c)}),zJ.set(GJ(r),{snapshot:a,loadedAt:Date.now()})}return a}function Nve(r){let e={};if(!r||typeof r!="object")return e;let t=r;if(typeof t.model=="string"&&(e.responseModel=t.model),typeof t.stop_reason=="string"&&(e.finishReason=t.stop_reason),typeof t.stop_sequence=="string"&&(e.stopSequence=t.stop_sequence),Array.isArray(t.content)){let n=t.content.filter(o=>!!o&&typeof o=="object"&&o.type==="tool_use").map(o=>String(o.name??"")).filter(o=>o.length>0);n.length>0&&(e.toolCalls=n)}return e}function qnt(r){let e={};r.model&&(e.responseModel=r.model),r.stopReason&&(e.finishReason=r.stopReason),r.stopSequence&&(e.stopSequence=r.stopSequence);let t=(r.contentBlocks??[]).filter(n=>n.type==="tool_use").map(n=>String(n.toolName??"")).filter(n=>n.length>0);return t.length>0&&(e.toolCalls=t),e}function Fan(r,e,t,n,o){try{let s=JSON.parse(r),i={type:"text",text:t?.body?.agentBlock||"You are a Claude agent, built on Anthropic's Claude Agent SDK."};if(s.system){if(typeof s.system=="string"&&(s.system=[{type:"text",text:s.system}]),Array.isArray(s.system)){let l=s.system.findIndex(f=>typeof f.text=="string"&&f.text.includes("x-anthropic-billing-header")),u=s.system.findIndex(f=>typeof f.text=="string"&&f.text.includes("Claude Agent SDK")),d={type:"text",text:lC(s.system[l]?.text??t?.body?.billingHeader)};if(n&&u>=0)l<0&&s.system.unshift(d);else{let f=[l,u].filter(h=>h>=0).sort((h,y)=>y-h);for(let h of f)s.system.splice(h,1);s.system.length>0&&Q3(s,s.system),s.system=[d,i]}}}else{let l={type:"text",text:lC(t?.body?.billingHeader)};s.system=[l,i]}let a=e.substring(0,Math.min(20,e.length)),c=Y3(a,{existingUserId:s.metadata?.user_id??t?.body?.metadataUserId,preferredSessionId:o??t?.body?.sessionId});return s.metadata={...s.metadata,user_id:c.metadataUserId},{bodyStr:JSON.stringify(s),sessionId:c.sessionId}}catch{return{bodyStr:r}}}async function Uan(r,e){if(!r.oauth?.accessToken)return;let t=r.oauth.accessToken,n=r.oauth.refreshToken,o=r.oauth.expiresAt,s=r.email?.trim()||"legacy-default",i=o?o<Date.now():!1,a=()=>({key:oF,label:s,token:t,refreshToken:n,expiresAt:o,type:"oauth",persistTarget:{credPath:e}});if(!i)return a();let c=Vf(oF);if(c.permanentlyDisabled)return;let l=(await pJ())[oF];if(l?.coolingUntil>Date.now()&&(!c.coolingUntil||l.coolingUntil>c.coolingUntil)&&(c.coolingUntil=l.coolingUntil,c.coolingReason=l.reason),c.coolingReason==="auth"&&c.coolingUntil&&c.coolingUntil>Date.now())return a();if(!n){g.always("[proxy] skipping legacy account (expired, no refresh token)"),await mw(a(),c,"missing_refresh_token");return}let u={token:t,refreshToken:n,expiresAt:o,label:s},d=await vve(u);if(!d.success){if(pw(d)){await mw(a(),c,"refresh_invalid");return}let p=await VJ(a(),c);return g.always(`[proxy] legacy refresh temporarily unavailable (${d.status??"network"}); cooling until ${new Date(p).toISOString()}`),a()}return t=u.token,n=u.refreshToken,o=u.expiresAt,await DJ(e,u),await qJ(a(),c),g.always("[proxy] refreshed legacy account at startup"),a()}async function $an(r){let{ctx:e,body:t,route:n,modelRouter:o,tracer:s,requestStartTime:i,logProxyBody:a}=r;s?.setMode("full");let c=hJ(t),l=bA({provider:n.provider,model:n.model},o?.getFallbackChain()??[],t.model,c);Hnt(a,"translated_request",l);let u=l.attempts;if(t.stream)return AJ({ctx:e,format:"claude",requestModel:t.model,parsed:c,attempts:u,tracer:s,requestStartTime:i});try{return await IJ({ctx:e,format:"claude",requestModel:t.model,parsed:c,attempts:u,tracer:s,requestStartTime:i,terminalFailureStatus:502})}catch(d){let p=d instanceof Error?d.message:"unknown error";g.error(`[claude-proxy] Translated generation failed for ${t.model}: ${p}`);let f=ld(502,`Generation failed: ${p}`),h=JSON.stringify(f);return a({phase:"client_response",headers:{"content-type":"application/json"},body:h,bodySize:Buffer.byteLength(h,"utf8"),contentType:"application/json",account:"translation",accountType:"translation",responseStatus:502,durationMs:Date.now()-i}),f}}function Hnt(r,e,t){r({phase:"routing_decision",contentType:"application/json",body:{stage:e,attempts:t.attempts}})}async function Ban(r){let{ctx:e,body:t,clientRequestBody:n,tracer:o,requestStartTime:s,logProxyBody:i,logFinalRequest:a}=r;o?.setMode("passthrough-cli");let c=n,l=Array.isArray(t.tools)?t.tools.length:0,u={};for(let[h,y]of Object.entries(e.headers))!jJ.has(h.toLowerCase())&&y&&(u[h]=y);u["content-type"]||(u["content-type"]="application/json");let d=o?.startUpstreamAttempt({account:"passthrough",attempt:1,polyfillHeaders:!1,polyfillBody:!1,upstreamUrl:"https://api.anthropic.com/v1/messages?beta=true"});o?.logUpstreamRequestHeaders(u),o?.logUpstreamRequestBody(c),i({phase:"upstream_request",headers:u,body:c,bodySize:Buffer.byteLength(c,"utf8"),contentType:u["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,metadata:{upstreamMethod:"POST",upstreamUrl:"https://api.anthropic.com/v1/messages?beta=true"}}),uw("passthrough","passthrough");let p;try{p=await fetch("https://api.anthropic.com/v1/messages?beta=true",{method:"POST",headers:u,body:c,signal:AbortSignal.timeout(Rve)})}catch(h){let y=h instanceof Error?h.message:String(h);ao("passthrough","passthrough",502),o?.setError("network_error",y),d?.end(),o?.end(502,Date.now()-s),a(502,"passthrough","passthrough","network_error",y);let x=ld(502,`Passthrough fetch failed: ${y}`),b=JSON.stringify(x);return i({phase:"client_response",headers:{"content-type":"application/json"},body:b,bodySize:Buffer.byteLength(b,"utf8"),contentType:"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:502,durationMs:Date.now()-s}),x}let f={};if(p.headers.forEach((h,y)=>{f[y]=h}),o?.logUpstreamResponseHeaders(f),!p.ok){let h=await p.text();ao("passthrough","passthrough",p.status,p.status===429?"quota":void 0),o?.logUpstreamResponseBody(h),i({phase:"upstream_response",headers:f,body:h,bodySize:Buffer.byteLength(h,"utf8"),contentType:f["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:p.status,durationMs:Date.now()-s}),i({phase:"client_response",headers:f,body:h,bodySize:Buffer.byteLength(h,"utf8"),contentType:f["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:p.status,durationMs:Date.now()-s}),d?.end(),o?.setError("api_error",h.slice(0,500)),o?.end(p.status,Date.now()-s),a(p.status,"passthrough","passthrough",p.status===429?"rate_limit_error":"api_error",h);try{return JSON.parse(h)}catch{return ld(p.status,h)}}return t.stream&&p.body?jan({ctx:e,body:t,bodyStr:c,response:p,tracer:o,requestStartTime:s,toolCount:l,upstreamSpan:d,upstreamResponseHeaders:f,logProxyBody:i,logFinalRequest:a}):Gan({ctx:e,body:t,bodyStr:c,response:p,tracer:o,requestStartTime:s,toolCount:l,upstreamSpan:d,upstreamResponseHeaders:f,logProxyBody:i,logFinalRequest:a})}function zan(r){let e=r.getReader(),t=gve(),n=!1;return{stream:new ReadableStream({async pull(s){if(!n)try{let{done:i,value:a}=await e.read();if(n)return;if(i){n=!0,t.complete(),s.close();return}s.enqueue(a)}catch(i){n=!0;let a=i instanceof Error?i.message:String(i);t.fail(a),s.error(i)}},cancel(s){return n=!0,t.cancel(),e.cancel(s)}}),outcome:t.outcome}}async function jan(r){let{bodyStr:e,response:t,tracer:n,requestStartTime:o,upstreamSpan:s,upstreamResponseHeaders:i,logProxyBody:a,logFinalRequest:c}=r,l={...i},{stream:u,capture:d}=dve(),p=t.body;if(!p)throw ao("passthrough","passthrough",502),new Error("Expected passthrough stream response body");let f=zan(p),h=f.stream,y=!1,x=(T,S,E,C)=>y?!1:(y=!0,S==="stream_error"&&ao("passthrough","passthrough",T),c(T,"passthrough","passthrough",S,E,C),!0);if(n)try{let{stream:T,telemetry:S}=bF({captureRawText:!0});h=h.pipeThrough(T);let E=n,C=s,R=t,P=e.length;Promise.all([S,d,f.outcome]).then(([A,I,M])=>{let O=vF(M,A.streamErrorMessage),F=Db(O);E.setUsage({inputTokens:A.usage.inputTokens,outputTokens:A.usage.outputTokens,cacheCreationTokens:A.usage.cacheCreationInputTokens,cacheReadTokens:A.usage.cacheReadInputTokens}),E.logStreamEvents(A.events),E.setResponseInfo(qnt(A));let N=parseFloat(R.headers.get("anthropic-ratelimit-unified-5h-utilization")??""),z=parseFloat(R.headers.get("anthropic-ratelimit-unified-7d-utilization")??""),$={inputTokens:A.usage.inputTokens,outputTokens:A.usage.outputTokens,cacheCreationTokens:A.usage.cacheCreationInputTokens,cacheReadTokens:A.usage.cacheReadInputTokens};isNaN(N)||($.rateLimitAfter5h=N),isNaN(z)||($.rateLimitAfter7d=z),(!isNaN(N)||!isNaN(z))&&E.setUsage($),E.logUpstreamResponseBody(A.rawText??""),E.recordMetrics(),E.recordBodySizes(P,A.totalBytesReceived),C?.end(),F&&E.setError(F.errorType,F.message),E.end(F?.status??t.status,Date.now()-o),x(F?.status??t.status,F?.errorType,F?.message,{inputTokens:A.usage.inputTokens,outputTokens:A.usage.outputTokens,cacheCreationTokens:A.usage.cacheCreationInputTokens,cacheReadTokens:A.usage.cacheReadInputTokens}),a({phase:"upstream_response",headers:l,body:A.rawText??"",bodySize:A.totalBytesReceived,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:200,durationMs:Date.now()-o}),a({phase:"client_response",headers:l,body:I.text,bodySize:I.totalBytes,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:200,durationMs:Date.now()-o})}).catch(A=>{if(y)return;let I=A instanceof Error?A.message:String(A);E.setError("stream_telemetry_error",I),C?.end(),E.end(500,Date.now()-o),x(500,"stream_telemetry_error",I)})}catch{f.outcome.then(T=>{let S=Db(T);s?.end(),S&&n.setError(S.errorType,S.message),n.end(S?.status??t.status,Date.now()-o),x(S?.status??t.status,S?.errorType,S?.message)})}else try{let{stream:T,telemetry:S}=bF({captureRawText:!0});h=h.pipeThrough(T),Promise.all([S,d,f.outcome]).then(([E,C,R])=>{let P=vF(R,E.streamErrorMessage),A=Db(P);x(A?.status??t.status,A?.errorType,A?.message,{inputTokens:E.usage.inputTokens,outputTokens:E.usage.outputTokens,cacheCreationTokens:E.usage.cacheCreationInputTokens,cacheReadTokens:E.usage.cacheReadInputTokens}),a({phase:"upstream_response",headers:l,body:E.rawText??"",bodySize:E.totalBytesReceived,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o}),a({phase:"client_response",headers:l,body:C.text,bodySize:C.totalBytes,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o})}).catch(E=>{y||x(500,"stream_telemetry_error",E instanceof Error?E.message:String(E))})}catch{f.outcome.then(T=>{let S=Db(T);x(S?.status??t.status,S?.errorType,S?.message)})}let b=h.pipeThrough(u);return new Response(b,{status:t.status,headers:l})}async function Gan(r){let{bodyStr:e,response:t,tracer:n,requestStartTime:o,upstreamSpan:s,upstreamResponseHeaders:i,logProxyBody:a,logFinalRequest:c}=r,l=await t.text();n?.logUpstreamResponseBody(l),a({phase:"upstream_response",headers:i,body:l,bodySize:Buffer.byteLength(l,"utf8"),contentType:i["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o}),a({phase:"client_response",headers:i,body:l,bodySize:Buffer.byteLength(l,"utf8"),contentType:i["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o});let u=JSON.parse(l);if(n&&u&&typeof u=="object"){let d=u.usage;if(d){n.setUsage({inputTokens:d.input_tokens??0,outputTokens:d.output_tokens??0,cacheCreationTokens:d.cache_creation_input_tokens??0,cacheReadTokens:d.cache_read_input_tokens??0});let f=parseFloat(t.headers.get("anthropic-ratelimit-unified-5h-utilization")??""),h=parseFloat(t.headers.get("anthropic-ratelimit-unified-7d-utilization")??"");if(!isNaN(f)||!isNaN(h)){let y={inputTokens:d.input_tokens??0,outputTokens:d.output_tokens??0,cacheCreationTokens:d.cache_creation_input_tokens??0,cacheReadTokens:d.cache_read_input_tokens??0};isNaN(f)||(y.rateLimitAfter5h=f),isNaN(h)||(y.rateLimitAfter7d=h),n.setUsage(y)}}n.setResponseInfo(Nve(u)),n.recordMetrics();let p=JSON.stringify(u);n.recordBodySizes(e.length,p.length),s?.end(),n.end(t.status,Date.now()-o),c(t.status,"passthrough","passthrough",void 0,void 0,{inputTokens:d?.input_tokens,outputTokens:d?.output_tokens,cacheCreationTokens:d?.cache_creation_input_tokens,cacheReadTokens:d?.cache_read_input_tokens})}else s?.end(),n?.end(t.status,Date.now()-o),c(t.status,"passthrough","passthrough");return u}async function Van(r){let{ctx:e,body:t,tracer:n,requestStartTime:o,accountStrategy:s,primaryAccountKey:i,accountAllowlist:a,quotaRoutingEnabled:c=Pve(),sessionSoftLimit:l=Mve(),sessionResetToleranceMs:u=Ove(),buildLoggedClaudeError:d,setRoutingDecision:p}=r,f=await Promise.resolve().then(()=>(Zn(),_c)),h=await Promise.resolve().then(()=>(xp(),jP)),y=[],x=`${h.homedir()}/.neurolink/anthropic-credentials.json`,{tokenStore:b}=await Promise.resolve().then(()=>(OJ(),yve)),T=await pJ();Pnt||(await b.pruneExpired(),Pnt=!0);let S=await b.listByPrefix("anthropic:");for(let N of S){if(!Hbe(N,a)){g.debug(`[proxy] skipping account=${N} (not in account allowlist)`);continue}if(await b.isDisabled(N)){let X=Vf(N);if(await b.getDisabledReason(N)==="refresh_failed")await b.markEnabled(N),g.always(`[proxy] account=${N.split(":")[1]??N} re-enabled for legacy refresh failure recheck`),X.permanentlyDisabled=!1,X.consecutiveRefreshFailures=0;else{g.debug(`[proxy] skipping disabled account=${N.split(":")[1]??N}`),X.permanentlyDisabled=!0;continue}}let z=await b.loadTokens(N);if(!z)continue;let $=z.accessToken,U=z.refreshToken,B=z.expiresAt,j=N.split(":")[1]??N,K=z.tokenType==="Bearer"?"oauth":"api_key",Y=Vf(N),G=T[N];G?.coolingUntil>Date.now()&&(!Y.coolingUntil||G.coolingUntil>Y.coolingUntil)&&(Y.coolingUntil=G.coolingUntil,Y.coolingReason=G.reason);let ne=()=>{y.push({key:N,label:j,token:$,refreshToken:U,expiresAt:B,type:K,persistTarget:{providerKey:N}})};if(B?B<Date.now():!1){if(Y.permanentlyDisabled)continue;if(Y.coolingReason==="auth"&&Y.coolingUntil&&Y.coolingUntil>Date.now()){ne();continue}if(!U){g.always(`[proxy] skipping account=${j} (expired, no refresh token)`),await mw({key:N,label:j,token:$,type:"oauth"},Y,"missing_refresh_token");continue}let X={token:$,refreshToken:U,expiresAt:B,label:j},se=await NJ(X,{providerKey:N});if(!se.success){let ue={key:N,label:j,token:$,type:"oauth"};if(pw(se))g.always(`[proxy] skipping account=${j} (refresh token rejected: ${se.error?.slice(0,200)??"unknown"})`),await mw(ue,Y,"refresh_invalid");else{let Ge=await VJ(ue,Y);g.always(`[proxy] account=${j} refresh temporarily unavailable (${se.status??"network"}); cooling until ${new Date(Ge).toISOString()} and rotating`),ne()}continue}$=X.token,U=X.refreshToken,B=X.expiresAt,await b.saveTokens(N,{accessToken:$,refreshToken:U,expiresAt:B??Date.now()+36e5,tokenType:"Bearer"}),g.always(`[proxy] refreshed expired account=${N.split(":")[1]??N} at startup`),await qJ({key:N},Y)}ne()}if(y.length===0&&Wbe(S.length,oF,a))try{let N=JSON.parse(f.readFileSync(x,"utf8")),z=await Uan(N,x);z&&y.push(z)}catch{}if(process.env.ANTHROPIC_API_KEY&&y.length===0&&Wbe(S.length,qbe,a)&&y.push({key:qbe,label:"env",token:process.env.ANTHROPIC_API_KEY,type:"api_key"}),y.length===0){let N=a?"No allowed Anthropic credentials are currently available":S.length>0?"Configured Anthropic accounts are disabled or unavailable":"No Anthropic credentials found";return n?.setError("authentication_error",N),n?.end(401,Date.now()-o),{response:d(401,N)}}for(let N of y)acn(N);await Ean(y);let E=y.filter(N=>!Vf(N.key).permanentlyDisabled);if(E.length===0){let N=HJ(y.map(z=>z.label));return n?.setError("authentication_error",N),n?.end(401,Date.now()-o),{response:d(401,N)}}let C=Can({enabledAccounts:E,accountStrategy:s,primaryAccountKey:i,quotaRoutingEnabled:c,sessionSoftLimit:l,sessionResetToleranceMs:u,setRoutingDecision:p}),R=pcn(t),P=JSON.stringify(R),A=Date.now(),I=Array.isArray(t.tools)?t.tools.length:0,M="https://api.anthropic.com/v1/messages?beta=true",O=e.headers??{},F=Gnt(t);return{accounts:y,enabledAccounts:E,orderedAccounts:C,bodyStr:P,requestStart:A,toolCount:I,url:M,clientHeaders:O,isClaudeClientRequest:Vnt(O,F)}}async function qan(r){let{ctx:e,body:t,tracer:n,requestStartTime:o,logProxyBody:s,logFinalRequest:i,options:a,providerLabel:c}=r,l=new AbortController,u;try{u=await kt(e.neurolink.stream({...a,abortSignal:l.signal}),UJ,`Fallback ${c} initialization timed out after ${UJ}ms`)}catch(x){throw l.abort(x),x}let d=async x=>{let b=u.stream[Symbol.asyncIterator](),T="";try{for(;;){let{value:S,done:E}=await kt(b.next(),UJ,`Fallback ${c} stream timed out after ${UJ}ms of inactivity`);if(E)return T;let C=CJ(S);C&&(T+=C,x?.(C))}}catch(S){throw l.abort(S),b.return?.().catch(()=>{}),S}};if(t.stream){let x=new lA(t.model,0),b=[];for(let A of x.start())b.push(A);let T=await d(A=>{for(let I of x.pushDelta(A))b.push(I)}),S=u.toolCalls??[];if(!gF(T,S))throw new Error(`Translated provider ${c} returned no content or tool calls`);if(S.length)for(let A of S){let I=A.toolName??A.name??"unknown";for(let M of x.pushToolUse(cF(),I,sve(A)))b.push(M)}let E=u.finishReason??"end_turn",C=dw(u.usage);for(let A of x.finish(C.output,E))b.push(A);n?.end(200,Date.now()-o),i(200,"",c,void 0,void 0,{inputTokens:C.input,outputTokens:C.output});let R=b.join("");s({phase:"client_response",headers:{"content-type":"text/event-stream"},body:R,bodySize:Buffer.byteLength(R,"utf8"),contentType:"text/event-stream",responseStatus:200,durationMs:Date.now()-o});async function*P(){for(let A of b)yield A}return P()}let p=await d();if(!gF(p,u.toolCalls))throw new Error(`Translated provider ${c} returned no content or tool calls`);let f={content:p,model:u.model,finishReason:u.finishReason??"end_turn",reasoning:void 0,usage:u.usage?dw(u.usage):void 0,toolCalls:u.toolCalls};n?.end(200,Date.now()-o);let h=yJ(f,t.model);i(200,"",c,void 0,void 0,{inputTokens:f.usage?.input,outputTokens:f.usage?.output});let y=JSON.stringify(h);return s({phase:"client_response",headers:{"content-type":"application/json"},body:y,bodySize:Buffer.byteLength(y,"utf8"),contentType:"application/json",responseStatus:200,durationMs:Date.now()-o}),h}async function Wnt(r){let e;for(let t=0;t<=Tve;t+=1)try{return await qan(r)}catch(n){if(e=n,!Dve(n)||t===Tve)throw n;let o=_ve[t]??250;g.always(`[proxy] retrying fallback=${r.providerLabel} after transient network error (${t+1}/${Tve}) in ${o}ms: ${wA(n)}`),await TA(o)}throw e}async function Han(r){let{ctx:e,body:t,parsedFallbackRequest:n,modelRouter:o,tracer:s,requestStartTime:i,logProxyBody:a,logFinalRequest:c}=r,l=o?.getFallbackChain()??[],u=bA({provider:"anthropic",model:t.model},l,t.model,n);a({phase:"routing_decision",contentType:"application/json",body:{stage:"anthropic_fallback",attempts:u.attempts.slice(1)}}),s?.setFallbackInfo({triggered:!0,attemptCount:u.attempts.slice(1).length,reason:"all_anthropic_accounts_exhausted"});let d;for(let p of u.attempts.slice(1)){if(!p.provider||!p.model)continue;let f=await wf.checkFallbackProviderAvailability(p.provider,p.model);f.available||g.always(`[proxy] fallback ${p.provider}/${p.model} health-check failed (${f.reason??"provider unavailable"}), attempting anyway`);let h=Date.now();try{g.always(`[proxy] fallback \u2192 ${p.provider}/${p.model}`);let y=Qnt(n,{provider:p.provider,model:p.model}),x=await Wnt({ctx:e,body:t,tracer:s,requestStartTime:i,logProxyBody:a,logFinalRequest:c,options:y,providerLabel:p.provider});return yF({provider:p.provider,model:p.model,status:"success",durationMs:Date.now()-h}),s?.setFallbackInfo({triggered:!0,provider:p.provider,model:p.model,attemptCount:u.attempts.slice(1).length,reason:"fallback_success"}),{response:x}}catch(y){let x=y instanceof Error?y.message:String(y),b="unknown";x.includes("Rate limit")||x.includes("rate_limit")||x.includes("max_parallel_requests")?b="rate_limit":x.includes("context length")||x.includes("ContextWindowExceeded")?b="context_overflow":x.includes("no content or tool calls")||x.includes("NoOutputGenerated")?b="empty_response":x.includes("thinking_level")||x.includes("Field required")?b="schema_mismatch":x.includes("Resource exhausted")&&(b="provider_quota"),g.always(`[proxy] fallback ${p.provider}/${p.model} failed [${b}]: ${wA(y)}`),yF({provider:p.provider,model:p.model,status:"failure",errorMessage:`[${b}] ${x}`,durationMs:Date.now()-h}),d=`[${p.provider}/${p.model}] ${wA(y)}`}}return{response:null,lastErrorMessage:d}}async function Wan(r){let{ctx:e,body:t,tracer:n,requestStartTime:o,logProxyBody:s,logFinalRequest:i}=r,a=Date.now();try{let c=hJ(t),l=bA({provider:"anthropic",model:t.model},[],t.model,c);if(Hnt(s,"auto_fallback",l),!l.attempts.find(f=>f.label==="auto-provider"))return{response:null};g.always("[proxy] fallback \u2192 auto-provider");let d=Qnt(c),p=await Wnt({ctx:e,body:t,tracer:n,requestStartTime:o,logProxyBody:s,logFinalRequest:i,options:d,providerLabel:"auto-provider"});return yF({provider:"auto-provider",model:t.model,status:"success",durationMs:Date.now()-a}),n?.setFallbackInfo({triggered:!0,provider:"auto-provider",model:t.model,attemptCount:1,reason:"fallback_success"}),{response:p}}catch(c){let l=wA(c);return g.always(`[proxy] fallback auto-provider failed: ${l}`),yF({provider:"auto-provider",model:t.model,status:"failure",errorMessage:l,durationMs:Date.now()-a}),n?.setFallbackInfo({triggered:!0,provider:"auto-provider",model:t.model,attemptCount:1,reason:"fallback_failure"}),{response:null,lastErrorMessage:l}}}function Kan(r){let{tracer:e,requestStartTime:t,authFailureMessage:n,authCooldownMessage:o,invalidRequestFailure:s,sawNetworkError:i,sawTransientFailure:a,sawRateLimit:c,lastError:l,fallbackFailureMessage:u,orderedAccounts:d,buildLoggedClaudeError:p,logProxyBody:f,logFinalRequest:h}=r;if(n&&!c)return e?.setError("authentication_error",n),e?.end(401,Date.now()-t),p(401,n);if(o&&!c)return e?.setError("token_refresh_unavailable",o),e?.end(503,Date.now()-t),p(503,o,"token_refresh_unavailable");if(s){e?.setError("invalid_request_error",bo(s.body)),e?.end(s.status,Date.now()-t);try{let P=JSON.parse(s.body);return h(s.status,"","final","invalid_request_error",bo(s.body)),f({phase:"client_response",headers:{"content-type":s.contentType??"application/json"},body:s.body,bodySize:Buffer.byteLength(s.body,"utf8"),contentType:s.contentType??"application/json",responseStatus:s.status,durationMs:Date.now()-t}),P}catch{return p(s.status,bo(s.body),"invalid_request_error")}}if((i||a)&&!c){let P=u?` Fallback also failed: ${u}`:"",A=`All Anthropic accounts failed due to transient upstream/network errors. Last error: ${l instanceof Error?l.message:String(l??"unknown")}.${P}`;return e?.setError("transient_error",A.slice(0,500)),e?.end(502,Date.now()-t),p(502,A,u?"fallback_exhausted":"transient_error")}if(!c){let P=u?` Fallback also failed: ${u}`:"",A=`All Anthropic accounts failed. Last error: ${l instanceof Error?l.message:String(l??"unknown")}.${P}`;return e?.setError("all_accounts_failed",A.slice(0,500)),e?.end(502,Date.now()-t),p(502,A,u?"fallback_exhausted":"all_accounts_failed")}let y=Date.now(),x=d.map(P=>Vf(P.key)).filter(P=>P.coolingUntil&&P.coolingUntil>y&&P.coolingReason!=="auth"),b=Math.min(...x.map(P=>P.coolingUntil??Number.POSITIVE_INFINITY)),T=d.length>0&&x.length===d.length,S=T?Math.max(1,Math.ceil((b-y)/1e3)):1,E=T?`All ${d.length} Anthropic accounts are cooling after upstream rate limits. Earliest retry at ${new Date(b).toISOString()}.`:`All ${d.length} accounts rate-limited after per-account retries.`;g.always(`[proxy] all accounts rate-limited, retry in ${S}s`);let C=ld(429,E,"overloaded_error");e?.setError("rate_limit_error",E),e?.end(429,Date.now()-t),h(429,"","final","rate_limit_error",E);let R=JSON.stringify(C);return f({phase:"client_response",headers:{"content-type":"application/json","retry-after":String(S)},body:R,bodySize:Buffer.byteLength(R,"utf8"),contentType:"application/json",responseStatus:429,durationMs:Date.now()-t}),new Response(R,{status:429,headers:{"content-type":"application/json","retry-after":String(S)}})}async function Knt(r){let{ctx:e,body:t,account:n,accountState:o,response:s,tracer:i,requestStartTime:a,fetchStartMs:c,attemptNumber:l,finalBodyStr:u,upstreamSpan:d,logAttempt:p,logProxyBody:f,logFinalRequest:h}=r;o.consecutiveRefreshFailures=0,g.always(`[proxy] \u2190 ${s.status} account=${n.label}`);let y=cA(s.headers);if(y){if(o.quota=y,$nt(o,y,Date.now())){let{coolingUntil:b,coolingReason:T}=o;b!==void 0&&T!==void 0&&aw(n.key,b,T).catch(()=>{})}aF(n.label,y).catch(()=>{})}let x={};return s.headers.forEach((b,T)=>{x[T]=b}),i?.logUpstreamResponseHeaders(x),t.stream?Jan({ctx:e,body:t,account:n,accountState:o,response:s,responseHeaders:x,tracer:i,requestStartTime:a,fetchStartMs:c,attemptNumber:l,finalBodyStr:u,upstreamSpan:d,logAttempt:p,logProxyBody:f,logFinalRequest:h}):Xan({account:n,response:s,responseHeaders:x,tracer:i,requestStartTime:a,fetchStartMs:c,attemptNumber:l,finalBodyStr:u,upstreamSpan:d,logAttempt:p,logProxyBody:f,logFinalRequest:h})}async function Jan(r){let{account:e,accountState:t,response:n,responseHeaders:o,tracer:s,requestStartTime:i,fetchStartMs:a,attemptNumber:c,finalBodyStr:l,upstreamSpan:u,logAttempt:d,logProxyBody:p,logFinalRequest:f}=r;if(!n.body){ao(e.label,e.type,502),d(502,"stream_error","No response body from upstream"),u?.end(),s?.setError("stream_error","No response body from upstream"),s?.end(502,Date.now()-i),f(502,e.label,e.type,"stream_error","No response body from upstream");let E=ld(502,"No response body from upstream"),C=JSON.stringify(E);return p({phase:"client_response",headers:{"content-type":"application/json"},body:C,bodySize:Buffer.byteLength(C,"utf8"),contentType:"application/json",account:e.label,accountType:e.type,attempt:c,responseStatus:502,durationMs:Date.now()-i}),{response:E}}let h=n.body.getReader(),y=await Snt(h);if(y.kind==="transport_error"){let E=wA(y.error),C=Buffer.concat(y.chunks.map(R=>Buffer.from(R))).toString("utf8");return g.always(`[proxy] stream failed before first chunk account=${e.label}: ${E}; trying next account`),ao(e.label,e.type,502),d(502,"stream_error",E,{retryable:!0}),s?.recordRetry(e.label,"stream_before_first_chunk"),u?.end(),p({phase:"upstream_response",headers:o,body:C,bodySize:Buffer.byteLength(C,"utf8"),contentType:o["content-type"]??"text/event-stream",account:e.label,accountType:e.type,attempt:c,responseStatus:n.status,durationMs:Date.now()-a,metadata:{logicalStatus:502,transportError:E}}),{retryNextAccount:!0,failure:{message:E,rateLimit:!1}}}if(y.kind==="empty")return await h.cancel().catch(()=>{}),g.always(`[proxy] \u2190 empty stream from account=${e.label}, trying next`),ao(e.label,e.type,502),d(502,"empty_stream","Empty upstream stream",{retryable:!0}),s?.recordRetry(e.label,"empty_stream"),u?.end(),p({phase:"upstream_response",headers:o,body:"",bodySize:0,contentType:o["content-type"]??"text/event-stream",account:e.label,accountType:e.type,attempt:c,responseStatus:n.status,durationMs:Date.now()-a,metadata:{logicalStatus:502,upstreamErrorType:"empty_stream"}}),{retryNextAccount:!0,failure:{message:"Empty upstream stream",rateLimit:!1}};if(y.kind==="sse_error"){await h.cancel().catch(()=>{});let E=Buffer.concat(y.chunks.map(I=>Buffer.from(I))).toString("utf8"),C=y.errorType==="rate_limit_error",R=C?429:502,P=cA(o),A=Date.now();if(C){let I=Ave(P,LJ(o["retry-after"]??null),A,iF(o));t.quota=P??t.quota;let M=I.reason==="transient"?"transient":"quota";(!t.coolingUntil||I.coolingUntil>t.coolingUntil)&&(t.coolingUntil=I.coolingUntil,t.coolingReason=I.reason,await aw(e.key,I.coolingUntil,I.reason).catch(()=>{})),ao(e.label,e.type,429,M),d(429,"rate_limit_error",y.message,{retryable:!0,rateLimitKind:M,cooldownReason:I.reason})}else ao(e.label,e.type,R),d(R,y.errorType,y.message,{retryable:!0});return g.always(`[proxy] immediate SSE ${y.errorType} account=${e.label}: ${y.message}; rotating before client commit`),s?.recordRetry(e.label,C?"stream_rate_limit_before_commit":"stream_error_before_commit"),u?.end(),p({phase:"upstream_response",headers:o,body:E,bodySize:Buffer.byteLength(E,"utf8"),contentType:o["content-type"]??"text/event-stream",account:e.label,accountType:e.type,attempt:c,responseStatus:n.status,durationMs:Date.now()-a,metadata:{logicalStatus:R,upstreamErrorType:y.errorType}}),{retryNextAccount:!0,failure:{message:y.message,rateLimit:C}}}d(n.status,void 0,void 0,{attemptDurationMs:Date.now()-a});let x=gve(),b=!1,T=new ReadableStream({start(E){for(let C of y.chunks)E.enqueue(C)},async pull(E){if(!b)try{let{done:C,value:R}=await h.read();if(b)return;if(C){b=!0,x.complete(),E.close();return}E.enqueue(R)}catch(C){let R=wA(C);if(g.always(`[proxy] mid-stream error account=${e.label}: ${R}`),x.fail(R),!b){b=!0;let P=`event: error
|
|
2469
|
+
`);for(let T of b)bnt(t,T)}c()}}),u=l.writable.getWriter(),d,p=new WritableStream({start(x){d=x},write(x){return u.write(x)},close(){return u.close()},abort(x){return c(),u.abort(x)}});u.closed.catch(x=>{c();try{d.error(x)}catch{}});let f=l.readable.getReader();return{stream:{readable:new ReadableStream({async pull(x){try{let{done:b,value:T}=await f.read();b?x.close():x.enqueue(T)}catch(b){x.error(b)}},async cancel(x){c();try{d.error(x)}catch{}await Promise.allSettled([f.cancel(x),u.abort(x)])}}),writable:p},telemetry:a}}var Qin=64*1024,ean=32;function vnt(r){try{let e=JSON.parse(r);return{errorType:e.error?.type??e.type??"stream_error",message:e.error?.message??e.message??"Upstream SSE error"}}catch{return{errorType:"stream_error",message:r.trim()||"Upstream SSE error"}}}function Tnt(r){if(r.event==="error")return!0;try{let e=JSON.parse(r.data);return e.type==="error"||e.error!==void 0}catch{return!1}}async function Snt(r){let e=new TextDecoder,t=[],n="",o=0;for(;o<Qin&&t.length<ean;){let s;try{s=await r.read()}catch(a){return{kind:"transport_error",chunks:t,error:a}}if(s.done){n+=e.decode();let{events:a}=xF(n),c=a.find(Tnt);return c?{kind:"sse_error",chunks:t,...vnt(c.data)}:t.length>0?{kind:"ready",chunks:t}:{kind:"empty",chunks:t}}if(!s.value||s.value.length===0)continue;t.push(s.value),o+=s.value.byteLength,n+=e.decode(s.value,{stream:!0});let i=xF(n);n=i.remainder;for(let a of i.events){if(Tnt(a))return{kind:"sse_error",chunks:t,...vnt(a.data)};if(a.event!=="ping"&&(a.event||a.data))return{kind:"ready",chunks:t}}}return t.length>0?{kind:"ready",chunks:t}:{kind:"empty",chunks:t}}function gve(){let r=!1,e,t=new Promise(o=>{e=o}),n=o=>{r||(r=!0,e(o))};return{outcome:t,complete:()=>n({kind:"completed"}),fail:o=>n({kind:"upstream_error",message:o}),cancel:()=>n({kind:"client_cancelled"})}}function vF(r,e){return r.kind==="completed"&&e?{kind:"upstream_error",message:e}:r}J();OJ();BD();cs();ln();var ian=300*1e3,aan=6e4,xve=2e3,Gf=new Map;function bve(r){return!!(r.expiresAt&&r.expiresAt<=Date.now()+ian&&r.refreshToken)}function knt(r){return r===400||r===401||r===403||r===404}function pw(r){return knt(r.status)}async function can(r){if(!r.refreshToken)return{success:!1,error:"No refresh token available"};let e=new URLSearchParams({grant_type:"refresh_token",refresh_token:r.refreshToken,client_id:J3}).toString(),t={"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json","User-Agent":Jx},n=[cC,Z4e],o;for(let s of n)try{let i=await fetch(s,{method:"POST",headers:t,body:e,signal:AbortSignal.timeout(1e4)});if(!i.ok){let c=await i.text();g.warn(`[token-refresh] failed for ${r.label} at ${xi(s)}`,{status:i.status,error:c.slice(0,500)});let l={success:!1,error:c,status:i.status};if(knt(i.status)&&(o=l),s===cC)continue;return o??l}let a=await i.json();return r.token=a.access_token,r.expiresAt=a.expires_in!==void 0?Date.now()+a.expires_in*1e3:Date.now()+3300*1e3,a.refresh_token&&(r.refreshToken=a.refresh_token),g.debug(`[token-refresh] refreshed for ${r.label}`),{success:!0}}catch(i){if(g.warn(`[token-refresh] exception for ${r.label} at ${xi(s)}`,{error:String(i)}),s===cC)continue;return o??{success:!1,error:String(i)}}return o??{success:!1,error:"No refresh URLs available"}}async function vve(r){if(!r.refreshToken)return{success:!1,error:"No refresh token available"};let e=r.refreshToken,t=Gf.get(e);if(!t){let o={...r},s=can(o).then(i=>{let a={result:i,token:o.token,refreshToken:o.refreshToken,expiresAt:o.expiresAt};if(i.success){let c=new Set([e]),l=o.refreshToken;l&&l!==e&&!Gf.has(l)&&(Gf.set(l,s),c.add(l)),setTimeout(()=>{for(let d of c)Gf.get(d)===s&&Gf.delete(d)},aan).unref?.()}else Gf.get(e)===s&&Gf.delete(e);return a},i=>{throw Gf.get(e)===s&&Gf.delete(e),i});Gf.set(e,s),t=s}let n=await t;return n.result.success&&(r.token=n.token,r.refreshToken=n.refreshToken,r.expiresAt=n.expiresAt),n.result}async function _nt(r,e){if(!e||typeof e=="string"||!("providerKey"in e))return!1;let t;try{t=await kt(xA.peekTokens(e.providerKey),xve,"[token-refresh] peekTokens reconciliation timed out")}catch(n){return g.debug("[token-refresh] skipping persisted-state reconciliation (peek failed)",{error:n instanceof Error?n.message:String(n)}),!1}return!t||t.expiresAt<=(r.expiresAt??0)||t.accessToken===r.token&&t.refreshToken===r.refreshToken&&t.expiresAt===r.expiresAt?!1:(r.token=t.accessToken,r.refreshToken=t.refreshToken,r.expiresAt=t.expiresAt,!0)}async function NJ(r,e){if(await _nt(r,e)&&!bve(r))return{success:!0};let n=await vve(r);return n.success?n:await _nt(r,e)?{success:!0}:n}async function DJ(r,e){if(typeof r!="string"&&"providerKey"in r){await uan(r.providerKey,e);return}let t=typeof r=="string"?r:r.credPath;await lan(t,e)}async function lan(r,e){try{let t=await Promise.resolve().then(()=>(Nu(),wg)),n=JSON.parse(await t.readFile(r,"utf8"));n.oauth={...n.oauth,accessToken:e.token,expiresAt:e.expiresAt,refreshToken:e.refreshToken},n.updatedAt=Date.now(),await ep(r,n,384)}catch(t){g.warn("[token-refresh] Failed to persist legacy credentials",{error:t instanceof Error?t.message:String(t)})}}async function uan(r,e){try{let t=await kt(xA.peekTokens(r),xve,"[token-refresh] peekTokens for persistence timed out"),n={accessToken:e.token,refreshToken:e.refreshToken??t?.refreshToken,expiresAt:e.expiresAt??t?.expiresAt??Date.now()+3300*1e3,tokenType:t?.tokenType??"Bearer",...t?.scope?{scope:t.scope}:{}};await kt(xA.saveTokens(r,n),xve,"[token-refresh] saveTokens timed out")}catch(t){g.warn("[token-refresh] Failed to persist TokenStore credentials",{error:t instanceof Error?t.message:String(t)})}}function dan(r){let e=r.toLowerCase();return e.includes("opus")?"opus":e.includes("sonnet")?"sonnet":e.includes("haiku")?"haiku":"other"}function bA(r,e,t,n){let o=[{provider:r.provider,model:r.model,label:`${r.provider}/${r.model??"unknown"}`}];for(let s of e)s.provider===r.provider&&s.model===r.model||o.push({provider:s.provider,model:s.model,label:`${s.provider}/${s.model}`});return(e.length===0||o.length===1)&&o.push({label:"auto-provider"}),{requestedModel:t,modelTier:dan(t),attempts:o,skipped:[]}}function LJ(r){if(!r)return 0;let e=parseInt(r,10);if(!Number.isNaN(e))return Math.max(1,e)*1e3;let t=new Date(r);return Number.isNaN(t.getTime())?0:Math.max(1e3,t.getTime()-Date.now())}J();cs();pb();var jJ=new Set(["cookie","proxy-authorization","host","connection","content-length","transfer-encoding"]),wve="proxy/internal",Eve="internal",Nb=0,Cnt=0,TF=5,FJ=2,_ve=[250,1e3],Tve=1,UJ=120*1e3,kve=2,Rnt=3e4,pan=11520*60*1e3,Dnt=5e3,man=900*1e3,Lnt=900*1e3,fan=3e4,gan=300*1e3,Rve=900*1e3,SF=new Map,Ant=new Map,Int=new Map,Pnt=!1,Sve=6e4,han=9e4,yan=12e4,xan=250,ban=15e3;function vA(r,e,t){e<=1||r===t&&(Nb=(Nb+1)%e)}function Fnt(r,e){if(!e)return 0;let t=r.findIndex(n=>jrt(n.key,e));return t>=0?t:0}function van(r,e){if(r.length<=1)return;let t=Fnt(r,e);if(Nb===t)return;let n=r[t],o=SF.get(n.key);if((!o||!o.coolingUntil||Date.now()>=o.coolingUntil)&&(Nb=t,o?.coolingUntil)){let s=o.coolingUntil;o.coolingUntil=void 0,o.coolingReason=void 0,mJ(n.key,s).catch(()=>{}),g.always(`[proxy] home primary account=${n.label} cooling expired, resetting primaryAccountIndex to ${t}`)}}function Unt(r){let e=SF.get(r);return!!e?.coolingUntil&&Date.now()<e.coolingUntil}function Tan(r,e,t=Date.now()){let n=Ant.get(r);if(!n||t>=n.coolingUntil?(n={coolingUntil:e,retriesClaimed:0},Ant.set(r,n)):e>n.coolingUntil&&(n.coolingUntil=e),!(n.retriesClaimed>=kve))return n.retriesClaimed+=1,n.retriesClaimed}function San(r,e,t=Date.now()){if(e<=t)return 0;if(e-t>han)return;let n=Int.get(r);!n||t>=n.coolingUntil?(n={coolingUntil:e,nextAdmissionAt:e},Int.set(r,n)):e>n.coolingUntil&&(n.coolingUntil=e,n.nextAdmissionAt=Math.max(n.nextAdmissionAt,e));let o=Math.max(t,n.coolingUntil,n.nextAdmissionAt);if(!(o-n.coolingUntil>ban))return n.nextAdmissionAt=o+xan,o-t}async function wan(r){let e=Date.now()+yan;for(;Date.now()<e;){let t=r.filter(i=>!Unt(i.key));if(t.length>0)return t;let n=Date.now(),o=r.map(i=>({account:i,state:Vf(i.key)})).filter(({state:i})=>i.coolingReason==="transient"&&i.coolingUntil!==void 0&&i.coolingUntil>n).sort((i,a)=>(i.state.coolingUntil??Number.POSITIVE_INFINITY)-(a.state.coolingUntil??Number.POSITIVE_INFINITY))[0];if(!o?.state.coolingUntil)return[];let s=San(o.account.key,o.state.coolingUntil,n);if(s===void 0||n+s>e)return[];g.always(`[proxy] all usable accounts are transiently cooling; queueing request for account=${o.account.label} in ${s}ms`),await TA(s)}return[]}function SA(r,e){if(!r||r<=0)return;let t=r>4102444800?r:r*1e3;return t>e?t:void 0}function BJ(r,e){return Math.min(Math.max(r,e+Dnt),e+pan)}function Ave(r,e,t,n=r?.unifiedStatus){if(r&&r.weeklyStatus==="rejected"){let s=SA(r.weeklyResetAt,t)??(e>0?t+e:t+Sve);return{reason:"weekly",coolingUntil:BJ(s,t),rotateImmediately:!0}}if(r&&r.sessionStatus==="rejected"){let s=SA(r.sessionResetAt,t)??(e>0?t+e:t+Sve);return{reason:"session",coolingUntil:BJ(s,t),rotateImmediately:!0}}if(n?.trim().toLowerCase()==="rejected"){let s=e>0?t+e:t+Lnt;return{reason:"unified",coolingUntil:BJ(s,t),rotateImmediately:!0}}let o=e>0?e:Sve;return{reason:"transient",coolingUntil:t+Math.max(Dnt,Math.min(o,man)),rotateImmediately:!1}}function Ive(r,e){return Math.max(0,Math.round((r-e)/6e4))}function $nt(r,e,t){let n,o;if(e.weeklyStatus==="rejected"?(n=SA(e.weeklyResetAt,t),o="weekly"):e.sessionStatus==="rejected"?(n=SA(e.sessionResetAt,t),o="session"):e.unifiedStatus==="rejected"&&(n=t+Lnt,o="unified"),n===void 0)return!1;let s=BJ(n,t);return!r.coolingUntil||s>r.coolingUntil?(r.coolingUntil=s,r.coolingReason=o,g.always(`[proxy] proactively cooling account (${o}) ~${Ive(s,t)}m from success-response quota (status rejected)`),!0):!1}async function Ean(r){try{let[e,t]=await Promise.all([Hrt(),pJ()]),n=Date.now();for(let o of r){let s=Vf(o.key);!s.quota&&e[o.label]&&(s.quota=e[o.label]);let i=t[o.key];i?.coolingUntil>n&&(!s.coolingUntil||i.coolingUntil>s.coolingUntil)&&(s.coolingUntil=i.coolingUntil,s.coolingReason=i.reason)}}catch{}}function Pve(){let r=(process.env.NEUROLINK_PROXY_QUOTA_ROUTING??"").toLowerCase();return r!=="off"&&r!=="false"&&r!=="0"}function Mve(){let r=Number(process.env.NEUROLINK_PROXY_SESSION_SOFT_LIMIT??"");return Number.isFinite(r)&&r>0&&r<=1?r:.97}function Ove(){let r=Number(process.env.NEUROLINK_PROXY_SESSION_RESET_TOLERANCE_MS??"");return Number.isInteger(r)&&r>0?r:900*1e3}function Bnt(r,e,t,n){let o=SF.get(r),s=o?.quota,i=!!o?.coolingUntil&&e<o.coolingUntil,a=SA(s?.weeklyResetAt,e),c=SA(s?.sessionResetAt,e),l=c!==void 0,u=a!==void 0,d=s?l?s.sessionUsed??0:0:null,p=s?u?s.weeklyUsed??null:0:null,f=s?l?s.sessionStatus??"unknown":"allowed":null,h=s?u?s.weeklyStatus??"unknown":"allowed":null,y=f==="throttled"||l&&(d??0)>=t,x=s&&Number.isFinite(s.lastUpdated)?s.lastUpdated:null;return{usable:!i&&h!=="rejected"&&f!=="rejected",saturated:y,hasQuota:!!s,quotaLastUpdated:x,quotaAgeMs:x===null?null:Math.max(0,e-x),coolingActive:i,coolingReason:o?.coolingReason??null,coolingUntil:o?.coolingUntil??0,unifiedStatus:s?.unifiedStatus??null,overageStatus:s?.overageStatus??null,sessionStatus:f,sessionUsed:d,sessionResetBucket:l?Math.floor(c/n):Number.POSITIVE_INFINITY,sessionReset:c??Number.POSITIVE_INFINITY,weeklyStatus:h,weeklyReset:a??Number.POSITIVE_INFINITY,weeklyUsed:p,weeklyUsedForSort:p??-1}}function znt(r,e,t,n){let o=t.get(r.key),s=t.get(e.key);if(!o||!s)return[0,"insertion_order"];if(o.usable!==s.usable)return[o.usable?-1:1,"availability"];if(!o.usable&&!s.usable){let i=o.coolingUntil||Number.POSITIVE_INFINITY,a=s.coolingUntil||Number.POSITIVE_INFINITY;return[i===a?0:i-a,i===a?"insertion_order":"cooldown_recovery"]}if(o.hasQuota!==s.hasQuota)return[o.hasQuota?1:-1,"quota_probe"];if(o.saturated!==s.saturated)return[o.saturated?1:-1,"session_headroom"];if(o.saturated&&s.saturated){if(o.sessionResetBucket!==s.sessionResetBucket)return[o.sessionResetBucket-s.sessionResetBucket,"session_reset"];if(o.weeklyReset!==s.weeklyReset)return[o.weeklyReset-s.weeklyReset,"weekly_reset"]}else{if(o.weeklyReset!==s.weeklyReset)return[o.weeklyReset-s.weeklyReset,"weekly_reset"];if(o.sessionResetBucket!==s.sessionResetBucket)return[o.sessionResetBucket-s.sessionResetBucket,"session_reset"]}return o.weeklyUsedForSort!==s.weeklyUsedForSort?[s.weeklyUsedForSort-o.weeklyUsedForSort,"weekly_utilization"]:n&&r.key===n!=(e.key===n)?[r.key===n?-1:1,"configured_primary"]:[0,"insertion_order"]}function _an(r,e,t,n,o){let s=new Map(r.map(i=>[i.key,Bnt(i.key,e,n,o)]));return{orderedAccounts:[...r].sort((i,a)=>znt(i,a,s,t)[0]),metricsByKey:s}}function kan(r){let{accounts:e,orderedAccounts:t,metricsByKey:n,evaluatedAt:o,strategy:s,primaryKey:i,quotaRoutingEnabled:a,quotaOrdered:c,sessionSoftLimit:l,sessionResetToleranceMs:u,rotationOffset:d}=r,p=new Map(e.map((T,S)=>[T.key,S])),f=!!i&&e.some(T=>T.key===i),h=[];for(let T of t){let S=n.get(T.key);if(!S){g.warn(`[proxy] routing evidence omitted because metrics are missing for account=${T.label}`);return}h.push({account:T.label,accountType:T.type,sourceIndex:p.get(T.key)??h.length,rank:h.length,configuredPrimary:!!i&&T.key===i,usable:S.usable,saturated:S.saturated,quotaObserved:S.hasQuota,quotaLastUpdated:S.quotaLastUpdated,quotaAgeMs:S.quotaAgeMs,coolingActive:S.coolingActive,coolingReason:S.coolingReason,coolingUntil:S.coolingUntil>0&&Number.isFinite(S.coolingUntil)?S.coolingUntil:null,unifiedStatus:S.unifiedStatus,overageStatus:S.overageStatus,sessionStatus:S.sessionStatus,sessionUsed:S.sessionUsed,sessionResetAt:Number.isFinite(S.sessionReset)?S.sessionReset:null,sessionResetBucket:Number.isFinite(S.sessionResetBucket)?S.sessionResetBucket:null,weeklyStatus:S.weeklyStatus,weeklyUsed:S.weeklyUsed,weeklyResetAt:Number.isFinite(S.weeklyReset)?S.weeklyReset:null})}let y=t[0],x,b;return t.length===1?(x="single_account",b="single_account"):c?(x="quota",b=znt(t[0],t[1],n,i)[1]):s==="round-robin"?(x="round_robin",b="round_robin"):(x="primary",b=f&&y?.key===i?"configured_primary":"insertion_order"),{schemaVersion:1,evaluatedAt:new Date(o).toISOString(),strategy:s,mode:x,selectionReason:b,quotaRoutingEnabled:a,quotaInputsUsed:c,sessionSoftLimit:l,sessionResetToleranceMs:u,configuredPrimaryAccount:i??null,configuredPrimaryMatched:f,rotationOffset:d,initialAccount:y?.label??"",candidates:h}}function Can(r){let{enabledAccounts:e,accountStrategy:t,primaryAccountKey:n,quotaRoutingEnabled:o,sessionSoftLimit:s,sessionResetToleranceMs:i,setRoutingDecision:a}=r,c=[...e],l=Date.now(),u,d=0,p=t==="fill-first"&&c.length>1&&o;if(!p&&t==="fill-first"&&van(e,n),p){let h=_an(e,l,n,s,i);c=h.orderedAccounts,u=h.metricsByKey,g.shouldLog("debug")&&g.debug(`[proxy] quota-ordered fill sequence: ${c.map(y=>y.label).join(" \u2192 ")}`)}else{if(t==="round-robin"&&c.length!==Cnt&&(Nb=Fnt(c,n),Cnt=c.length),c.length>1&&(d=Nb%c.length,t==="round-robin"&&(Nb=(Nb+1)%c.length),d>0)){let h=c.splice(0,d);c.push(...h)}u=new Map(e.map(h=>[h.key,Bnt(h.key,l,s,i)]))}let f=kan({accounts:e,orderedAccounts:c,metricsByKey:u,evaluatedAt:l,strategy:t,primaryKey:n,quotaRoutingEnabled:o,quotaOrdered:p,sessionSoftLimit:s,sessionResetToleranceMs:i,rotationOffset:d});return f&&a(f),c}var zJ=new Map,Ran=300*1e3,Aan=new Set(["accept","accept-encoding","accept-language","anthropic-beta","anthropic-dangerous-direct-browser-access","anthropic-version","sec-fetch-mode","user-agent","x-app","x-stainless-arch","x-stainless-lang","x-stainless-os","x-stainless-package-version","x-stainless-retry-count","x-stainless-runtime","x-stainless-runtime-version","x-stainless-timeout","x-subscription-tier"]),Ian=["oauth-2025-04-20","claude-code-20250219","fine-grained-tool-streaming-2025-05-14"];function GJ(r){return r.replace(/[^a-zA-Z0-9._@-]/g,"_")}function jnt(r){return Xt(xH(),".neurolink","header-snapshots",`anthropic_${GJ(r)}.json`)}function Pan(r,e){if(e?.headers)for(let[t,n]of Object.entries(e.headers)){let o=t.toLowerCase();typeof n=="string"&&!r[o]&&!jJ.has(o)&&o!=="authorization"&&o!=="x-api-key"&&o!=="x-claude-code-session-id"&&(r[o]=n)}}async function Man(r){try{let e=GJ(r),t=zJ.get(e);if(t&&Date.now()-t.loadedAt<Ran)return t.snapshot;let n=jnt(r);try{await vM(n)}catch{return null}let o=JSON.parse(await Bn(n,"utf8"));if(!o||typeof o!="object")return null;let s={accountKey:"accountKey"in o&&typeof o.accountKey=="string"?o.accountKey:`anthropic:${r}`,capturedAt:"capturedAt"in o&&typeof o.capturedAt=="string"?o.capturedAt:new Date(0).toISOString(),source:"claude-code",headers:"headers"in o&&o.headers?o.headers:{},...o.body?{body:o.body}:{}};return Object.keys(s.headers).length===0&&Object.keys(s.body??{}).length===0?null:(zJ.set(e,{snapshot:s,loadedAt:Date.now()}),s)}catch{return null}}function Oan(r,e){let t={...e??{}};for(let[n,o]of Object.entries(r)){let s=n.toLowerCase();typeof o=="string"&&Aan.has(s)&&!jJ.has(s)&&s!=="authorization"&&s!=="x-api-key"&&s!=="x-claude-code-session-id"&&(t[s]=o)}return t}function Gnt(r){if(!r||typeof r!="object")return;let e=r,t=sde(e.metadata?.user_id),n=Array.isArray(e.system)?e.system:typeof e.system=="string"?[{type:"text",text:e.system}]:[],o=n.find(i=>typeof i?.text=="string"&&i.text.includes("x-anthropic-billing-header"))?.text,s=n.find(i=>typeof i?.text=="string"&&i.text.includes("Claude Agent SDK"))?.text;if(!(!t&&!o&&!s))return{...t?{metadataUserId:t.metadataUserId}:{},...t?{sessionId:t.sessionId}:{},...o?{billingHeader:o}:{},...s?{agentBlock:s}:{}}}function Vnt(r,e){return typeof r["x-claude-code-session-id"]=="string"||r["user-agent"]?.startsWith("claude-cli/")||!!e?.metadataUserId||!!e?.billingHeader||!!e?.agentBlock}function Nan(r,e){return r?JSON.stringify(r.headers??{})===JSON.stringify(e.headers??{})&&JSON.stringify(r.body??{})===JSON.stringify(e.body??{}):!1}async function Dan(r,e){let t=jnt(r);await ep(t,e,384),zJ.set(GJ(r),{snapshot:e,loadedAt:Date.now()})}async function Lan(r,e,t,n){let o=await Man(r),s;try{s=JSON.parse(n)}catch{return o}let i=Gnt(s);if(!Vnt(t,i))return o;let a={accountKey:e,capturedAt:new Date().toISOString(),source:"claude-code",headers:Oan(t,o?.headers),body:{...o?.body??{},...i??{},...typeof t["x-claude-code-session-id"]=="string"?{sessionId:t["x-claude-code-session-id"]}:{}}};if(Nan(o,a))return o;try{await Dan(r,a)}catch(c){g.warn("[proxy] failed to persist Claude snapshot",{accountLabel:r,error:c instanceof Error?c.message:String(c)}),zJ.set(GJ(r),{snapshot:a,loadedAt:Date.now()})}return a}function Nve(r){let e={};if(!r||typeof r!="object")return e;let t=r;if(typeof t.model=="string"&&(e.responseModel=t.model),typeof t.stop_reason=="string"&&(e.finishReason=t.stop_reason),typeof t.stop_sequence=="string"&&(e.stopSequence=t.stop_sequence),Array.isArray(t.content)){let n=t.content.filter(o=>!!o&&typeof o=="object"&&o.type==="tool_use").map(o=>String(o.name??"")).filter(o=>o.length>0);n.length>0&&(e.toolCalls=n)}return e}function qnt(r){let e={};r.model&&(e.responseModel=r.model),r.stopReason&&(e.finishReason=r.stopReason),r.stopSequence&&(e.stopSequence=r.stopSequence);let t=(r.contentBlocks??[]).filter(n=>n.type==="tool_use").map(n=>String(n.toolName??"")).filter(n=>n.length>0);return t.length>0&&(e.toolCalls=t),e}function Fan(r,e,t,n,o){try{let s=JSON.parse(r),i={type:"text",text:t?.body?.agentBlock||"You are a Claude agent, built on Anthropic's Claude Agent SDK."};if(s.system){if(typeof s.system=="string"&&(s.system=[{type:"text",text:s.system}]),Array.isArray(s.system)){let l=s.system.findIndex(f=>typeof f.text=="string"&&f.text.includes("x-anthropic-billing-header")),u=s.system.findIndex(f=>typeof f.text=="string"&&f.text.includes("Claude Agent SDK")),d={type:"text",text:lC(s.system[l]?.text??t?.body?.billingHeader)};if(n&&u>=0)l<0&&s.system.unshift(d);else{let f=[l,u].filter(h=>h>=0).sort((h,y)=>y-h);for(let h of f)s.system.splice(h,1);s.system.length>0&&Q3(s,s.system),s.system=[d,i]}}}else{let l={type:"text",text:lC(t?.body?.billingHeader)};s.system=[l,i]}let a=e.substring(0,Math.min(20,e.length)),c=Y3(a,{existingUserId:s.metadata?.user_id??t?.body?.metadataUserId,preferredSessionId:o??t?.body?.sessionId});return s.metadata={...s.metadata,user_id:c.metadataUserId},{bodyStr:JSON.stringify(s),sessionId:c.sessionId}}catch{return{bodyStr:r}}}async function Uan(r,e){if(!r.oauth?.accessToken)return;let t=r.oauth.accessToken,n=r.oauth.refreshToken,o=r.oauth.expiresAt,s=r.email?.trim()||"legacy-default",i=o?o<Date.now():!1,a=()=>({key:oF,label:s,token:t,refreshToken:n,expiresAt:o,type:"oauth",persistTarget:{credPath:e}});if(!i)return a();let c=Vf(oF);if(c.permanentlyDisabled)return;let l=(await pJ())[oF];if(l?.coolingUntil>Date.now()&&(!c.coolingUntil||l.coolingUntil>c.coolingUntil)&&(c.coolingUntil=l.coolingUntil,c.coolingReason=l.reason),c.coolingReason==="auth"&&c.coolingUntil&&c.coolingUntil>Date.now())return a();if(!n){g.always("[proxy] skipping legacy account (expired, no refresh token)"),await mw(a(),c,"missing_refresh_token");return}let u={token:t,refreshToken:n,expiresAt:o,label:s},d=await vve(u);if(!d.success){if(pw(d)){await mw(a(),c,"refresh_invalid");return}let p=await VJ(a(),c);return g.always(`[proxy] legacy refresh temporarily unavailable (${d.status??"network"}); cooling until ${new Date(p).toISOString()}`),a()}return t=u.token,n=u.refreshToken,o=u.expiresAt,await DJ(e,u),await qJ(a(),c),g.always("[proxy] refreshed legacy account at startup"),a()}async function $an(r){let{ctx:e,body:t,route:n,modelRouter:o,tracer:s,requestStartTime:i,logProxyBody:a}=r;s?.setMode("full");let c=hJ(t),l=bA({provider:n.provider,model:n.model},o?.getFallbackChain()??[],t.model,c);Hnt(a,"translated_request",l);let u=l.attempts;if(t.stream)return AJ({ctx:e,format:"claude",requestModel:t.model,parsed:c,attempts:u,tracer:s,requestStartTime:i});try{return await IJ({ctx:e,format:"claude",requestModel:t.model,parsed:c,attempts:u,tracer:s,requestStartTime:i,terminalFailureStatus:502})}catch(d){let p=d instanceof Error?d.message:"unknown error";g.error(`[claude-proxy] Translated generation failed for ${t.model}: ${p}`);let f=ld(502,`Generation failed: ${p}`),h=JSON.stringify(f);return a({phase:"client_response",headers:{"content-type":"application/json"},body:h,bodySize:Buffer.byteLength(h,"utf8"),contentType:"application/json",account:"translation",accountType:"translation",responseStatus:502,durationMs:Date.now()-i}),f}}function Hnt(r,e,t){r({phase:"routing_decision",contentType:"application/json",body:{stage:e,attempts:t.attempts}})}async function Ban(r){let{ctx:e,body:t,clientRequestBody:n,tracer:o,requestStartTime:s,logProxyBody:i,logFinalRequest:a}=r;o?.setMode("passthrough-cli");let c=n,l=Array.isArray(t.tools)?t.tools.length:0,u={};for(let[h,y]of Object.entries(e.headers))!jJ.has(h.toLowerCase())&&y&&(u[h]=y);u["content-type"]||(u["content-type"]="application/json");let d=o?.startUpstreamAttempt({account:"passthrough",attempt:1,polyfillHeaders:!1,polyfillBody:!1,upstreamUrl:"https://api.anthropic.com/v1/messages?beta=true"});o?.logUpstreamRequestHeaders(u),o?.logUpstreamRequestBody(c),i({phase:"upstream_request",headers:u,body:c,bodySize:Buffer.byteLength(c,"utf8"),contentType:u["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,metadata:{upstreamMethod:"POST",upstreamUrl:"https://api.anthropic.com/v1/messages?beta=true"}}),uw("passthrough","passthrough");let p;try{p=await fetch("https://api.anthropic.com/v1/messages?beta=true",{method:"POST",headers:u,body:c,signal:AbortSignal.timeout(Rve)})}catch(h){let y=h instanceof Error?h.message:String(h);ao("passthrough","passthrough",502),o?.setError("network_error",y),d?.end(),o?.end(502,Date.now()-s),a(502,"passthrough","passthrough","network_error",y);let x=ld(502,`Passthrough fetch failed: ${y}`),b=JSON.stringify(x);return i({phase:"client_response",headers:{"content-type":"application/json"},body:b,bodySize:Buffer.byteLength(b,"utf8"),contentType:"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:502,durationMs:Date.now()-s}),x}let f={};if(p.headers.forEach((h,y)=>{f[y]=h}),o?.logUpstreamResponseHeaders(f),!p.ok){let h=await p.text();ao("passthrough","passthrough",p.status,p.status===429?"quota":void 0),o?.logUpstreamResponseBody(h),i({phase:"upstream_response",headers:f,body:h,bodySize:Buffer.byteLength(h,"utf8"),contentType:f["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:p.status,durationMs:Date.now()-s}),i({phase:"client_response",headers:f,body:h,bodySize:Buffer.byteLength(h,"utf8"),contentType:f["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:p.status,durationMs:Date.now()-s}),d?.end(),o?.setError("api_error",h.slice(0,500)),o?.end(p.status,Date.now()-s),a(p.status,"passthrough","passthrough",p.status===429?"rate_limit_error":"api_error",h);try{return JSON.parse(h)}catch{return ld(p.status,h)}}return t.stream&&p.body?jan({ctx:e,body:t,bodyStr:c,response:p,tracer:o,requestStartTime:s,toolCount:l,upstreamSpan:d,upstreamResponseHeaders:f,logProxyBody:i,logFinalRequest:a}):Gan({ctx:e,body:t,bodyStr:c,response:p,tracer:o,requestStartTime:s,toolCount:l,upstreamSpan:d,upstreamResponseHeaders:f,logProxyBody:i,logFinalRequest:a})}function zan(r){let e=r.getReader(),t=gve(),n=!1;return{stream:new ReadableStream({async pull(s){if(!n)try{let{done:i,value:a}=await e.read();if(n)return;if(i){n=!0,t.complete(),s.close();return}s.enqueue(a)}catch(i){n=!0;let a=i instanceof Error?i.message:String(i);t.fail(a),s.error(i)}},cancel(s){return n=!0,t.cancel(),e.cancel(s)}}),outcome:t.outcome}}async function jan(r){let{bodyStr:e,response:t,tracer:n,requestStartTime:o,upstreamSpan:s,upstreamResponseHeaders:i,logProxyBody:a,logFinalRequest:c}=r,l={...i},{stream:u,capture:d}=dve(),p=t.body;if(!p)throw ao("passthrough","passthrough",502),new Error("Expected passthrough stream response body");let f=zan(p),h=f.stream,y=!1,x=(T,S,E,C)=>y?!1:(y=!0,S==="stream_error"&&ao("passthrough","passthrough",T),c(T,"passthrough","passthrough",S,E,C),!0);if(n)try{let{stream:T,telemetry:S}=bF({captureRawText:!0});h=h.pipeThrough(T);let E=n,C=s,R=t,P=e.length;Promise.all([S,d,f.outcome]).then(([A,I,M])=>{let O=vF(M,A.streamErrorMessage),F=Db(O);E.setUsage({inputTokens:A.usage.inputTokens,outputTokens:A.usage.outputTokens,cacheCreationTokens:A.usage.cacheCreationInputTokens,cacheReadTokens:A.usage.cacheReadInputTokens}),E.logStreamEvents(A.events),E.setResponseInfo(qnt(A));let N=parseFloat(R.headers.get("anthropic-ratelimit-unified-5h-utilization")??""),z=parseFloat(R.headers.get("anthropic-ratelimit-unified-7d-utilization")??""),$={inputTokens:A.usage.inputTokens,outputTokens:A.usage.outputTokens,cacheCreationTokens:A.usage.cacheCreationInputTokens,cacheReadTokens:A.usage.cacheReadInputTokens};isNaN(N)||($.rateLimitAfter5h=N),isNaN(z)||($.rateLimitAfter7d=z),(!isNaN(N)||!isNaN(z))&&E.setUsage($),E.logUpstreamResponseBody(A.rawText??""),E.recordMetrics(),E.recordBodySizes(P,A.totalBytesReceived),C?.end(),F&&E.setError(F.errorType,F.message),E.end(F?.status??t.status,Date.now()-o),x(F?.status??t.status,F?.errorType,F?.message,{inputTokens:A.usage.inputTokens,outputTokens:A.usage.outputTokens,cacheCreationTokens:A.usage.cacheCreationInputTokens,cacheReadTokens:A.usage.cacheReadInputTokens}),a({phase:"upstream_response",headers:l,body:A.rawText??"",bodySize:A.totalBytesReceived,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:200,durationMs:Date.now()-o}),a({phase:"client_response",headers:l,body:I.text,bodySize:I.totalBytes,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:200,durationMs:Date.now()-o})}).catch(A=>{if(y)return;let I=A instanceof Error?A.message:String(A);E.setError("stream_telemetry_error",I),C?.end(),E.end(500,Date.now()-o),x(500,"stream_telemetry_error",I)})}catch{f.outcome.then(T=>{let S=Db(T);s?.end(),S&&n.setError(S.errorType,S.message),n.end(S?.status??t.status,Date.now()-o),x(S?.status??t.status,S?.errorType,S?.message)})}else try{let{stream:T,telemetry:S}=bF({captureRawText:!0});h=h.pipeThrough(T),Promise.all([S,d,f.outcome]).then(([E,C,R])=>{let P=vF(R,E.streamErrorMessage),A=Db(P);x(A?.status??t.status,A?.errorType,A?.message,{inputTokens:E.usage.inputTokens,outputTokens:E.usage.outputTokens,cacheCreationTokens:E.usage.cacheCreationInputTokens,cacheReadTokens:E.usage.cacheReadInputTokens}),a({phase:"upstream_response",headers:l,body:E.rawText??"",bodySize:E.totalBytesReceived,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o}),a({phase:"client_response",headers:l,body:C.text,bodySize:C.totalBytes,contentType:l["content-type"]??"text/event-stream",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o})}).catch(E=>{y||x(500,"stream_telemetry_error",E instanceof Error?E.message:String(E))})}catch{f.outcome.then(T=>{let S=Db(T);x(S?.status??t.status,S?.errorType,S?.message)})}let b=h.pipeThrough(u);return new Response(b,{status:t.status,headers:l})}async function Gan(r){let{bodyStr:e,response:t,tracer:n,requestStartTime:o,upstreamSpan:s,upstreamResponseHeaders:i,logProxyBody:a,logFinalRequest:c}=r,l=await t.text();n?.logUpstreamResponseBody(l),a({phase:"upstream_response",headers:i,body:l,bodySize:Buffer.byteLength(l,"utf8"),contentType:i["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o}),a({phase:"client_response",headers:i,body:l,bodySize:Buffer.byteLength(l,"utf8"),contentType:i["content-type"]??"application/json",account:"passthrough",accountType:"passthrough",attempt:1,responseStatus:t.status,durationMs:Date.now()-o});let u=JSON.parse(l);if(n&&u&&typeof u=="object"){let d=u.usage;if(d){n.setUsage({inputTokens:d.input_tokens??0,outputTokens:d.output_tokens??0,cacheCreationTokens:d.cache_creation_input_tokens??0,cacheReadTokens:d.cache_read_input_tokens??0});let f=parseFloat(t.headers.get("anthropic-ratelimit-unified-5h-utilization")??""),h=parseFloat(t.headers.get("anthropic-ratelimit-unified-7d-utilization")??"");if(!isNaN(f)||!isNaN(h)){let y={inputTokens:d.input_tokens??0,outputTokens:d.output_tokens??0,cacheCreationTokens:d.cache_creation_input_tokens??0,cacheReadTokens:d.cache_read_input_tokens??0};isNaN(f)||(y.rateLimitAfter5h=f),isNaN(h)||(y.rateLimitAfter7d=h),n.setUsage(y)}}n.setResponseInfo(Nve(u)),n.recordMetrics();let p=JSON.stringify(u);n.recordBodySizes(e.length,p.length),s?.end(),n.end(t.status,Date.now()-o),c(t.status,"passthrough","passthrough",void 0,void 0,{inputTokens:d?.input_tokens,outputTokens:d?.output_tokens,cacheCreationTokens:d?.cache_creation_input_tokens,cacheReadTokens:d?.cache_read_input_tokens})}else s?.end(),n?.end(t.status,Date.now()-o),c(t.status,"passthrough","passthrough");return u}async function Van(r){let{ctx:e,body:t,tracer:n,requestStartTime:o,accountStrategy:s,primaryAccountKey:i,accountAllowlist:a,quotaRoutingEnabled:c=Pve(),sessionSoftLimit:l=Mve(),sessionResetToleranceMs:u=Ove(),buildLoggedClaudeError:d,setRoutingDecision:p}=r,f=await Promise.resolve().then(()=>(Zn(),_c)),h=await Promise.resolve().then(()=>(xp(),jP)),y=[],x=`${h.homedir()}/.neurolink/anthropic-credentials.json`,{tokenStore:b}=await Promise.resolve().then(()=>(OJ(),yve)),T=await pJ();Pnt||(await b.pruneExpired(),Pnt=!0);let S=await b.listByPrefix("anthropic:");for(let N of S){if(!Hbe(N,a)){g.debug(`[proxy] skipping account=${N} (not in account allowlist)`);continue}if(await b.isDisabled(N)){let X=Vf(N);if(await b.getDisabledReason(N)==="refresh_failed")await b.markEnabled(N),g.always(`[proxy] account=${N.split(":")[1]??N} re-enabled for legacy refresh failure recheck`),X.permanentlyDisabled=!1,X.consecutiveRefreshFailures=0;else{g.debug(`[proxy] skipping disabled account=${N.split(":")[1]??N}`),X.permanentlyDisabled=!0;continue}}let z=await b.loadTokens(N);if(!z)continue;let $=z.accessToken,U=z.refreshToken,B=z.expiresAt,j=N.split(":")[1]??N,K=z.tokenType==="Bearer"?"oauth":"api_key",Y=Vf(N),G=T[N];G?.coolingUntil>Date.now()&&(!Y.coolingUntil||G.coolingUntil>Y.coolingUntil)&&(Y.coolingUntil=G.coolingUntil,Y.coolingReason=G.reason);let ne=()=>{y.push({key:N,label:j,token:$,refreshToken:U,expiresAt:B,type:K,persistTarget:{providerKey:N}})};if(B?B<Date.now():!1){if(Y.permanentlyDisabled)continue;if(Y.coolingReason==="auth"&&Y.coolingUntil&&Y.coolingUntil>Date.now()){ne();continue}if(!U){g.always(`[proxy] skipping account=${j} (expired, no refresh token)`),await mw({key:N,label:j,token:$,type:"oauth"},Y,"missing_refresh_token");continue}let X={token:$,refreshToken:U,expiresAt:B,label:j},se=await NJ(X,{providerKey:N});if(!se.success){let ue={key:N,label:j,token:$,type:"oauth"};if(pw(se))g.always(`[proxy] skipping account=${j} (refresh token rejected: ${se.error?.slice(0,200)??"unknown"})`),await mw(ue,Y,"refresh_invalid");else{let Ge=await VJ(ue,Y);g.always(`[proxy] account=${j} refresh temporarily unavailable (${se.status??"network"}); cooling until ${new Date(Ge).toISOString()} and rotating`),ne()}continue}$=X.token,U=X.refreshToken,B=X.expiresAt,await b.saveTokens(N,{accessToken:$,refreshToken:U,expiresAt:B??Date.now()+36e5,tokenType:"Bearer"}),g.always(`[proxy] refreshed expired account=${N.split(":")[1]??N} at startup`),await qJ({key:N},Y)}ne()}if(y.length===0&&Wbe(S.length,oF,a))try{let N=JSON.parse(f.readFileSync(x,"utf8")),z=await Uan(N,x);z&&y.push(z)}catch{}if(process.env.ANTHROPIC_API_KEY&&y.length===0&&Wbe(S.length,qbe,a)&&y.push({key:qbe,label:"env",token:process.env.ANTHROPIC_API_KEY,type:"api_key"}),y.length===0){let N=a?"No allowed Anthropic credentials are currently available":S.length>0?"Configured Anthropic accounts are disabled or unavailable":"No Anthropic credentials found";return n?.setError("authentication_error",N),n?.end(401,Date.now()-o),{response:d(401,N)}}for(let N of y)acn(N);await Ean(y);let E=y.filter(N=>!Vf(N.key).permanentlyDisabled);if(E.length===0){let N=HJ(y.map(z=>z.label));return n?.setError("authentication_error",N),n?.end(401,Date.now()-o),{response:d(401,N)}}let C=Can({enabledAccounts:E,accountStrategy:s,primaryAccountKey:i,quotaRoutingEnabled:c,sessionSoftLimit:l,sessionResetToleranceMs:u,setRoutingDecision:p}),R=pcn(t),P=JSON.stringify(R),A=Date.now(),I=Array.isArray(t.tools)?t.tools.length:0,M="https://api.anthropic.com/v1/messages?beta=true",O=e.headers??{},F=Gnt(t);return{accounts:y,enabledAccounts:E,orderedAccounts:C,bodyStr:P,requestStart:A,toolCount:I,url:M,clientHeaders:O,isClaudeClientRequest:Vnt(O,F)}}async function qan(r){let{ctx:e,body:t,tracer:n,requestStartTime:o,logProxyBody:s,logFinalRequest:i,options:a,providerLabel:c}=r,l=new AbortController,u;try{u=await kt(e.neurolink.stream({...a,abortSignal:l.signal}),UJ,`Fallback ${c} initialization timed out after ${UJ}ms`)}catch(x){throw l.abort(x),x}let d=async x=>{let b=u.stream[Symbol.asyncIterator](),T="";try{for(;;){let{value:S,done:E}=await kt(b.next(),UJ,`Fallback ${c} stream timed out after ${UJ}ms of inactivity`);if(E)return T;let C=CJ(S);C&&(T+=C,x?.(C))}}catch(S){throw l.abort(S),b.return?.().catch(()=>{}),S}};if(t.stream){let x=new lA(t.model,0),b=[];for(let A of x.start())b.push(A);let T=await d(A=>{for(let I of x.pushDelta(A))b.push(I)}),S=u.toolCalls??[];if(!gF(T,S))throw new Error(`Translated provider ${c} returned no content or tool calls`);if(S.length)for(let A of S){let I=A.toolName??A.name??"unknown";for(let M of x.pushToolUse(cF(),I,sve(A)))b.push(M)}let E=u.finishReason??"end_turn",C=dw(u.usage);for(let A of x.finish(C.output,E))b.push(A);n?.end(200,Date.now()-o),i(200,"",c,void 0,void 0,{inputTokens:C.input,outputTokens:C.output});let R=b.join("");s({phase:"client_response",headers:{"content-type":"text/event-stream"},body:R,bodySize:Buffer.byteLength(R,"utf8"),contentType:"text/event-stream",responseStatus:200,durationMs:Date.now()-o});async function*P(){for(let A of b)yield A}return P()}let p=await d();if(!gF(p,u.toolCalls))throw new Error(`Translated provider ${c} returned no content or tool calls`);let f={content:p,model:u.model,finishReason:u.finishReason??"end_turn",reasoning:void 0,usage:u.usage?dw(u.usage):void 0,toolCalls:u.toolCalls};n?.end(200,Date.now()-o);let h=yJ(f,t.model);i(200,"",c,void 0,void 0,{inputTokens:f.usage?.input,outputTokens:f.usage?.output});let y=JSON.stringify(h);return s({phase:"client_response",headers:{"content-type":"application/json"},body:y,bodySize:Buffer.byteLength(y,"utf8"),contentType:"application/json",responseStatus:200,durationMs:Date.now()-o}),h}async function Wnt(r){let e;for(let t=0;t<=Tve;t+=1)try{return await qan(r)}catch(n){if(e=n,!Dve(n)||t===Tve)throw n;let o=_ve[t]??250;g.always(`[proxy] retrying fallback=${r.providerLabel} after transient network error (${t+1}/${Tve}) in ${o}ms: ${wA(n)}`),await TA(o)}throw e}async function Han(r){let{ctx:e,body:t,parsedFallbackRequest:n,modelRouter:o,tracer:s,requestStartTime:i,logProxyBody:a,logFinalRequest:c}=r,l=o?.getFallbackChain()??[],u=bA({provider:"anthropic",model:t.model},l,t.model,n);a({phase:"routing_decision",contentType:"application/json",body:{stage:"anthropic_fallback",attempts:u.attempts.slice(1)}}),s?.setFallbackInfo({triggered:!0,attemptCount:u.attempts.slice(1).length,reason:"all_anthropic_accounts_exhausted"});let d;for(let p of u.attempts.slice(1)){if(!p.provider||!p.model)continue;let f=await wf.checkFallbackProviderAvailability(p.provider,p.model);f.available||g.always(`[proxy] fallback ${p.provider}/${p.model} health-check failed (${f.reason??"provider unavailable"}), attempting anyway`);let h=Date.now();try{g.always(`[proxy] fallback \u2192 ${p.provider}/${p.model}`);let y=Qnt(n,{provider:p.provider,model:p.model}),x=await Wnt({ctx:e,body:t,tracer:s,requestStartTime:i,logProxyBody:a,logFinalRequest:c,options:y,providerLabel:p.provider});return yF({provider:p.provider,model:p.model,status:"success",durationMs:Date.now()-h}),s?.setFallbackInfo({triggered:!0,provider:p.provider,model:p.model,attemptCount:u.attempts.slice(1).length,reason:"fallback_success"}),{response:x}}catch(y){let x=y instanceof Error?y.message:String(y),b="unknown";x.includes("Rate limit")||x.includes("rate_limit")||x.includes("max_parallel_requests")?b="rate_limit":x.includes("context length")||x.includes("ContextWindowExceeded")?b="context_overflow":x.includes("no content or tool calls")||x.includes("NoOutputGenerated")?b="empty_response":x.includes("thinking_level")||x.includes("Field required")?b="schema_mismatch":x.includes("Resource exhausted")&&(b="provider_quota"),g.always(`[proxy] fallback ${p.provider}/${p.model} failed [${b}]: ${wA(y)}`),yF({provider:p.provider,model:p.model,status:"failure",errorMessage:`[${b}] ${x}`,durationMs:Date.now()-h}),d=`[${p.provider}/${p.model}] ${wA(y)}`}}return{response:null,lastErrorMessage:d}}async function Wan(r){let{ctx:e,body:t,tracer:n,requestStartTime:o,logProxyBody:s,logFinalRequest:i}=r,a=Date.now();try{let c=hJ(t),l=bA({provider:"anthropic",model:t.model},[],t.model,c);if(Hnt(s,"auto_fallback",l),!l.attempts.find(f=>f.label==="auto-provider"))return{response:null};g.always("[proxy] fallback \u2192 auto-provider");let d=Qnt(c),p=await Wnt({ctx:e,body:t,tracer:n,requestStartTime:o,logProxyBody:s,logFinalRequest:i,options:d,providerLabel:"auto-provider"});return yF({provider:"auto-provider",model:t.model,status:"success",durationMs:Date.now()-a}),n?.setFallbackInfo({triggered:!0,provider:"auto-provider",model:t.model,attemptCount:1,reason:"fallback_success"}),{response:p}}catch(c){let l=wA(c);return g.always(`[proxy] fallback auto-provider failed: ${l}`),yF({provider:"auto-provider",model:t.model,status:"failure",errorMessage:l,durationMs:Date.now()-a}),n?.setFallbackInfo({triggered:!0,provider:"auto-provider",model:t.model,attemptCount:1,reason:"fallback_failure"}),{response:null,lastErrorMessage:l}}}function Kan(r){let{tracer:e,requestStartTime:t,authFailureMessage:n,authCooldownMessage:o,invalidRequestFailure:s,sawNetworkError:i,sawTransientFailure:a,sawRateLimit:c,lastError:l,fallbackFailureMessage:u,orderedAccounts:d,buildLoggedClaudeError:p,logProxyBody:f,logFinalRequest:h}=r;if(n&&!c)return e?.setError("authentication_error",n),e?.end(401,Date.now()-t),p(401,n);if(o&&!c)return e?.setError("token_refresh_unavailable",o),e?.end(503,Date.now()-t),p(503,o,"token_refresh_unavailable");if(s){e?.setError("invalid_request_error",bo(s.body)),e?.end(s.status,Date.now()-t);try{let P=JSON.parse(s.body);return h(s.status,"","final","invalid_request_error",bo(s.body)),f({phase:"client_response",headers:{"content-type":s.contentType??"application/json"},body:s.body,bodySize:Buffer.byteLength(s.body,"utf8"),contentType:s.contentType??"application/json",responseStatus:s.status,durationMs:Date.now()-t}),P}catch{return p(s.status,bo(s.body),"invalid_request_error")}}if((i||a)&&!c){let P=u?` Fallback also failed: ${u}`:"",A=`All Anthropic accounts failed due to transient upstream/network errors. Last error: ${l instanceof Error?l.message:String(l??"unknown")}.${P}`;return e?.setError("transient_error",A.slice(0,500)),e?.end(502,Date.now()-t),p(502,A,u?"fallback_exhausted":"transient_error")}if(!c){let P=u?` Fallback also failed: ${u}`:"",A=`All Anthropic accounts failed. Last error: ${l instanceof Error?l.message:String(l??"unknown")}.${P}`;return e?.setError("all_accounts_failed",A.slice(0,500)),e?.end(502,Date.now()-t),p(502,A,u?"fallback_exhausted":"all_accounts_failed")}let y=Date.now(),x=d.map(P=>Vf(P.key)).filter(P=>P.coolingUntil&&P.coolingUntil>y&&P.coolingReason!=="auth"),b=Math.min(...x.map(P=>P.coolingUntil??Number.POSITIVE_INFINITY)),T=d.length>0&&x.length===d.length,S=T?Math.max(1,Math.ceil((b-y)/1e3)):1,E=T?`All ${d.length} Anthropic accounts are cooling after upstream rate limits. Earliest retry at ${new Date(b).toISOString()}.`:`All ${d.length} accounts rate-limited after per-account retries.`;g.always(`[proxy] all accounts rate-limited, retry in ${S}s`);let C=ld(429,E,"overloaded_error");e?.setError("rate_limit_error",E),e?.end(429,Date.now()-t),h(429,"","final","rate_limit_error",E);let R=JSON.stringify(C);return f({phase:"client_response",headers:{"content-type":"application/json","retry-after":String(S)},body:R,bodySize:Buffer.byteLength(R,"utf8"),contentType:"application/json",responseStatus:429,durationMs:Date.now()-t}),new Response(R,{status:429,headers:{"content-type":"application/json","retry-after":String(S)}})}async function Knt(r){let{ctx:e,body:t,account:n,accountState:o,response:s,tracer:i,requestStartTime:a,fetchStartMs:c,attemptNumber:l,finalBodyStr:u,upstreamSpan:d,logAttempt:p,logProxyBody:f,logFinalRequest:h}=r;o.consecutiveRefreshFailures=0,g.always(`[proxy] \u2190 ${s.status} account=${n.label}`);let y=cA(s.headers);if(y){if(o.quota=y,$nt(o,y,Date.now())){let{coolingUntil:b,coolingReason:T}=o;b!==void 0&&T!==void 0&&aw(n.key,b,T).catch(()=>{})}aF(n.label,y).catch(()=>{})}let x={};return s.headers.forEach((b,T)=>{x[T]=b}),i?.logUpstreamResponseHeaders(x),t.stream?Jan({ctx:e,body:t,account:n,accountState:o,response:s,responseHeaders:x,tracer:i,requestStartTime:a,fetchStartMs:c,attemptNumber:l,finalBodyStr:u,upstreamSpan:d,logAttempt:p,logProxyBody:f,logFinalRequest:h}):Xan({account:n,response:s,responseHeaders:x,tracer:i,requestStartTime:a,fetchStartMs:c,attemptNumber:l,finalBodyStr:u,upstreamSpan:d,logAttempt:p,logProxyBody:f,logFinalRequest:h})}async function Jan(r){let{account:e,accountState:t,response:n,responseHeaders:o,tracer:s,requestStartTime:i,fetchStartMs:a,attemptNumber:c,finalBodyStr:l,upstreamSpan:u,logAttempt:d,logProxyBody:p,logFinalRequest:f}=r;if(!n.body){ao(e.label,e.type,502),d(502,"stream_error","No response body from upstream"),u?.end(),s?.setError("stream_error","No response body from upstream"),s?.end(502,Date.now()-i),f(502,e.label,e.type,"stream_error","No response body from upstream");let E=ld(502,"No response body from upstream"),C=JSON.stringify(E);return p({phase:"client_response",headers:{"content-type":"application/json"},body:C,bodySize:Buffer.byteLength(C,"utf8"),contentType:"application/json",account:e.label,accountType:e.type,attempt:c,responseStatus:502,durationMs:Date.now()-i}),{response:E}}let h=n.body.getReader(),y=await Snt(h);if(y.kind==="transport_error"){let E=wA(y.error),C=Buffer.concat(y.chunks.map(R=>Buffer.from(R))).toString("utf8");return g.always(`[proxy] stream failed before first chunk account=${e.label}: ${E}; trying next account`),ao(e.label,e.type,502),d(502,"stream_error",E,{retryable:!0}),s?.recordRetry(e.label,"stream_before_first_chunk"),u?.end(),p({phase:"upstream_response",headers:o,body:C,bodySize:Buffer.byteLength(C,"utf8"),contentType:o["content-type"]??"text/event-stream",account:e.label,accountType:e.type,attempt:c,responseStatus:n.status,durationMs:Date.now()-a,metadata:{logicalStatus:502,transportError:E}}),{retryNextAccount:!0,failure:{message:E,rateLimit:!1}}}if(y.kind==="empty")return await h.cancel().catch(()=>{}),g.always(`[proxy] \u2190 empty stream from account=${e.label}, trying next`),ao(e.label,e.type,502),d(502,"empty_stream","Empty upstream stream",{retryable:!0}),s?.recordRetry(e.label,"empty_stream"),u?.end(),p({phase:"upstream_response",headers:o,body:"",bodySize:0,contentType:o["content-type"]??"text/event-stream",account:e.label,accountType:e.type,attempt:c,responseStatus:n.status,durationMs:Date.now()-a,metadata:{logicalStatus:502,upstreamErrorType:"empty_stream"}}),{retryNextAccount:!0,failure:{message:"Empty upstream stream",rateLimit:!1}};if(y.kind==="sse_error"){await h.cancel().catch(()=>{});let E=Buffer.concat(y.chunks.map(I=>Buffer.from(I))).toString("utf8"),C=y.errorType==="rate_limit_error",R=C?429:502,P=cA(o),A=Date.now();if(C){let I=Ave(P,LJ(o["retry-after"]??null),A,iF(o));t.quota=P??t.quota;let M=I.reason==="transient"?"transient":"quota";(!t.coolingUntil||I.coolingUntil>t.coolingUntil)&&(t.coolingUntil=I.coolingUntil,t.coolingReason=I.reason,await aw(e.key,I.coolingUntil,I.reason).catch(()=>{})),ao(e.label,e.type,429,M),d(429,"rate_limit_error",y.message,{retryable:!0,rateLimitKind:M,cooldownReason:I.reason})}else ao(e.label,e.type,R),d(R,y.errorType,y.message,{retryable:!0});return g.always(`[proxy] immediate SSE ${y.errorType} account=${e.label}: ${y.message}; rotating before client commit`),s?.recordRetry(e.label,C?"stream_rate_limit_before_commit":"stream_error_before_commit"),u?.end(),p({phase:"upstream_response",headers:o,body:E,bodySize:Buffer.byteLength(E,"utf8"),contentType:o["content-type"]??"text/event-stream",account:e.label,accountType:e.type,attempt:c,responseStatus:n.status,durationMs:Date.now()-a,metadata:{logicalStatus:R,upstreamErrorType:y.errorType}}),{retryNextAccount:!0,failure:{message:y.message,rateLimit:C}}}d(n.status,void 0,void 0,{attemptDurationMs:Date.now()-a});let x=gve(),b=!1,T=new ReadableStream({start(E){for(let C of y.chunks)E.enqueue(C)},async pull(E){if(!b)try{let{done:C,value:R}=await h.read();if(b)return;if(C){b=!0,x.complete(),E.close();return}E.enqueue(R)}catch(C){let R=wA(C);if(g.always(`[proxy] mid-stream error account=${e.label}: ${R}`),x.fail(R),!b){b=!0;let P=`event: error
|
|
2470
2470
|
data: ${JSON.stringify({type:"error",error:{type:"api_error",message:`Upstream stream interrupted: ${R}`}})}
|
|
2471
2471
|
|
|
2472
2472
|
`;E.enqueue(new TextEncoder().encode(P)),E.close()}}},cancel(){return b=!0,x.cancel(),h.cancel()}});return{response:Yan({account:e,response:n,responseHeaders:o,remainingStream:T,streamOutcome:x.outcome,tracer:s,requestStartTime:i,attemptNumber:c,finalBodyStr:l,upstreamSpan:u,logProxyBody:p,logFinalRequest:f})}}function Db(r){if(r.kind==="upstream_error")return{status:502,errorType:"stream_error",message:r.message};if(r.kind==="client_cancelled")return{status:499,errorType:"client_cancelled",message:"Client cancelled the streaming response"}}function $J(r,e){r.kind==="upstream_error"&&ao(e.label,e.type,502)}function Yan(r){let{account:e,response:t,responseHeaders:n,remainingStream:o,streamOutcome:s,tracer:i,requestStartTime:a,attemptNumber:c,finalBodyStr:l,upstreamSpan:u,logProxyBody:d,logFinalRequest:p}=r,{stream:f,capture:h}=dve(),y=o;if(i)try{let{stream:T,telemetry:S}=bF({captureRawText:!0});y=y.pipeThrough(T);let E=i,C=u,R=t,P=l.length,A=e.label;Promise.all([S,h,s]).then(([I,M,O])=>{let F=vF(O,I.streamErrorMessage);$J(F,e),E.setUsage({inputTokens:I.usage.inputTokens,outputTokens:I.usage.outputTokens,cacheCreationTokens:I.usage.cacheCreationInputTokens,cacheReadTokens:I.usage.cacheReadInputTokens}),E.logStreamEvents(I.events),E.setResponseInfo(qnt(I));let N=parseFloat(R.headers.get("anthropic-ratelimit-unified-5h-utilization")??""),z=parseFloat(R.headers.get("anthropic-ratelimit-unified-7d-utilization")??""),$={inputTokens:I.usage.inputTokens,outputTokens:I.usage.outputTokens,cacheCreationTokens:I.usage.cacheCreationInputTokens,cacheReadTokens:I.usage.cacheReadInputTokens};isNaN(N)||($.rateLimitAfter5h=N),isNaN(z)||($.rateLimitAfter7d=z),(!isNaN(N)||!isNaN(z))&&E.setUsage($),E.logUpstreamResponseBody(I.rawText??""),E.recordMetrics(),E.recordBodySizes(P,I.totalBytesReceived),C?.end();let U=Db(F),B={inputTokens:I.usage.inputTokens,outputTokens:I.usage.outputTokens,cacheCreationTokens:I.usage.cacheCreationInputTokens,cacheReadTokens:I.usage.cacheReadInputTokens};U?(E.setError(U.errorType,U.message),E.end(U.status,Date.now()-a),p(U.status,A,e.type,U.errorType,U.message,B)):(E.end(200,Date.now()-a),p(200,A,e.type,void 0,void 0,B)),d({phase:"upstream_response",headers:n,body:I.rawText??"",bodySize:I.totalBytesReceived,contentType:n["content-type"]??"text/event-stream",account:A,accountType:e.type,attempt:c,responseStatus:200,durationMs:Date.now()-a}),d({phase:"client_response",headers:n,body:M.text,bodySize:M.totalBytes,contentType:n["content-type"]??"text/event-stream",account:A,accountType:e.type,attempt:c,responseStatus:200,durationMs:Date.now()-a})}).catch(I=>{E.setError("stream_telemetry_error",I instanceof Error?I.message:String(I)),C?.end(),E.end(500,Date.now()-a),p(500,A,e.type,"stream_telemetry_error",I instanceof Error?I.message:String(I))})}catch{s.then(T=>{$J(T,e);let S=Db(T);u?.end(),S?(i.setError(S.errorType,S.message),i.end(S.status,Date.now()-a),p(S.status,e.label,e.type,S.errorType,S.message)):(i.end(t.status,Date.now()-a),p(t.status,e.label,e.type))})}else{u?.end();try{let{stream:T,telemetry:S}=bF({captureRawText:!0});y=y.pipeThrough(T);let E=e.label;Promise.all([S,h,s]).then(([C,R,P])=>{let A=vF(P,C.streamErrorMessage);$J(A,e);let I=Db(A),M={inputTokens:C.usage.inputTokens,outputTokens:C.usage.outputTokens,cacheCreationTokens:C.usage.cacheCreationInputTokens,cacheReadTokens:C.usage.cacheReadInputTokens};I?p(I.status,E,e.type,I.errorType,I.message,M):p(200,E,e.type,void 0,void 0,M),d({phase:"upstream_response",headers:n,body:C.rawText??"",bodySize:C.totalBytesReceived,contentType:n["content-type"]??"text/event-stream",account:E,accountType:e.type,attempt:c,responseStatus:200,durationMs:Date.now()-a}),d({phase:"client_response",headers:n,body:R.text,bodySize:R.totalBytes,contentType:n["content-type"]??"text/event-stream",account:E,accountType:e.type,attempt:c,responseStatus:200,durationMs:Date.now()-a})}).catch(C=>{let R=C instanceof Error?C.message:String(C);p(500,e.label,e.type,"stream_telemetry_error",R)})}catch{h.then(T=>{d({phase:"client_response",headers:n,body:T.text,bodySize:T.totalBytes,contentType:n["content-type"]??"text/event-stream",account:e.label,accountType:e.type,attempt:c,responseStatus:200,durationMs:Date.now()-a})}).catch(()=>{}),s.then(T=>{$J(T,e);let S=Db(T);S?p(S.status,e.label,e.type,S.errorType,S.message):p(t.status,e.label,e.type)})}}let x=y.pipeThrough(f),b={"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"};for(let T of["retry-after","anthropic-ratelimit-requests-remaining","anthropic-ratelimit-requests-limit","anthropic-ratelimit-tokens-remaining","anthropic-ratelimit-tokens-limit"]){let S=t.headers.get(T);S&&(b[T]=S)}return new Response(x,{status:t.status,headers:b})}async function Xan(r){let{account:e,response:t,responseHeaders:n,tracer:o,requestStartTime:s,fetchStartMs:i,attemptNumber:a,finalBodyStr:c,upstreamSpan:l,logAttempt:u,logProxyBody:d,logFinalRequest:p}=r,f=await t.text();u(t.status,void 0,void 0,{attemptDurationMs:Date.now()-i}),o?.logUpstreamResponseBody(f),d({phase:"upstream_response",headers:n,body:f,bodySize:Buffer.byteLength(f,"utf8"),contentType:n["content-type"]??"application/json",account:e.label,accountType:e.type,attempt:a,responseStatus:t.status,durationMs:Date.now()-i}),d({phase:"client_response",headers:n,body:f,bodySize:Buffer.byteLength(f,"utf8"),contentType:n["content-type"]??"application/json",account:e.label,accountType:e.type,attempt:a,responseStatus:t.status,durationMs:Date.now()-s});let h=JSON.parse(f);if(o&&h&&typeof h=="object"){let y=h.usage;if(y){o.setUsage({inputTokens:y.input_tokens??0,outputTokens:y.output_tokens??0,cacheCreationTokens:y.cache_creation_input_tokens??0,cacheReadTokens:y.cache_read_input_tokens??0});let b=parseFloat(t.headers.get("anthropic-ratelimit-unified-5h-utilization")??""),T=parseFloat(t.headers.get("anthropic-ratelimit-unified-7d-utilization")??"");if(!isNaN(b)||!isNaN(T)){let S={inputTokens:y.input_tokens??0,outputTokens:y.output_tokens??0,cacheCreationTokens:y.cache_creation_input_tokens??0,cacheReadTokens:y.cache_read_input_tokens??0};isNaN(b)||(S.rateLimitAfter5h=b),isNaN(T)||(S.rateLimitAfter7d=T),o.setUsage(S)}}o.setResponseInfo(Nve(h)),o.recordMetrics();let x=JSON.stringify(h);o.recordBodySizes(c.length,x.length),l?.end(),o.end(t.status,Date.now()-s),p(t.status,e.label,e.type,void 0,void 0,{inputTokens:y?.input_tokens,outputTokens:y?.output_tokens,cacheCreationTokens:y?.cache_creation_input_tokens,cacheReadTokens:y?.cache_read_input_tokens})}else{l?.end();let y=h&&typeof h=="object"?h.usage:void 0;p(t.status,e.label,e.type,void 0,void 0,{inputTokens:y?.input_tokens,outputTokens:y?.output_tokens,cacheCreationTokens:y?.cache_creation_input_tokens,cacheReadTokens:y?.cache_read_input_tokens})}return{response:h}}async function Zan(r){let{account:e,accountState:t,retryResp:n,tracer:o,requestStartTime:s,fetchStartMs:i,attemptNumber:a,finalBodyStr:c,upstreamSpan:l,logAttempt:u,logProxyBody:d,logFinalRequest:p}=r,f=cA(n.headers);if(f){if(t.quota=f,$nt(t,f,Date.now())){let{coolingUntil:b,coolingReason:T}=t;b!==void 0&&T!==void 0&&aw(e.key,b,T).catch(()=>{})}aF(e.label,f).catch(b=>{g.debug("[proxy] Failed to persist account quota after auth retry",{account:e.label,error:b instanceof Error?b.message:String(b)})})}let h=Object.fromEntries([...n.headers.entries()]),y=await n.text();u(n.status,void 0,void 0,{attemptDurationMs:Date.now()-i}),o?.logUpstreamResponseHeaders(h),o?.logUpstreamResponseBody(y),d({phase:"upstream_response",headers:h,body:y,bodySize:Buffer.byteLength(y,"utf8"),contentType:h["content-type"]??"application/json",account:e.label,accountType:e.type,attempt:a,responseStatus:n.status,durationMs:Date.now()-i}),d({phase:"client_response",headers:h,body:y,bodySize:Buffer.byteLength(y,"utf8"),contentType:h["content-type"]??"application/json",account:e.label,accountType:e.type,attempt:a,responseStatus:n.status,durationMs:Date.now()-s});let x=JSON.parse(y);if(o&&x&&typeof x=="object"){let b=x.usage;b&&o.setUsage({inputTokens:b.input_tokens??0,outputTokens:b.output_tokens??0,cacheCreationTokens:b.cache_creation_input_tokens??0,cacheReadTokens:b.cache_read_input_tokens??0}),o.setResponseInfo(Nve(x)),o.recordMetrics();let T=JSON.stringify(x);o.recordBodySizes(c.length,T.length),l?.end(),o.end(n.status,Date.now()-s),p(n.status,e.label,e.type,void 0,void 0,{inputTokens:b?.input_tokens,outputTokens:b?.output_tokens,cacheCreationTokens:b?.cache_creation_input_tokens,cacheReadTokens:b?.cache_read_input_tokens})}else l?.end(),p(n.status,e.label,e.type);return x}async function Qan(r){let{ctx:e,body:t,account:n,accountState:o,headers:s,buildUpstreamBody:i,url:a,enabledAccounts:c,orderedAccounts:l,tracer:u,requestStartTime:d,allocateAttemptNumber:p,upstreamSpan:f,logAttempt:h,logProxyBody:y,logFinalRequest:x,lastError:b,authFailureMessage:T,sawRateLimit:S,sawTransientFailure:E,sawNetworkError:C}=r;ao(n.label,n.type,401),h(401,"authentication_error","received 401 from Anthropic",{retryable:!0});let R=b,P=T,A=S,I=E,M=C,O=f,F=!1,N="received 401 from Anthropic";for(let z=0;z<TF;z++){g.always(`[proxy] \u2190 401 account=${n.label} refreshing (attempt ${z+1}/${TF})`);let $=await NJ(n,n.persistTarget);if(!$.success){if(N=`refresh failed for account=${n.label} attempt ${z+1}/${TF}: ${$.error?.slice(0,200)??"unknown"}`,R=N,pw($))await mw(n,o,"refresh_invalid"),P=HJ(n.label),g.always(`[proxy] account=${n.label} refresh token rejected; disabled until re-authentication`);else{let G=await VJ(n,o);I=!0,g.always(`[proxy] account=${n.label} refresh temporarily unavailable (${$.status??"network"}); cooling until ${new Date(G).toISOString()} and rotating`)}break}n.persistTarget&&await DJ(n.persistTarget,n),await qJ(n,o),s.authorization=`Bearer ${n.token}`;let U=p(),B=Date.now();uw(n.label,n.type);let j=(G,ne,we,X)=>h(G,ne,we,{...X,attempt:U,attemptDurationMs:X?.attemptDurationMs??Date.now()-B}),K=i(n.token).bodyStr,Y=Date.now();y({phase:"upstream_request",headers:s,body:K,bodySize:Buffer.byteLength(K,"utf8"),contentType:s["content-type"]??"application/json",account:n.label,accountType:n.type,attempt:U,metadata:{upstreamMethod:"POST",upstreamUrl:a}});try{let G=await fetch(a,{method:"POST",headers:s,body:K,signal:AbortSignal.timeout(Rve)});if(G.ok){F=!0,o.consecutiveRefreshFailures=0,g.always(`[proxy] \u2190 200 account=${n.label} (after ${z+1} refresh(es))`);let Ge=t.stream?await Knt({ctx:e,body:t,account:n,accountState:o,response:G,tracer:u,requestStartTime:d,fetchStartMs:Y,attemptNumber:U,finalBodyStr:K,upstreamSpan:O,logAttempt:j,logProxyBody:y,logFinalRequest:x}):{response:await Zan({account:n,accountState:o,retryResp:G,tracer:u,requestStartTime:d,fetchStartMs:Y,attemptNumber:U,finalBodyStr:K,upstreamSpan:O,logAttempt:j,logProxyBody:y,logFinalRequest:x})};if("retryNextAccount"in Ge){let Re=Ge.failure;return{continueLoop:!0,lastError:Re?.message??R,authFailureMessage:P,sawRateLimit:A||!!Re?.rateLimit,sawTransientFailure:I||!!(Re&&!Re.rateLimit),sawNetworkError:M,upstreamSpan:void 0}}return{response:Ge.response,continueLoop:!1,lastError:R,authFailureMessage:P,sawRateLimit:A,sawTransientFailure:I,sawNetworkError:M,upstreamSpan:void 0}}let ne=G.status,we=await G.text(),X={};G.headers.forEach((Ge,Re)=>{X[Re]=Ge});let se={...X};delete se.authorization,delete se["x-api-key"];let ue=we.length>4e3?we.slice(0,4e3)+"...[truncated]":we;if(u?.logUpstreamResponseHeaders(se),u?.logUpstreamResponseBody(ue),y({phase:"upstream_response",headers:se,body:ue,bodySize:Buffer.byteLength(we,"utf8"),contentType:X["content-type"]??"application/json",account:n.label,accountType:n.type,attempt:U,responseStatus:ne,durationMs:Date.now()-Y}),N=`retry ${z+1}/${TF} failed with status ${ne}`,R=we,g.debug(`[proxy] retry ${z+1} failed: ${ne} ${we.substring(0,120)}`),ne===429&&Ynt(X,we))return g.always(`[proxy] \u2190 429 account=${n.label} anti-abuse/construction rejection after OAuth refresh \u2014 returning non-retryable request error`),j(429,"construction_rejection",we),u?.setError("construction_rejection",we.slice(0,500)),O?.end(),{response:Jnt({terminalError:Xnt(),account:n,tracer:u,requestStartTime:d,attemptNumber:U,logProxyBody:y,logFinalRequest:x}),continueLoop:!1,lastError:we,authFailureMessage:P,sawRateLimit:A,sawTransientFailure:I,sawNetworkError:M,upstreamSpan:void 0};if(ne===429){A=!0;let Ge=Date.now(),Re=cA(X);Re&&(o.quota=Re);let me=Ave(Re,LJ(X["retry-after"]??null),Ge,iF(X)),re=me.reason==="transient"?"transient":"quota";ao(n.label,n.type,ne,re),j(429,"rate_limit_error",we,{retryable:!0,rateLimitKind:re,cooldownReason:me.reason}),(!o.coolingUntil||me.coolingUntil>o.coolingUntil)&&(o.coolingUntil=me.coolingUntil,o.coolingReason=me.reason),Re&&aF(n.label,Re).catch(()=>{}),await aw(n.key,o.coolingUntil??me.coolingUntil,o.coolingReason??me.reason).catch(()=>{}),vA(n.key,c.length,l[0]?.key);break}if(ne===401||ne===402||ne===403){ao(n.label,n.type,ne),j(ne,"authentication_error",bo(we),{retryable:!0}),z<TF-1&&await TA(1e3);continue}if(eot(ne,we)){ao(n.label,n.type,ne),j(ne,"api_error",bo(we),{retryable:!0}),I=!0;break}j(ne,"api_error",bo(we));try{return x(ne,n.label,n.type,"api_error",bo(we)),{response:JSON.parse(we),continueLoop:!1,lastError:R,authFailureMessage:P,sawRateLimit:A,sawTransientFailure:I,sawNetworkError:M,upstreamSpan:O}}catch{return x(ne,n.label,n.type,"api_error",bo(we)),{response:ld(ne,we),continueLoop:!1,lastError:R,authFailureMessage:P,sawRateLimit:A,sawTransientFailure:I,sawNetworkError:M,upstreamSpan:O}}}catch(G){M=!0,ao(n.label,n.type,502);let ne=G instanceof Error?G.message:String(G);N=`network error on retry ${z+1}: ${ne}`,R=N,j(502,"network_error",ne,{retryable:Dve(G),errorCode:WJ(G)??"unknown"}),g.debug(`[proxy] ${N}`);break}}return F||(R=N,g.always(`[proxy] \u26A0 account=${n.label} auth retries exhausted, rotating to next account`),u?.setError("authentication_error",N),u?.recordRetry(n.label,"auth_exhausted"),O?.end(),O=void 0,vA(n.key,c.length,l[0]?.key)),{continueLoop:!0,lastError:R,authFailureMessage:P,sawRateLimit:A,sawTransientFailure:I,sawNetworkError:M,upstreamSpan:O}}function Cve(r){let{responseStatus:e,account:t,errBody:n,errRespHeaders:o,requestStartTime:s,attemptNumber:i,logProxyBody:a,logFinalRequest:c,errorType:l}=r;try{let u=JSON.parse(n);return c(e,t.label,t.type,l,bo(n)),a({phase:"client_response",headers:{"content-type":o["content-type"]??"application/json"},body:n,bodySize:Buffer.byteLength(n,"utf8"),contentType:o["content-type"]??"application/json",account:t.label,accountType:t.type,attempt:i,responseStatus:e,durationMs:Date.now()-s}),u}catch{c(e,t.label,t.type,l,bo(n));let u=ld(e,n),d=JSON.stringify(u);return a({phase:"client_response",headers:{"content-type":"application/json"},body:d,bodySize:Buffer.byteLength(d,"utf8"),contentType:"application/json",account:t.label,accountType:t.type,attempt:i,responseStatus:e,durationMs:Date.now()-s}),u}}function Jnt(r){let{terminalError:e,account:t,tracer:n,requestStartTime:o,attemptNumber:s,logProxyBody:i,logFinalRequest:a}=r;return n?.end(e.status,Date.now()-o),Cve({responseStatus:e.status,account:t,errBody:e.body,errRespHeaders:e.headers,requestStartTime:o,attemptNumber:s,logProxyBody:i,logFinalRequest:a,errorType:e.errorType})}async function ecn(r){let{response:e,account:t,accountState:n,enabledAccounts:o,orderedAccounts:s,tracer:i,requestStartTime:a,fetchStartMs:c,attemptNumber:l,logAttempt:u,logProxyBody:d,logFinalRequest:p,lastError:f,authFailureMessage:h,sawTransientFailure:y,invalidRequestFailure:x}=r,b=f,T=h,S=y,E=x,C=await e.text(),R={};return e.headers.forEach((P,A)=>{R[A]=P}),i?.logUpstreamResponseHeaders(R),i?.logUpstreamResponseBody(C),d({phase:"upstream_response",headers:R,body:C,bodySize:Buffer.byteLength(C,"utf8"),contentType:R["content-type"]??"application/json",account:t.label,accountType:t.type,attempt:l,responseStatus:e.status,durationMs:Date.now()-c}),ucn(e.status,C)?dcn(e.status,C)?(g.always(`[proxy] \u2190 ${e.status} account=${t.label} beta unavailable for subscription; advancing to next account`),u(e.status,"invalid_request_error",bo(C)),i?.setError("invalid_request_error",bo(C)),i?.recordRetry(t.label,"beta_unavailable"),vA(t.key,o.length,s[0]?.key),b=bo(C),{continueLoop:!0,lastError:b,authFailureMessage:T,sawTransientFailure:S,invalidRequestFailure:E,upstreamSpan:void 0}):(g.always(`[proxy] \u2190 ${e.status} upstream invalid_request_error`),u(e.status,"invalid_request_error",bo(C)),i?.setError("invalid_request_error",bo(C)),E={status:e.status,body:C,contentType:R["content-type"]},b=bo(C),{continueLoop:!1,lastError:b,authFailureMessage:T,sawTransientFailure:S,invalidRequestFailure:E,upstreamSpan:void 0}):(e.status===401||e.status===402||e.status===403)&&t.type==="oauth"&&!t.refreshToken?(ao(t.label,t.type,e.status),await mw(t,n,"missing_refresh_token"),T=HJ(t.label),g.always(`[proxy] \u2190 ${e.status} account=${t.label} (auth failure, no refresh token)`),b=C,u(e.status,"authentication_error",bo(C)),i?.setError("authentication_error",bo(C)),i?.recordRetry(t.label,"auth_no_refresh"),vA(t.key,o.length,s[0]?.key),{continueLoop:!0,lastError:b,authFailureMessage:T,sawTransientFailure:S,invalidRequestFailure:E,upstreamSpan:void 0}):(e.status===401||e.status===402||e.status===403)&&t.type==="api_key"?(ao(t.label,t.type,e.status),T="Authentication failed for Anthropic API key credentials. Update ANTHROPIC_API_KEY or re-login with OAuth.",g.always(`[proxy] \u2190 ${e.status} account=${t.label} (auth failure, api_key)`),b=C,u(e.status,"authentication_error",bo(C)),i?.setError("authentication_error",bo(C)),i?.recordRetry(t.label,"auth_api_key"),vA(t.key,o.length,s[0]?.key),{continueLoop:!0,lastError:b,authFailureMessage:T,sawTransientFailure:S,invalidRequestFailure:E,upstreamSpan:void 0}):e.status===404?(g.always(`[proxy] \u2190 404 account=${t.label}`),u(404,"not_found_error",bo(C)),i?.setError("not_found_error",bo(C)),i?.end(404,Date.now()-a),{response:Cve({responseStatus:404,account:t,errBody:C,errRespHeaders:R,requestStartTime:a,attemptNumber:l,logProxyBody:d,logFinalRequest:p,errorType:"not_found_error"}),continueLoop:!1,lastError:b,authFailureMessage:T,sawTransientFailure:S,invalidRequestFailure:E,upstreamSpan:void 0}):eot(e.status,C)?(ao(t.label,t.type,e.status,e.status===429?"transient":void 0),S=!0,g.always(`[proxy] \u2190 ${e.status} account=${t.label} (transient)`),b=C,u(e.status,"api_error",bo(C),e.status===429?{retryable:!0,rateLimitKind:"transient",cooldownReason:"transient"}:void 0),i?.setError("transient_error",bo(C)),i?.recordRetry(t.label,"transient"),{continueLoop:!0,retrySameAccount:!0,lastError:b,authFailureMessage:T,sawTransientFailure:S,invalidRequestFailure:E,upstreamSpan:void 0}):(g.always(`[proxy] \u2190 ${e.status} account=${t.label}`),g.debug(`[claude-proxy] error body: ${C.substring(0,200)}`),u(e.status,"api_error",bo(C)),i?.setError("api_error",bo(C)),i?.end(e.status,Date.now()-a),{response:Cve({responseStatus:e.status,account:t,errBody:C,errRespHeaders:R,requestStartTime:a,attemptNumber:l,logProxyBody:d,logFinalRequest:p,errorType:"api_error"}),continueLoop:!1,lastError:b,authFailureMessage:T,sawTransientFailure:S,invalidRequestFailure:E,upstreamSpan:void 0})}function tcn(r){let{ctx:e,body:t,clientRequestBody:n}=r,o;try{o=hA.startRequest({requestId:e.requestId,method:e.method,path:e.path,model:t.model,stream:t.stream??!1,toolCount:Array.isArray(t.tools)?t.tools.length:0,toolNames:Array.isArray(t.tools)?t.tools.map(f=>f&&typeof f=="object"&&"name"in f?String(f.name??""):"").filter(f=>f.length>0):void 0,sessionId:e.headers["x-neurolink-session-id"]??e.headers["x-claude-code-session-id"]??void 0,userAgent:e.headers["user-agent"]??void 0},e.headers);let p=o.startReceive();o.logRequestHeaders(e.headers),o.logRequestBody(n),p.end()}catch{o=void 0}let s=Date.now(),i=p=>{let f=o?.getTraceContext();int({timestamp:new Date().toISOString(),requestId:e.requestId,model:t.model,stream:t.stream??!1,...p,...f?{traceId:f.traceId,spanId:f.spanId}:{}})},a,c=p=>{if(a){g.debug(`[claude-proxy] ignored duplicate routing decision for request ${e.requestId}`);return}a=p},l=!1,u=(p,f,h,y,x,b)=>{if(l){g.debug(`[claude-proxy] ignored duplicate finalization for request ${e.requestId}`);return}l=!0;let T=f||(p>=400?wve:void 0),S=f?h||void 0:p>=400?Eve:void 0;p>=400?gA(p,T,S,{requestId:e.requestId,errorType:y,terminalOutcome:y==="client_cancelled"?"client_cancelled":y?.includes("stream")?"stream_error":"handler_error",message:x}):fF(T,S);let E=o?.getTraceContext();zf({timestamp:new Date().toISOString(),requestId:e.requestId,method:e.method,path:e.path,model:t.model,stream:!!t.stream,toolCount:Array.isArray(t.tools)?t.tools.length:0,account:T??"",accountType:S??"",responseStatus:p,responseTimeMs:Date.now()-s,...y?{errorType:y}:{},...x?{errorMessage:x}:{},...b?.inputTokens!==void 0?{inputTokens:b.inputTokens}:{},...b?.outputTokens!==void 0?{outputTokens:b.outputTokens}:{},...b?.cacheCreationTokens!==void 0?{cacheCreationTokens:b.cacheCreationTokens}:{},...b?.cacheReadTokens!==void 0?{cacheReadTokens:b.cacheReadTokens}:{},...E?{traceId:E.traceId,spanId:E.spanId}:{},...a?{routingDecision:a}:{}})},d=(p,f,h,y)=>{let x=ld(p,f,h),b=JSON.stringify(x);return u(p,y?.account??"",y?.accountType??"final",h,f),i({phase:"client_response",headers:{"content-type":"application/json"},body:b,bodySize:Buffer.byteLength(b,"utf8"),contentType:"application/json",responseStatus:p,durationMs:Date.now()-s,...y}),x};return i({phase:"client_request",headers:e.headers,body:n,bodySize:Buffer.byteLength(n,"utf8"),contentType:e.headers["content-type"]??"application/json"}),{tracer:o,requestStartTime:s,logProxyBody:i,logFinalRequest:u,buildLoggedClaudeError:d,setRoutingDecision:c}}function rcn(r){let{ctx:e,body:t,toolCount:n,requestStart:o,tracer:s,account:i,attemptNumber:a}=r,c=Date.now();return(l,u,d,p)=>{let f=Date.now(),h=s?.getTraceContext();ont({timestamp:new Date().toISOString(),requestId:e.requestId,attempt:p?.attempt??a,method:e.method,path:e.path,model:t.model,stream:!!t.stream,toolCount:n,account:i.label,accountType:i.type,responseStatus:l,responseTimeMs:f-o,attemptDurationMs:p?.attemptDurationMs??f-c,...u?{errorType:u}:{},...d?{errorMessage:d}:{},...p?.errorCode?{errorCode:p.errorCode}:{},...p?.inputTokens!==void 0?{inputTokens:p.inputTokens}:{},...p?.outputTokens!==void 0?{outputTokens:p.outputTokens}:{},...p?.cacheCreationTokens!==void 0?{cacheCreationTokens:p.cacheCreationTokens}:{},...p?.cacheReadTokens!==void 0?{cacheReadTokens:p.cacheReadTokens}:{},...p?.retryable!==void 0?{retryable:p.retryable}:{},...p?.rateLimitKind?{rateLimitKind:p.rateLimitKind}:{},...p?.cooldownReason?{cooldownReason:p.cooldownReason}:{},...h?{traceId:h.traceId,spanId:h.spanId}:{}})}}async function ncn(r){let{account:e,accountState:t,bodyStr:n,clientHeaders:o,isClaudeClientRequest:s,url:i,tracer:a,attemptNumber:c,currentLastError:l,currentAuthFailureMessage:u,logAttempt:d,logProxyBody:p}=r,f=l,h=u;if(bve(e)){let A=await NJ(e,e.persistTarget);if(A.success)e.persistTarget&&await DJ(e.persistTarget,e),await qJ(e,t);else return f=`token refresh failed for account=${e.label}: ${A.error?.slice(0,200)??"unknown"}`,pw(A)?(await mw(e,t,"refresh_invalid"),h=HJ(e.label)):await VJ(e,t),d(pw(A)?401:503,pw(A)?"authentication_error":"token_refresh_unavailable",String(f)),{continueLoop:!0,lastError:f,authFailureMessage:h}}let y=e.type==="oauth",x={};for(let[A,I]of Object.entries(o))typeof I=="string"&&(x[A]=I);let b=y?await Lan(e.label,e.key,x,n):null,T={};for(let[A,I]of Object.entries(o)){let M=A.toLowerCase();typeof I=="string"&&!jJ.has(M)&&(T[M]=I)}if(T["content-type"]="application/json",y?(T.authorization=`Bearer ${e.token}`,delete T["x-api-key"],Pan(T,b)):(T["x-api-key"]=e.token,delete T.authorization),T["user-agent"]||(T["user-agent"]=Jx),T["anthropic-version"]||(T["anthropic-version"]="2023-06-01"),T["anthropic-dangerous-direct-browser-access"]||(T["anthropic-dangerous-direct-browser-access"]="true"),T["x-app"]||(T["x-app"]="cli"),T.accept||(T.accept="application/json"),y){let A=s?T["anthropic-beta"]??"":o["anthropic-beta"]??"",I=new Set(A.split(",").map(M=>M.trim()).filter(Boolean));for(let M of s?gS:Ian)I.add(M);T["anthropic-beta"]=[...I].join(",")}else{let A=(T["anthropic-beta"]??"").split(",").map(I=>I.trim()).filter(I=>I&&!gS.includes(I)).join(",");A?T["anthropic-beta"]=A:delete T["anthropic-beta"]}let S=A=>y?Fan(n,A,b,s,T["x-claude-code-session-id"]):{bodyStr:n},E=S(e.token);y&&E.sessionId&&!T["x-claude-code-session-id"]&&(T["x-claude-code-session-id"]=E.sessionId);let C=E.bodyStr;g.always(`[proxy] \u2192 account=${e.label} (${e.type})`),uw(e.label,e.type);let R=Date.now(),P;return a&&(P=a.startUpstreamAttempt({attempt:c,account:e.label,polyfillHeaders:y,polyfillBody:y,upstreamUrl:i}),a.logUpstreamRequestHeaders(T),a.logUpstreamRequestBody(C),Object.assign(T,a.getTraceHeaders())),p({phase:"upstream_request",headers:T,body:C,bodySize:Buffer.byteLength(C,"utf8"),contentType:T["content-type"]??"application/json",account:e.label,accountType:e.type,attempt:c,metadata:{upstreamMethod:"POST",upstreamUrl:i}}),{continueLoop:!1,lastError:f,authFailureMessage:h,headers:T,buildUpstreamBody:S,finalBodyStr:C,fetchStartMs:R,upstreamSpan:P}}function Ynt(r,e){let t=!!r["retry-after"],n=Object.keys(r).some(o=>o.toLowerCase().startsWith("anthropic-ratelimit-"));return t||n?!1:e.includes("rate_limit_error")&&/"message"\s*:\s*"Error"/.test(e)}function Xnt(){return{status:400,body:JSON.stringify(ld(400,"Anthropic rejected the OAuth request shape. This is not an account rate limit.","invalid_request_error")),headers:{"content-type":"application/json"},errorType:"construction_rejection"}}async function ocn(r){let{url:e,headers:t,finalBodyStr:n,account:o,accountState:s,enabledAccounts:i,orderedAccounts:a,tracer:c,logAttempt:l,logProxyBody:u,fetchStartMs:d,attemptNumber:p,currentLastError:f,currentSawRateLimit:h,currentSawNetworkError:y,upstreamSpan:x}=r,b=f,T=h,S=y,E=x,C;try{C=await fetch(e,{method:"POST",headers:t,body:n,signal:AbortSignal.timeout(Rve)})}catch(R){let P=Dve(R);S=!0,ao(o.label,o.type,502);let A=WJ(R)??"unknown",I=R instanceof Error?R.message:String(R);if(b=I,g.always(`[proxy] fetch error account=${o.label} code=${A} (${P?"retryable":"terminal"}): ${I}`),l(502,"network_error",I,{retryable:P,errorCode:A}),c?.setError("network_error",I),P&&c?.recordRetry(o.label,"network_error"),E?.end(),!P)throw R;return{continueLoop:!0,retrySameAccount:!0,lastError:b,sawRateLimit:T,sawNetworkError:S,upstreamSpan:void 0}}if(C.status===429){let R=LJ(C.headers.get("retry-after")),P={};C.headers.forEach(($,U)=>{P[U]=$}),b=await C.text();let A={...P};delete A.authorization,delete A["x-api-key"];let I=String(b).length>4e3?String(b).slice(0,4e3)+"...[truncated]":String(b);if(c?.logUpstreamResponseHeaders(A),c?.logUpstreamResponseBody(I),u({phase:"upstream_response",headers:A,body:I,bodySize:Buffer.byteLength(String(b),"utf8"),contentType:P["content-type"]??"application/json",account:o.label,accountType:o.type,attempt:p,responseStatus:429,durationMs:Date.now()-d}),Ynt(P,String(b)))return g.always(`[proxy] \u2190 429 account=${o.label} anti-abuse/construction rejection (no ratelimit headers, body="Error") \u2014 NOT a real rate limit; returning non-retryable request error`),l(429,"construction_rejection",String(b)),c?.setError("construction_rejection",String(b).slice(0,500)),E?.end(),{continueLoop:!1,terminalError:Xnt(),lastError:b,sawRateLimit:T,sawNetworkError:S,upstreamSpan:void 0};T=!0;let M=Date.now(),O=cA(P),F=iF(P),N=Ave(O,R,M,F),z=N.reason==="transient"?"transient":"quota";return ao(o.label,o.type,429,z),g.always(`[proxy] \u2190 429 account=${o.label} reason=${N.reason} retry-after=${R}ms 5h-status=${P["anthropic-ratelimit-unified-5h-status"]??"unknown"} 7d-status=${P["anthropic-ratelimit-unified-7d-status"]??"unknown"} unified-status=${F??"unknown"} \u2192 ${N.rotateImmediately?`rotate now, cool ${Ive(N.coolingUntil,M)}m`:"retry same account (transient)"}`),l(429,"rate_limit_error",String(b),{retryable:!0,rateLimitKind:z,cooldownReason:N.reason}),c?.setError("rate_limit_error",String(b).slice(0,500)),c?.recordRetry(o.label,"rate_limit"),E?.end(),{continueLoop:!0,retrySameAccount:!N.rotateImmediately,retryAfterMs:R,cooldownPlan:N,...O?{quota:O}:{},lastError:b,sawRateLimit:T,sawNetworkError:S,upstreamSpan:void 0}}return{continueLoop:!1,response:C,lastError:b,sawRateLimit:T,sawNetworkError:S,upstreamSpan:E}}function scn(r){return r.invalidRequestFailure===null}async function icn(r){let{ctx:e,body:t,modelRouter:n,tracer:o,requestStartTime:s,accountStrategy:i,primaryAccountKey:a,accountAllowlist:c,quotaRoutingEnabled:l=Pve(),sessionSoftLimit:u=Mve(),sessionResetToleranceMs:d=Ove(),buildLoggedClaudeError:p,logProxyBody:f,logFinalRequest:h,setRoutingDecision:y}=r,x=hJ(t),b=await Van({ctx:e,body:t,tracer:o,requestStartTime:s,accountStrategy:i,primaryAccountKey:a,accountAllowlist:c,quotaRoutingEnabled:l,sessionSoftLimit:u,sessionResetToleranceMs:d,buildLoggedClaudeError:p,setRoutingDecision:y});if("response"in b)return b.response;let{accounts:T,enabledAccounts:S,orderedAccounts:E,bodyStr:C,requestStart:R,toolCount:P,url:A,clientHeaders:I,isClaudeClientRequest:M}=b,O={lastError:void 0,sawRateLimit:!1,sawNetworkError:!1,sawTransientFailure:!1,invalidRequestFailure:null,authFailureMessage:null,authCooldownMessage:null,attemptNumber:0},F=o?.startAccountSelection(),z=E.filter($=>!Unt($.key));if(z.length===0&&(z=await wan(E)),z.length===0&&E.length>0){let $=E.map(B=>Vf(B.key)),U=$.some(B=>B.coolingReason!=="auth");if(O.sawRateLimit=U,O.sawTransientFailure=!U,O.lastError=U?"All Anthropic accounts have active rate-limit cooldowns":"All Anthropic accounts have active authentication cooldowns",!U){let B=Math.min(...$.map(j=>j.coolingUntil??Number.POSITIVE_INFINITY));O.authCooldownMessage=`All ${E.length} Anthropic accounts are temporarily unavailable while OAuth refresh is cooling. Earliest retry at ${new Date(B).toISOString()}.`}}e:for(let $ of z){let U=Vf($.key),B=0,j=0;for(;;){O.attemptNumber+=1,o&&O.attemptNumber===1&&F&&(o.setAccountSelection({strategy:i,accountsTotal:T.length,accountsHealthy:S.length,selectedAccount:$.label,accountType:$.type}),F.end());let K=rcn({ctx:e,body:t,toolCount:P,requestStart:R,tracer:o,account:$,attemptNumber:O.attemptNumber}),Y=await ncn({account:$,accountState:U,bodyStr:C,clientHeaders:I,isClaudeClientRequest:M,url:A,tracer:o,attemptNumber:O.attemptNumber,currentLastError:O.lastError,currentAuthFailureMessage:O.authFailureMessage,logAttempt:K,logProxyBody:f});if(O.lastError=Y.lastError,O.authFailureMessage=Y.authFailureMessage,Y.continueLoop||!Y.headers||!Y.buildUpstreamBody||!Y.finalBodyStr||Y.fetchStartMs===void 0)continue e;let G=await ocn({url:A,headers:Y.headers,finalBodyStr:Y.finalBodyStr,account:$,accountState:U,enabledAccounts:S,orderedAccounts:E,tracer:o,logAttempt:K,logProxyBody:f,fetchStartMs:Y.fetchStartMs,attemptNumber:O.attemptNumber,currentLastError:O.lastError,currentSawRateLimit:O.sawRateLimit,currentSawNetworkError:O.sawNetworkError,upstreamSpan:Y.upstreamSpan});if(O.lastError=G.lastError,O.sawRateLimit=G.sawRateLimit,O.sawNetworkError=G.sawNetworkError,G.terminalError)return Jnt({terminalError:G.terminalError,account:$,tracer:o,requestStartTime:s,attemptNumber:O.attemptNumber,logProxyBody:f,logFinalRequest:h});if(G.continueLoop||!G.response){if(G.cooldownPlan){let se=G.cooldownPlan;G.quota&&(U.quota=G.quota,aF($.label,G.quota).catch(()=>{}));let ue=!1;(!U.coolingUntil||se.coolingUntil>U.coolingUntil)&&(U.coolingUntil=se.coolingUntil,U.coolingReason=se.reason,ue=!0),ue&&await aw($.key,U.coolingUntil,U.coolingReason??se.reason).catch(()=>{});let Ge=G.retrySameAccount?Tan($.key,se.coolingUntil):void 0;if(G.retrySameAccount&&G.retryAfterMs!==void 0&&j<kve&&Ge!==void 0){j+=1;let Re=Math.min(G.retryAfterMs||1e3,Rnt),me=Math.min(Rnt,ccn(Re*Ge));g.always(`[proxy] retrying same account=${$.label} after transient 429 (shared slot ${Ge}/${kve}) in ${me}ms`),await TA(me);continue}vA($.key,S.length,E[0]?.key),g.always(`[proxy] account=${$.label} rate-limited (${se.reason}); cooling ~${Ive(se.coolingUntil,Date.now())}m until ${new Date(se.coolingUntil).toISOString()}, rotating`);continue e}if(G.retrySameAccount&&B<FJ){B+=1;let se=Nnt(B);g.always(`[proxy] retrying same account=${$.label} after transient network error (${B}/${FJ}) in ${se}ms`),await TA(se);continue}G.retrySameAccount&&g.always(`[proxy] exhausted transient same-account retries for account=${$.label}; rotating`);continue e}let ne=G.upstreamSpan,we=G.response;if(we.status===401&&$.type==="oauth"&&$.refreshToken){let se=await Qan({ctx:e,body:t,account:$,accountState:U,headers:Y.headers,buildUpstreamBody:Y.buildUpstreamBody,url:A,enabledAccounts:S,orderedAccounts:E,tracer:o,requestStartTime:s,allocateAttemptNumber:()=>(O.attemptNumber+=1,O.attemptNumber),upstreamSpan:ne,logAttempt:K,logProxyBody:f,logFinalRequest:h,lastError:O.lastError,authFailureMessage:O.authFailureMessage,sawRateLimit:O.sawRateLimit,sawTransientFailure:O.sawTransientFailure,sawNetworkError:O.sawNetworkError});if(O.lastError=se.lastError,O.authFailureMessage=se.authFailureMessage,O.sawRateLimit=se.sawRateLimit,O.sawTransientFailure=se.sawTransientFailure,O.sawNetworkError=se.sawNetworkError,ne=se.upstreamSpan,se.response!==void 0)return se.response;if(se.continueLoop)continue e}if(!we.ok){let se=await ecn({response:we,account:$,accountState:U,enabledAccounts:S,orderedAccounts:E,tracer:o,requestStartTime:s,fetchStartMs:Y.fetchStartMs,attemptNumber:O.attemptNumber,logAttempt:K,logProxyBody:f,logFinalRequest:h,lastError:O.lastError,authFailureMessage:O.authFailureMessage,sawTransientFailure:O.sawTransientFailure,invalidRequestFailure:O.invalidRequestFailure});if(O.lastError=se.lastError,O.authFailureMessage=se.authFailureMessage,O.sawTransientFailure=se.sawTransientFailure,O.invalidRequestFailure=se.invalidRequestFailure,se.response!==void 0)return se.response;if(se.continueLoop){if(se.retrySameAccount&&B<FJ){B+=1;let ue=Nnt(B);g.always(`[proxy] retrying same account=${$.label} after transient upstream ${we.status} (${B}/${FJ}) in ${ue}ms`),await TA(ue);continue}se.retrySameAccount&&g.always(`[proxy] exhausted transient same-account retries for account=${$.label}; rotating`);continue e}break e}if(U.coolingUntil&&Date.now()>=U.coolingUntil){let se=U.coolingUntil;U.coolingUntil=void 0,U.coolingReason=void 0,mJ($.key,se).catch(()=>{})}let X=await Knt({ctx:e,body:t,account:$,accountState:U,response:we,tracer:o,requestStartTime:s,fetchStartMs:Y.fetchStartMs,attemptNumber:O.attemptNumber,finalBodyStr:Y.finalBodyStr,upstreamSpan:ne,logAttempt:K,logProxyBody:f,logFinalRequest:h});if("retryNextAccount"in X){X.failure&&(O.lastError=X.failure.message,O.sawRateLimit||=X.failure.rateLimit,O.sawTransientFailure||=!X.failure.rateLimit);continue e}return X.response}}if(O.attemptNumber===0&&F?.end(),scn(O)){let $,U=await Han({ctx:e,body:t,parsedFallbackRequest:x,modelRouter:n,tracer:o,requestStartTime:s,logProxyBody:f,logFinalRequest:h});if(U.response)return U.response;if($=U.lastErrorMessage,!O.sawRateLimit){let B=await Wan({ctx:e,body:t,tracer:o,requestStartTime:s,logProxyBody:f,logFinalRequest:h});if(B.response)return B.response;$=B.lastErrorMessage??$}O.fallbackFailureMessage=$}return Kan({tracer:o,requestStartTime:s,authFailureMessage:O.authFailureMessage,authCooldownMessage:O.authCooldownMessage,invalidRequestFailure:O.invalidRequestFailure,sawNetworkError:O.sawNetworkError,sawTransientFailure:O.sawTransientFailure,sawRateLimit:O.sawRateLimit,lastError:O.lastError,fallbackFailureMessage:O.fallbackFailureMessage,orderedAccounts:E,buildLoggedClaudeError:p,logProxyBody:f,logFinalRequest:h})}function Mnt(r){return r!==void 0&&"runtimeConfigProvider"in r&&typeof r.runtimeConfigProvider=="function"}function Ont(r){let{ctx:e,body:t,status:n,message:o,errorType:s}=r;return gA(n,wve,Eve,{requestId:e.requestId,errorType:s,terminalOutcome:"handler_error",message:o}),zf({timestamp:new Date().toISOString(),requestId:e.requestId,method:e.method,path:e.path,model:typeof t?.model=="string"?t.model:"",stream:t?.stream??!1,toolCount:Array.isArray(t?.tools)?t.tools.length:0,account:wve,accountType:Eve,responseStatus:n,responseTimeMs:0,errorType:s,errorMessage:o}),ld(n,o)}function Znt(r,e="",t="fill-first",n=!1,o,s){let i=Mnt(s)?s.accountAllowlist:s,a=Mnt(s)?s.runtimeConfigProvider:void 0;return{prefix:`${e}/v1`,routes:[{method:"POST",path:`${e}/v1/messages`,handler:async c=>{let l=a?.()??{generation:0,strategy:t,modelRouter:r,passthrough:n,primaryAccountKey:o,accountAllowlist:i,quotaRoutingEnabled:Pve(),sessionSoftLimit:Mve(),sessionResetToleranceMs:Ove()},u=l.modelRouter,d=c.body;if(typeof d?.model!="string"||!Array.isArray(d?.messages))return Ont({ctx:c,body:d,status:400,message:"Missing required fields: model, messages",errorType:"invalid_request_error"});let p=d.model.toLowerCase();if(!u&&!p.startsWith("claude-"))return Ont({ctx:c,body:d,status:404,message:`Model '${d.model}' is not an Anthropic model. The proxy only supports Claude models. Use a model router to route non-Claude models to other providers.`,errorType:"not_found_error"});let f=u?.resolve(d.model)??{provider:"anthropic",model:d.model},h=JSON.stringify(d),{tracer:y,requestStartTime:x,logProxyBody:b,logFinalRequest:T,buildLoggedClaudeError:S,setRoutingDecision:E}=tcn({ctx:c,body:d,clientRequestBody:h});try{return f.provider===null?(y?.setError("not_found_error",`Model '${d.model}' is not a Claude model.`),y?.end(404,Date.now()-x),S(404,`Model '${d.model}' is not a Claude model. Use a model router to route it to another provider.`)):f.provider==="anthropic"?(y?.setMode("passthrough"),l.passthrough?Ban({ctx:c,body:d,clientRequestBody:h,tracer:y,requestStartTime:x,logProxyBody:b,logFinalRequest:T}):icn({ctx:c,body:d,modelRouter:u,tracer:y,requestStartTime:x,accountStrategy:l.strategy,primaryAccountKey:l.primaryAccountKey,accountAllowlist:l.accountAllowlist,quotaRoutingEnabled:l.quotaRoutingEnabled,sessionSoftLimit:l.sessionSoftLimit,sessionResetToleranceMs:l.sessionResetToleranceMs,buildLoggedClaudeError:S,logProxyBody:b,logFinalRequest:T,setRoutingDecision:E})):$an({ctx:c,body:d,route:{provider:f.provider,model:f.model},modelRouter:u,tracer:y,requestStartTime:x,logProxyBody:b})}catch(C){let R=C instanceof Error?C.message:String(C);return g.error(`[claude-proxy] Generation error for ${d.model}: ${R}`),y?.setError("generation_error",R.slice(0,500)),y?.end(502,Date.now()-x),S(502,`Generation failed: ${C instanceof Error?C.message:"unknown error"}`)}},description:"Claude-compatible messages endpoint routed through NeuroLink",tags:["claude-proxy","messages"],streaming:{enabled:!0,contentType:"text/event-stream"}},{method:"GET",path:`${e}/v1/models`,handler:async c=>{let l=a?a().modelRouter:r;return Qe({name:"neurolink.http.claudeProxy.listModels",tracer:Me.http,attributes:{"http.route":`${e}/v1/models`}},async()=>gnt(l))},description:"List available models (Anthropic schema)",tags:["claude-proxy","models"]},{method:"POST",path:`${e}/v1/messages/count_tokens`,handler:async c=>Qe({name:"neurolink.http.claudeProxy.countTokens",tracer:Me.http,attributes:{"http.route":`${e}/v1/messages/count_tokens`}},async l=>{let u=c.body;if(typeof u?.model!="string"||!Array.isArray(u?.messages))return ld(400,"Missing required fields: model, messages");let d=u.messages.map(f=>typeof f.content=="string"?f.content:JSON.stringify(f.content)).join(" "),p=Math.ceil(d.length/4);return l.setAttribute("ai.model",u.model),l.setAttribute("gen_ai.usage.input_tokens",p),{input_tokens:p}}),description:"Count tokens for a messages request",tags:["claude-proxy","tokens"]}]}}function Vf(r){let e=SF.get(r);if(e)return e;let t={consecutiveRefreshFailures:0,permanentlyDisabled:!1};return SF.set(r,t),t}function acn(r){let e=Vf(r.key),t=e.lastToken!==r.token||e.lastRefreshToken!==r.refreshToken,n=e.permanentlyDisabled;n&&g.always(`[proxy] account=${r.label} is enabled in the token store; clearing stale runtime auth-disable state`),e.permanentlyDisabled=!1,(t||n)&&(e.consecutiveRefreshFailures=0),e.lastToken=r.token,e.lastRefreshToken=r.refreshToken}async function mw(r,e,t){try{let{tokenStore:n}=await Promise.resolve().then(()=>(OJ(),yve)),o=r.persistTarget&&typeof r.persistTarget!="string"&&"providerKey"in r.persistTarget?r.persistTarget.providerKey:void 0;if(o){if(!await n.markDisabledIfCurrent(o,{accessToken:r.token,refreshToken:r.refreshToken,expiresAt:r.expiresAt??0},t))return e.permanentlyDisabled=!1,g.always(`[proxy] account=${r.label} credentials changed while authentication was in flight; ignored stale disable`),!1}else await n.markDisabled(r.key,t)}catch(n){g.debug(`[proxy] failed to persist disabled state for ${r.label}: ${n instanceof Error?n.message:String(n)}`)}return e.permanentlyDisabled=!0,g.always(`[proxy] account=${r.label} disabled until re-authentication. Run: neurolink auth login anthropic --method oauth`),!0}async function VJ(r,e){e.consecutiveRefreshFailures+=1;let t=Math.min(e.consecutiveRefreshFailures-1,4),n=Math.min(gan,fan*2**t),o=Date.now()+n;(!e.coolingUntil||o>e.coolingUntil)&&(e.coolingUntil=o,e.coolingReason="auth");let s=e.coolingUntil??o,i=e.coolingReason??"auth";return e.coolingUntil=s,e.coolingReason=i,await aw(r.key,s,i).catch(()=>{}),s}async function qJ(r,e){if(e.consecutiveRefreshFailures=0,e.coolingReason!=="auth"||!e.coolingUntil)return;let t=e.coolingUntil;e.coolingUntil=void 0,e.coolingReason=void 0,await mJ(r.key,t).catch(()=>{})}function HJ(r){return`Account(s) require re-authentication: ${Array.isArray(r)?r.join(", "):r}. Run: neurolink auth login anthropic --method oauth`}function bo(r,e=180){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:`${t.slice(0,e)}...`}function Nnt(r){let e=Math.min(Math.max(r-1,0),_ve.length-1);return _ve[e]??0}async function TA(r){await new Promise(e=>setTimeout(e,r))}function ccn(r){return r+Math.floor(Math.random()*r*.25)}function WJ(r){if(!r||typeof r!="object")return;let e=r.code;if(typeof e=="string")return e;let t=r.cause;if(!t||typeof t!="object")return;let n=t.code;return typeof n=="string"?n:void 0}function wA(r){let e=r instanceof Error?r.message:String(r);if(!r||typeof r!="object")return e;let t=r.cause,n=t instanceof Error?t.message:t&&typeof t=="object"?String(t.message??""):"",s=[WJ(r),n&&n!==e&&n].filter(Boolean).join(": ");return s?`${e} (${s})`:e}function Dve(r){let e=WJ(r);if(e&&["ECONNREFUSED","ECONNRESET","ENOTFOUND","ETIMEDOUT","EHOSTUNREACH","UND_ERR_CONNECT_TIMEOUT","UND_ERR_CONNECT","UND_ERR_SOCKET","UND_ERR_HEADERS_TIMEOUT"].includes(e))return!0;let n=(r instanceof Error?r.message:String(r)).toLowerCase();return n.includes("econnrefused")||n.includes("econnreset")||n.includes("enotfound")||n.includes("etimedout")||n.includes("timed out")||n.includes("connection error")||n.includes("connect error")||n.includes("fetch failed")||n.includes("socket hang up")}var lcn=new Set([408,500,502,503,504,520,521,522,523,524,525,526,529]);function Lve(r){try{let e=JSON.parse(r);if(e&&e.type==="error"&&e.error&&typeof e.error=="object")return{errorType:typeof e.error.type=="string"?e.error.type:void 0,message:typeof e.error.message=="string"?e.error.message:void 0}}catch{}return{}}function ucn(r,e){return r===422?!0:Lve(e).errorType==="invalid_request_error"||e.includes("invalid_request_error")}function dcn(r,e){if(r!==400)return!1;let t=Lve(e);if(t.errorType!=="invalid_request_error")return!1;let n=(t.message??"").toLowerCase();return n.includes("beta")&&n.includes("subscription")&&n.includes("available")}function pcn(r){return{...r,messages:r.messages.map(e=>typeof e.content!="string"?e:{...e,content:[{type:"text",text:e.content}]})}}var Qnt=RJ;function eot(r,e){if(lcn.has(r))return!0;if(r!==400)return!1;let t=Lve(e);if(t.errorType==="overloaded_error")return!0;if(t.errorType!=="api_error")return!1;let n=(t.message??e).toLowerCase();return n.includes("<!doctype html")||n.includes("error code 520")||n.includes("web server is returning an unknown error")||n.includes("cloudflare")||n.includes("internal server error")}An();Hr();function Fve(r,e,t){return n=>Qe({name:r,tracer:Me.http,attributes:{"http.route":e,"http.request.id":n.requestId??""}},()=>t(n))}function wF(r="/api"){return{prefix:`${r}/health`,routes:[{method:"GET",path:`${r}/health`,handler:Fve("neurolink.http.health.check",`${r}/health`,async()=>({status:"ok",timestamp:new Date().toISOString(),uptime:process.uptime()*1e3,version:process.env.npm_package_version||"unknown"})),description:"Basic health check",tags:["health"]},{method:"GET",path:`${r}/health/live`,handler:Fve("neurolink.http.health.live",`${r}/health/live`,async()=>({status:"alive",timestamp:new Date().toISOString()})),description:"Kubernetes liveness probe",tags:["health"]},{method:"GET",path:`${r}/health/ready`,handler:e=>Qe({name:"neurolink.http.health.ready",tracer:Me.http,attributes:{"http.route":`${r}/health/ready`,"http.request.id":e.requestId??""}},async t=>{let n=await e.toolRegistry.listTools(),o=n.length>0,s=!!e.externalServerManager,i=!0;if(e.externalServerManager){let c=e.externalServerManager.getServerStatuses();for(let l of c)if(l.status!=="connected"){i=!1;break}}let a=o||!s||i;return t.setAttribute("health.ready",a),t.setAttribute("health.tools_count",n.length),t.setAttribute("health.external_servers_ready",i),{ready:a,timestamp:new Date().toISOString(),services:{neurolink:!0,tools:o,externalServers:i}}}),description:"Kubernetes readiness probe",tags:["health"]},{method:"GET",path:`${r}/health/startup`,handler:e=>Qe({name:"neurolink.http.health.startup",tracer:Me.http,attributes:{"http.route":`${r}/health/startup`,"http.request.id":e.requestId??""}},async t=>{let n=await e.toolRegistry.listTools();return t.setAttribute("health.tools_count",n.length),{started:!0,timestamp:new Date().toISOString(),services:{neurolink:!0,toolsLoaded:n.length,externalServerManager:!!e.externalServerManager}}}),description:"Kubernetes startup probe",tags:["health"]},{method:"GET",path:`${r}/health/detailed`,handler:e=>Qe({name:"neurolink.http.health.detailed",tracer:Me.http,attributes:{"http.route":`${r}/health/detailed`,"http.request.id":e.requestId??""}},async t=>{let n=await e.toolRegistry.listTools(),o={};for(let l of n){let u=typeof l.source=="string"?l.source:l.serverId||"built-in";o[u]=(o[u]||0)+1}let s=[];if(e.externalServerManager){let l=e.externalServerManager.getServerStatuses();for(let u of l)s.push({name:u.serverId,status:u.status,toolCount:u.toolCount})}let i=e.neurolink.conversationMemory,a={available:!!i,type:i?.constructor.name||"none"},c={status:"ok",timestamp:new Date().toISOString(),uptime:process.uptime()*1e3,version:process.env.npm_package_version||"unknown",node:{version:process.version,platform:process.platform,arch:process.arch},memory:{...a,process:{heapUsed:Math.round(process.memoryUsage().heapUsed/1024/1024),heapTotal:Math.round(process.memoryUsage().heapTotal/1024/1024),rss:Math.round(process.memoryUsage().rss/1024/1024),external:Math.round(process.memoryUsage().external/1024/1024)}},tools:{total:n.length,bySource:o},externalServers:{count:s.length,servers:s}};if(e.metadata?.accountPool){let l=e.metadata.accountPool,u=l.getAllAccounts(),d={};for(let p of u)d[p.status]=(d[p.status]||0)+1;c.proxy={totalAccounts:u.length,statusDistribution:d,healthyCount:l.getHealthyCount(),strategy:l.getStrategy()},t.setAttribute("health.proxy.accounts",u.length),t.setAttribute("health.proxy.healthy",l.getHealthyCount())}return t.setAttribute("health.tools_count",n.length),t.setAttribute("health.external_servers_count",s.length),t.setAttribute("health.memory.heap_mb",Math.round(process.memoryUsage().heapUsed/1024/1024)),c}),description:"Detailed health information",tags:["health"]},{method:"GET",path:`${r}/version`,handler:Fve("neurolink.http.version",`${r}/version`,async()=>({name:"@juspay/neurolink",version:process.env.npm_package_version||"unknown",node:process.version,timestamp:new Date().toISOString()})),description:"Get version information",tags:["health","version"]}]}}cs();ln();J();var tot=300*1e3,mcn=55669;function fcn(r){return r?{status:502,errorType:"loopback_stream_error",errorMessage:r}:{status:499,errorType:"client_cancelled",errorMessage:"Client cancelled the OpenAI-compatible stream"}}function EF(r,e){return new Response(JSON.stringify(Qrt(r,e)),{status:r,headers:{"content-type":"application/json"}})}function gcn(r){return{model:r.model,maxTokens:r.maxTokens??4096,temperature:r.temperature,topP:r.topP,systemPrompt:typeof r.systemPrompt=="string"?r.systemPrompt:void 0,stream:r.stream,prompt:r.prompt,images:r.images,conversationMessages:r.conversationMessages,tools:r.tools,toolChoice:r.toolChoice,toolChoiceName:r.toolChoiceName,stopSequences:r.stopSequences}}async function hcn(r){let{ctx:e,body:t,targetModel:n,requestStartTime:o,loopbackPort:s}=r,i=t.stream===!0,a=t.tools?.length??0,c=(h,y={})=>zf({timestamp:new Date().toISOString(),requestId:e.requestId,method:e.method,path:e.path,model:t.model,stream:i,toolCount:a,account:"",accountType:"openai-bridge",responseStatus:h,responseTimeMs:Date.now()-o,...y}),l=ent(t);l.model=n;let u=`http://127.0.0.1:${s}/v1/messages`,d={"content-type":"application/json",accept:i?"text/event-stream":"application/json"};for(let[h,y]of Object.entries(e.headers)){if(typeof y!="string")continue;let x=h.toLowerCase();(x.startsWith("anthropic-")||x==="x-api-key")&&(d[x]=y)}let p=await kt(fetch(u,{method:"POST",headers:d,body:JSON.stringify({...l,stream:i})}),tot,`Anthropic loopback timed out after ${tot}ms`);if(!p.ok){let h=await p.text().catch(()=>""),y=ko(h);return g.always(`[proxy:openai] anthropic loopback error ${p.status}: ${y}`),await c(p.status,{errorType:"loopback_upstream_error",errorMessage:y}),EF(p.status,y||`Anthropic loopback failed with status ${p.status}`)}if(i){if(!p.body)return await c(502,{errorType:"loopback_empty_stream",errorMessage:"Anthropic loopback returned empty stream body"}),EF(502,"Anthropic loopback returned empty stream body");let h,x=p.body.pipeThrough(rnt(t.model,{onError:E=>{h=ko(E)}})).getReader(),b=!1,T=async(E,C,R)=>{b||(b=!0,await c(E,{errorType:C,errorMessage:R}))},S=new ReadableStream({async pull(E){try{let{value:C,done:R}=await x.read();if(R){h?await T(502,"loopback_stream_error",h):await T(200),E.close();return}E.enqueue(C)}catch(C){let R=ko(C instanceof Error?C.message:String(C));await T(502,"loopback_stream_error",R),E.error(C)}},async cancel(E){try{await x.cancel(E)}finally{let C=fcn(h);await T(C.status,C.errorType,C.errorMessage)}}});return new Response(S,{status:200,headers:{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"}})}let f=await p.json();return await c(200,{inputTokens:f.usage?.input_tokens,outputTokens:f.usage?.output_tokens,cacheCreationTokens:f.usage?.cache_creation_input_tokens,cacheReadTokens:f.usage?.cache_read_input_tokens}),tnt(f,t.model)}function rot(r,e="",t=mcn,n){return{prefix:`${e}/v1`,routes:[{method:"POST",path:`${e}/v1/chat/completions`,description:"OpenAI-compatible chat completions (translation mode)",handler:async o=>{let s=n?n().modelRouter:r,i=Date.now(),a=o.body;if(!a||!a.model||!a.messages?.length)return EF(400,"Request must include 'model' and 'messages' fields");let c=s?s.resolve(a.model):{provider:null,model:a.model},l=c.provider??void 0,u=c.model??a.model;if(g.debug(`[proxy:openai] ${a.model} \u2192 ${l??"auto"}/${u}`),c.provider==="anthropic")try{return await hcn({ctx:o,body:a,targetModel:u,requestStartTime:i,loopbackPort:t})}catch(x){let b=x instanceof Error?x.message:String(x),T=ko(b);return g.always(`[proxy:openai] anthropic loopback failed: ${T}`),await zf({timestamp:new Date().toISOString(),requestId:o.requestId,method:o.method,path:o.path,model:a.model,stream:a.stream===!0,toolCount:a.tools?.length??0,account:"",accountType:"openai-bridge",responseStatus:502,responseTimeMs:Date.now()-i,errorType:"loopback_exception",errorMessage:T}),EF(502,"Anthropic loopback failed")}let d=Xrt(a),p=gcn(d),h=bA({provider:l??"auto",model:u},s?.getFallbackChain()??[],a.model,p).attempts,y;try{y=hA.startRequest({requestId:o.requestId,method:o.method,path:o.path,model:a.model,stream:a.stream===!0,toolCount:Object.keys(d.tools).length,clientApp:"openai-compat",userAgent:o.headers["user-agent"]??""},o.headers),y.setMode("full")}catch{}try{return a.stream?AJ({ctx:o,format:"openai",requestModel:a.model,parsed:d,attempts:h,tracer:y,requestStartTime:i}):await IJ({ctx:o,format:"openai",requestModel:a.model,parsed:d,attempts:h,tracer:y,requestStartTime:i})}catch(x){let b=x instanceof Error?x.message:String(x),T=ko(b);return g.always(`[proxy:openai] request failed: ${T}`),y?.setError("generation_error",T),y?.end(500,Date.now()-i),EF(500,"Internal proxy error")}}},{method:"GET",path:`${e}/v1/models`,description:"List available models in OpenAI format",handler:async()=>{let o=n?n().modelRouter:r;return mnt(o)}}]}}Lr();Xn();An();Hr();Ff();function fw(r,e,t){return n=>Qe({name:r,tracer:Me.http,attributes:{"http.route":e,"http.request.id":n.requestId}},async o=>{let s=await t(n);if(s&&typeof s=="object"){let i=s.error;if(i!=null){let a=typeof i=="string"?i:typeof i?.message=="string"?i.message:"MCP handler error";o.setStatus({code:Fe.ERROR,message:a})}}return s})}var ycn=m.object({name:m.string().min(1,"Server name is required"),toolName:m.string().min(1,"Tool name is required")});async function xcn(r){let e=r.externalServerManager;if(!e)return{servers:[],total:0,message:"External server manager not available",metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}};let t=e.listServers(),n=e.getServerStatuses(),o=new Map(n.map(i=>[i.serverId,i])),s=t.map(i=>{let a=o.get(i.name);return{serverId:i.name,name:i.name,status:a?.status||"disconnected",toolCount:a?.toolCount||0,lastHealthCheck:a?.checkedAt?.toISOString(),error:a?.issues?.[0]}});return{servers:s,total:s.length,metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}async function bcn(r){let e=hl(nw,r.params,r.requestId);if(!e.success)return e.error;let{name:t}=e.data,n=r.externalServerManager;if(!n)return sr("MCP_UNAVAILABLE","External server manager not available",void 0,r.requestId);if(!n.listServers().find(u=>u.name===t))return sr("SERVER_NOT_FOUND",`MCP server '${t}' not found`,void 0,r.requestId);let a=n.getServerStatuses().find(u=>u.serverId===t),l=(await r.toolRegistry.listTools()).filter(u=>u.source===t);return{serverId:t,name:t,status:a?.status||"disconnected",toolCount:a?.toolCount||0,tools:l.map(u=>({name:u.name,description:u.description})),lastHealthCheck:a?.checkedAt?.toISOString(),error:a?.issues?.[0],metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}async function vcn(r){let e=hl(nw,r.params,r.requestId);if(!e.success)return e.error;let{name:t}=e.data,n=r.externalServerManager;if(!n)return sr("MCP_UNAVAILABLE","External server manager not available",void 0,r.requestId);try{if(!n.listServers().find(c=>c.name===t))return sr("SERVER_NOT_FOUND",`Server '${t}' not found`,void 0,r.requestId);let a=n.getServerStatuses().find(c=>c.serverId===t);return{success:!0,server:{serverId:t,name:t,status:a?.status||"disconnected",toolCount:a?.toolCount||0},message:"Server status retrieved (full reconnect requires server restart)",metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}catch(o){return sr("RECONNECT_FAILED",o instanceof Error?o.message:String(o),void 0,r.requestId)}}async function Tcn(r){let e=hl(nw,r.params,r.requestId);if(!e.success)return e.error;let{name:t}=e.data,n=r.externalServerManager;if(!n)return sr("MCP_UNAVAILABLE","External server manager not available",void 0,r.requestId);try{let o=await n.removeServer(t);return o.success?{success:!0,message:`Server '${t}' removed`,metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}:sr("REMOVE_FAILED",o.error||"Failed to remove server",void 0,r.requestId)}catch(o){return sr("REMOVE_FAILED",o instanceof Error?o.message:String(o),void 0,r.requestId)}}async function Scn(r){let e=hl(nw,r.params,r.requestId);if(!e.success)return e.error;let{name:t}=e.data,o=(await r.toolRegistry.listTools()).filter(s=>s.source===t);if(o.length===0){let s=r.externalServerManager;if(s&&!s.listServers().find(c=>c.name===t))return sr("SERVER_NOT_FOUND",`MCP server '${t}' not found`,void 0,r.requestId)}return{serverId:t,tools:o.map(s=>({name:s.name,description:s.description,inputSchema:s.inputSchema})),total:o.length,metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}async function wcn(r){let e=hl(ycn,r.params,r.requestId);if(!e.success)return e.error;let{name:t,toolName:n}=e.data,o=lu(FR,r.body||{},r.requestId);if(!o.success)return o.error;let s=o.data,i=Date.now();try{return(await r.toolRegistry.listTools()).find(u=>u.name===n&&u.source===t)?{success:!0,data:await r.toolRegistry.executeTool(n,s),duration:Date.now()-i,metadata:{server:t,toolName:n,timestamp:new Date().toISOString(),requestId:r.requestId}}:sr("TOOL_NOT_FOUND",`Tool '${n}' not found on server '${t}'`,void 0,r.requestId)}catch(a){return sr("EXECUTION_FAILED",a instanceof Error?a.message:String(a),{duration:Date.now()-i},r.requestId)}}async function Ecn(r){let e=r.externalServerManager;if(!e)return{healthy:!1,message:"External server manager not available",servers:[]};let n=e.getServerStatuses().map(i=>({name:i.serverId,healthy:i.isHealthy,error:i.issues?.[0]})),o=n.every(i=>i.healthy),s=n.some(i=>i.healthy);return{healthy:n.length===0||o,status:n.length===0?"no_servers":o?"all_healthy":s?"degraded":"unhealthy",servers:n,timestamp:new Date().toISOString()}}function _F(r="/api"){return{prefix:`${r}/mcp`,routes:[{method:"GET",path:`${r}/mcp/servers`,handler:fw("neurolink.http.mcp.listServers",`${r}/mcp/servers`,xcn),description:"List all MCP servers",tags:["mcp"]},{method:"GET",path:`${r}/mcp/servers/:name`,handler:fw("neurolink.http.mcp.getServer",`${r}/mcp/servers/:name`,bcn),description:"Get MCP server status",tags:["mcp"]},{method:"POST",path:`${r}/mcp/servers/:name/reconnect`,handler:fw("neurolink.http.mcp.reconnectServer",`${r}/mcp/servers/:name/reconnect`,vcn),description:"Reconnect to an MCP server",tags:["mcp"]},{method:"DELETE",path:`${r}/mcp/servers/:name`,handler:fw("neurolink.http.mcp.removeServer",`${r}/mcp/servers/:name`,Tcn),description:"Remove an MCP server",tags:["mcp"]},{method:"GET",path:`${r}/mcp/servers/:name/tools`,handler:fw("neurolink.http.mcp.listServerTools",`${r}/mcp/servers/:name/tools`,Scn),description:"List tools from a specific MCP server",tags:["mcp","tools"]},{method:"POST",path:`${r}/mcp/servers/:name/tools/:toolName/execute`,handler:fw("neurolink.http.mcp.executeTool",`${r}/mcp/servers/:name/tools/:toolName/execute`,wcn),description:"Execute a tool from a specific MCP server",tags:["mcp","tools"]},{method:"GET",path:`${r}/mcp/health`,handler:fw("neurolink.http.mcp.health",`${r}/mcp/health`,Ecn),description:"Health check for all MCP servers",tags:["mcp","health"]}]}}An();Hr();Ff();function gw(r,e,t){return n=>Qe({name:r,tracer:Me.http,attributes:{"http.route":e,"http.request.id":n.requestId}},()=>t(n))}async function _cn(r){let e=hl(Oxe,r.params,r.requestId);if(!e.success)return e.error;let{id:t}=e.data,n=r.query.limit?parseInt(r.query.limit,10):50,o=r.query.offset?parseInt(r.query.offset,10):0,s=isNaN(n)||n<1?50:Math.min(n,100),i=isNaN(o)||o<0?0:o,a=r.neurolink.conversationMemory;if(!a)return sr("MEMORY_UNAVAILABLE","Conversation memory not available",void 0,r.requestId);try{let c=[];if("getUserSessionHistory"in a){let d=r.query.userId||"default",p=await a.getUserSessionHistory(d,t);if(p===null)return sr("SESSION_NOT_FOUND",`Session '${t}' not found`,void 0,r.requestId);c=p}else if("getSession"in a){let d=a.getSession(t);if(!d)return sr("SESSION_NOT_FOUND",`Session '${t}' not found`,void 0,r.requestId);c=d.messages}else if("buildContextMessages"in a&&(c=await a.buildContextMessages(t),c.length===0))return sr("SESSION_NOT_FOUND",`Session '${t}' not found or has no messages`,void 0,r.requestId);let l=c.length,u=c.slice(i,i+s);return{sessionId:t,messages:u,total:l,limit:s,offset:i,metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}catch(c){return sr("MEMORY_ERROR",c instanceof Error?c.message:"Failed to get session messages",void 0,r.requestId)}}async function kcn(r){let e=hl(Oxe,r.params,r.requestId);if(!e.success)return e.error;let{id:t}=e.data,n=r.neurolink.conversationMemory;if(!n)return sr("MEMORY_UNAVAILABLE","Conversation memory not available",void 0,r.requestId);try{if("getUserSessionObject"in n){let o=r.query.userId||"default",s=await n.getUserSessionObject(o,t);return s===null?sr("SESSION_NOT_FOUND",`Session '${t}' not found`,void 0,r.requestId):{session:s,metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}else if("getSession"in n){let o=n.getSession(t);return o?{session:o,metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}:sr("SESSION_NOT_FOUND",`Session '${t}' not found`,void 0,r.requestId)}return sr("MEMORY_ERROR","Session retrieval not supported for this memory type",void 0,r.requestId)}catch(o){return sr("MEMORY_ERROR",o instanceof Error?o.message:"Failed to get session",void 0,r.requestId)}}async function Ccn(r){let e=r.query.userId,t=r.query.limit?parseInt(r.query.limit,10):50,n=r.query.offset?parseInt(r.query.offset,10):0,o=isNaN(t)||t<1?50:Math.min(t,100),s=isNaN(n)||n<0?0:n,i=r.neurolink.conversationMemory;if(!i)return sr("MEMORY_UNAVAILABLE","Conversation memory not available",void 0,r.requestId);try{let a=[];if("getUserAllSessionsHistory"in i&&e)a=await i.getUserAllSessionsHistory(e);else if("getUserSessions"in i&&e){let u=await i.getUserSessions(e);if("getUserSessionMetadata"in i){let d=u.map(f=>i.getUserSessionMetadata(e,f));a=(await Promise.all(d)).filter(f=>f!==null)}else a=u.map(d=>({id:d}))}else if("getStats"in i){let u=await i.getStats?.();return{sessions:[],total:u?.totalSessions||0,limit:o,offset:s,message:"Session listing not fully supported for in-memory storage. Use /stats endpoint for session counts.",metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}let c=a.length;return{sessions:a.slice(s,s+o),total:c,limit:o,offset:s,metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}catch(a){return sr("MEMORY_ERROR",a instanceof Error?a.message:"Failed to list sessions",void 0,r.requestId)}}async function Rcn(r){let e=r.neurolink.conversationMemory;if(!e)return sr("MEMORY_UNAVAILABLE","Conversation memory not available",void 0,r.requestId);try{let t=await e.getStats?.();return{available:!0,type:e.constructor.name,stats:t||{message:"Statistics not available for this memory type"},timestamp:new Date().toISOString()}}catch(t){return sr("MEMORY_ERROR",t instanceof Error?t.message:"Failed to get statistics",void 0,r.requestId)}}async function Acn(r){let e=hl(D8,r.params,r.requestId);if(!e.success)return e.error;let{sessionId:t}=e.data,n=r.neurolink.conversationMemory;if(!n)return sr("MEMORY_UNAVAILABLE","Conversation memory not available",void 0,r.requestId);try{return await n.clearSession?.(t)===!1?sr("SESSION_NOT_FOUND",`Session '${t}' not found`,void 0,r.requestId):{success:!0,sessionId:t,message:"Session cleared successfully",metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}catch(o){return sr("MEMORY_ERROR",o instanceof Error?o.message:"Failed to clear session",void 0,r.requestId)}}async function Icn(r){let e=r.neurolink.conversationMemory;if(!e)return sr("MEMORY_UNAVAILABLE","Conversation memory not available",void 0,r.requestId);try{return await e.clearAllSessions?.(),{success:!0,message:"All sessions cleared successfully",metadata:{timestamp:new Date().toISOString(),requestId:r.requestId}}}catch(t){return sr("MEMORY_ERROR",t instanceof Error?t.message:"Failed to clear sessions",void 0,r.requestId)}}async function Pcn(r){let e=r.neurolink.conversationMemory;return{available:!!e,type:e?.constructor.name||"none",timestamp:new Date().toISOString()}}function kF(r="/api"){return{prefix:`${r}/memory`,routes:[{method:"GET",path:`${r}/memory/sessions/:id/messages`,handler:gw("neurolink.http.memory.getSessionMessages",`${r}/memory/sessions/:id/messages`,_cn),description:"Get messages for a session",tags:["memory"]},{method:"GET",path:`${r}/memory/sessions/:id`,handler:gw("neurolink.http.memory.getSession",`${r}/memory/sessions/:id`,kcn),description:"Get session by ID",tags:["memory"]},{method:"GET",path:`${r}/memory/sessions`,handler:gw("neurolink.http.memory.listSessions",`${r}/memory/sessions`,Ccn),description:"List all conversation sessions",tags:["memory"]},{method:"GET",path:`${r}/memory/stats`,handler:gw("neurolink.http.memory.stats",`${r}/memory/stats`,Rcn),description:"Get memory statistics",tags:["memory"]},{method:"DELETE",path:`${r}/memory/sessions/:sessionId`,handler:gw("neurolink.http.memory.clearSession",`${r}/memory/sessions/:sessionId`,Acn),description:"Clear a conversation session",tags:["memory"]},{method:"DELETE",path:`${r}/memory/sessions`,handler:gw("neurolink.http.memory.clearAllSessions",`${r}/memory/sessions`,Icn),description:"Clear all conversation sessions",tags:["memory"]},{method:"GET",path:`${r}/memory/health`,handler:gw("neurolink.http.memory.health",`${r}/memory/health`,Pcn),description:"Check memory system health",tags:["memory","health"]}]}}J();An();Hr();function Uve(r="/api",e){return e||g.debug("[OpenAPI] createOpenApiRoutes called without getRoutes callback. Custom routes will not be documented in the OpenAPI spec."),{prefix:`${r}/openapi`,routes:[{method:"GET",path:`${r}/openapi.json`,handler:async()=>Qe({name:"neurolink.http.openapi.json",tracer:Me.http,attributes:{"http.route":`${r}/openapi.json`,"openapi.format":"json"}},async t=>{let n=e?.()??[];return e?n.length===0&&g.debug("[OpenAPI] getRoutes returned empty array. No custom routes will be documented."):g.warn("[OpenAPI] No getRoutes callback provided. OpenAPI spec will use default endpoint definitions. Use registerAllRoutes(server, basePath, { enableSwagger: true }) to automatically include your routes."),t.setAttribute("openapi.route_count",n.length),new Bf({basePath:r,routes:n}).generate()}),description:"Get OpenAPI specification as JSON",tags:["openapi","documentation"]},{method:"GET",path:`${r}/openapi.yaml`,handler:async()=>Qe({name:"neurolink.http.openapi.yaml",tracer:Me.http,attributes:{"http.route":`${r}/openapi.yaml`,"openapi.format":"yaml"}},async t=>{let n=e?.()??[];return e?n.length===0&&g.debug("[OpenAPI] getRoutes returned empty array. No custom routes will be documented."):g.warn("[OpenAPI] No getRoutes callback provided. OpenAPI spec will use default endpoint definitions. Use registerAllRoutes(server, basePath, { enableSwagger: true }) to automatically include your routes."),t.setAttribute("openapi.route_count",n.length),{_raw:!0,contentType:"text/yaml",body:new Bf({basePath:r,routes:n}).toYAML()}}),description:"Get OpenAPI specification as YAML",tags:["openapi","documentation"]},{method:"GET",path:`${r}/docs`,handler:async()=>Qe({name:"neurolink.http.openapi.docs",tracer:Me.http,attributes:{"http.route":`${r}/docs`}},async()=>({_raw:!0,contentType:"text/html",body:`<!DOCTYPE html>
|
|
@@ -44,7 +44,7 @@ function printAnalysis(report) {
|
|
|
44
44
|
logger.always("");
|
|
45
45
|
logger.always(chalk.bold(" Account Routing"));
|
|
46
46
|
if (report.coverage.routingDecisions) {
|
|
47
|
-
logger.always(` Decisions: ${report.routing.records.length}, modes: ${JSON.stringify(report.routing.modes)}`);
|
|
47
|
+
logger.always(` Decisions: ${report.routing.totalRecords} (${report.routing.records.length} retained), modes: ${JSON.stringify(report.routing.modes)}`);
|
|
48
48
|
logger.always(` Selection reasons: ${JSON.stringify(report.routing.selectionReasons)}`);
|
|
49
49
|
logger.always(` Initial accounts: ${JSON.stringify(report.routing.initialAccounts)}`);
|
|
50
50
|
logger.always(` Final account changed after retry: ${report.routing.finalAccountChanges}, outside candidate set: ${report.routing.finalOutsideCandidateSet}`);
|
|
@@ -20,6 +20,8 @@ const ROUTING_MODES = new Set(PROXY_ACCOUNT_ROUTING_MODES);
|
|
|
20
20
|
const ROUTING_REASONS = new Set(PROXY_ACCOUNT_ROUTING_REASONS);
|
|
21
21
|
const ROUTING_ACCOUNT_TYPES = new Set(PROXY_ACCOUNT_TYPES);
|
|
22
22
|
const COOLING_REASONS = new Set(ACCOUNT_COOLING_REASONS);
|
|
23
|
+
const MAX_RETAINED_ROUTING_RECORDS = 200;
|
|
24
|
+
const MAX_ROUTING_RECORDS_BEFORE_COMPACTION = MAX_RETAINED_ROUTING_RECORDS * 2;
|
|
23
25
|
function isContainedPath(root, candidate) {
|
|
24
26
|
const candidateRelative = relative(root, candidate);
|
|
25
27
|
return (candidateRelative.length > 0 &&
|
|
@@ -338,7 +340,8 @@ function summarizeRouting(finalRequests) {
|
|
|
338
340
|
const modes = {};
|
|
339
341
|
const selectionReasons = {};
|
|
340
342
|
const initialAccounts = {};
|
|
341
|
-
const
|
|
343
|
+
const retainedRecords = [];
|
|
344
|
+
let totalRecords = 0;
|
|
342
345
|
let finalAccountChanges = 0;
|
|
343
346
|
let finalOutsideCandidateSet = 0;
|
|
344
347
|
for (const [requestId, request] of finalRequests) {
|
|
@@ -357,21 +360,36 @@ function summarizeRouting(finalRequests) {
|
|
|
357
360
|
else if (decision.initialAccount !== request.account) {
|
|
358
361
|
finalAccountChanges += 1;
|
|
359
362
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
363
|
+
totalRecords += 1;
|
|
364
|
+
retainedRecords.push({
|
|
365
|
+
record: {
|
|
366
|
+
requestId,
|
|
367
|
+
timestamp: request.timestamp,
|
|
368
|
+
responseStatus: request.status,
|
|
369
|
+
finalAccount: request.account,
|
|
370
|
+
finalAccountType: request.accountType,
|
|
371
|
+
decision,
|
|
372
|
+
},
|
|
373
|
+
timestampMs: Date.parse(request.timestamp),
|
|
374
|
+
sequence: totalRecords,
|
|
367
375
|
});
|
|
376
|
+
if (retainedRecords.length > MAX_ROUTING_RECORDS_BEFORE_COMPACTION) {
|
|
377
|
+
retainedRecords.sort((left, right) => left.timestampMs - right.timestampMs ||
|
|
378
|
+
left.sequence - right.sequence);
|
|
379
|
+
retainedRecords.splice(0, retainedRecords.length - MAX_RETAINED_ROUTING_RECORDS);
|
|
380
|
+
}
|
|
368
381
|
}
|
|
382
|
+
retainedRecords.sort((left, right) => left.timestampMs - right.timestampMs || left.sequence - right.sequence);
|
|
383
|
+
const records = retainedRecords
|
|
384
|
+
.slice(-MAX_RETAINED_ROUTING_RECORDS)
|
|
385
|
+
.map(({ record }) => record);
|
|
369
386
|
return {
|
|
370
387
|
modes,
|
|
371
388
|
selectionReasons,
|
|
372
389
|
initialAccounts,
|
|
373
390
|
finalAccountChanges,
|
|
374
391
|
finalOutsideCandidateSet,
|
|
392
|
+
totalRecords,
|
|
375
393
|
records,
|
|
376
394
|
};
|
|
377
395
|
}
|
|
@@ -704,7 +722,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
704
722
|
attempts: totalAttempts > 0,
|
|
705
723
|
attemptLatency: attemptLatency.length > 0,
|
|
706
724
|
cacheUsage: finalSummary.cache.requestsWithUsage > 0,
|
|
707
|
-
routingDecisions: routingSummary.
|
|
725
|
+
routingDecisions: routingSummary.totalRecords > 0,
|
|
708
726
|
},
|
|
709
727
|
dataQuality: {
|
|
710
728
|
linesRead,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { buildTranslationOptions } from "../../proxy/proxyTranslationEngine.js";
|
|
13
13
|
import { ProxyTracer } from "../../proxy/proxyTracer.js";
|
|
14
14
|
import { isPermanentRefreshFailure } from "../../proxy/tokenRefresh.js";
|
|
15
|
-
import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ClaudeProxyRouteRuntimeOptions, ModelRouterInterface, ParsedClaudeError, ProxyAccountRoutingDecision, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
|
|
15
|
+
import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ClaudeProxyRouteRuntimeOptions, ModelRouterInterface, ParsedClaudeError, ProxyAccountRoutingDecision, ProxyAccountSortMetrics, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
|
|
16
16
|
/** Resolve the configured primary's stable key to its current index in the
|
|
17
17
|
* request's enabledAccounts list. Returns 0 (insertion-order fallback) when
|
|
18
18
|
* no key is configured or the key cannot be matched (account disabled/
|
|
@@ -85,6 +85,19 @@ declare function seedRuntimeQuotasFromDisk(accounts: ProxyPassthroughAccount[]):
|
|
|
85
85
|
* last resort.
|
|
86
86
|
*/
|
|
87
87
|
declare function orderAccountsByQuota(accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number): ProxyPassthroughAccount[];
|
|
88
|
+
declare function buildRoutingDecision(args: {
|
|
89
|
+
accounts: ProxyPassthroughAccount[];
|
|
90
|
+
orderedAccounts: ProxyPassthroughAccount[];
|
|
91
|
+
metricsByKey: ReadonlyMap<string, ProxyAccountSortMetrics>;
|
|
92
|
+
evaluatedAt: number;
|
|
93
|
+
strategy: "round-robin" | "fill-first";
|
|
94
|
+
primaryKey: string | undefined;
|
|
95
|
+
quotaRoutingEnabled: boolean;
|
|
96
|
+
quotaOrdered: boolean;
|
|
97
|
+
sessionSoftLimit: number;
|
|
98
|
+
sessionResetToleranceMs: number;
|
|
99
|
+
rotationOffset: number;
|
|
100
|
+
}): ProxyAccountRoutingDecision | undefined;
|
|
88
101
|
declare function trackUpstreamReadableStream(source: ReadableStream<Uint8Array>): {
|
|
89
102
|
stream: ReadableStream<Uint8Array>;
|
|
90
103
|
outcome: Promise<StreamTerminalOutcome>;
|
|
@@ -279,7 +292,8 @@ export declare const __testHooks: {
|
|
|
279
292
|
getStreamFailureDetails: typeof getStreamFailureDetails;
|
|
280
293
|
trackUpstreamReadableStream: typeof trackUpstreamReadableStream;
|
|
281
294
|
orderAccountsByQuota: typeof orderAccountsByQuota;
|
|
282
|
-
buildQuotaRoutingDecision: (accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number) => ProxyAccountRoutingDecision;
|
|
295
|
+
buildQuotaRoutingDecision: (accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number) => ProxyAccountRoutingDecision | undefined;
|
|
296
|
+
buildRoutingDecision: typeof buildRoutingDecision;
|
|
283
297
|
resetEpochToMs: typeof resetEpochToMs;
|
|
284
298
|
seedRuntimeQuotasFromDisk: typeof seedRuntimeQuotasFromDisk;
|
|
285
299
|
reconcileEligibleAccountRuntimeState: typeof reconcileEligibleAccountRuntimeState;
|
|
@@ -562,16 +562,18 @@ function buildRoutingDecision(args) {
|
|
|
562
562
|
const { accounts, orderedAccounts, metricsByKey, evaluatedAt, strategy, primaryKey, quotaRoutingEnabled, quotaOrdered, sessionSoftLimit, sessionResetToleranceMs, rotationOffset, } = args;
|
|
563
563
|
const sourceIndexes = new Map(accounts.map((account, index) => [account.key, index]));
|
|
564
564
|
const configuredPrimaryMatched = !!primaryKey && accounts.some((account) => account.key === primaryKey);
|
|
565
|
-
const candidates =
|
|
565
|
+
const candidates = [];
|
|
566
|
+
for (const account of orderedAccounts) {
|
|
566
567
|
const metrics = metricsByKey.get(account.key);
|
|
567
568
|
if (!metrics) {
|
|
568
|
-
|
|
569
|
+
logger.warn(`[proxy] routing evidence omitted because metrics are missing for account=${account.label}`);
|
|
570
|
+
return undefined;
|
|
569
571
|
}
|
|
570
|
-
|
|
572
|
+
candidates.push({
|
|
571
573
|
account: account.label,
|
|
572
574
|
accountType: account.type,
|
|
573
|
-
sourceIndex: sourceIndexes.get(account.key) ??
|
|
574
|
-
rank,
|
|
575
|
+
sourceIndex: sourceIndexes.get(account.key) ?? candidates.length,
|
|
576
|
+
rank: candidates.length,
|
|
575
577
|
configuredPrimary: !!primaryKey && account.key === primaryKey,
|
|
576
578
|
usable: metrics.usable,
|
|
577
579
|
saturated: metrics.saturated,
|
|
@@ -598,8 +600,8 @@ function buildRoutingDecision(args) {
|
|
|
598
600
|
weeklyResetAt: Number.isFinite(metrics.weeklyReset)
|
|
599
601
|
? metrics.weeklyReset
|
|
600
602
|
: null,
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
+
});
|
|
604
|
+
}
|
|
603
605
|
const initialAccount = orderedAccounts[0];
|
|
604
606
|
let mode;
|
|
605
607
|
let selectionReason;
|
|
@@ -684,7 +686,7 @@ function selectClaudeProxyAccountOrder(args) {
|
|
|
684
686
|
accountSortMetrics(account.key, evaluatedAt, sessionSoftLimit, sessionResetToleranceMs),
|
|
685
687
|
]));
|
|
686
688
|
}
|
|
687
|
-
|
|
689
|
+
const routingDecision = buildRoutingDecision({
|
|
688
690
|
accounts: enabledAccounts,
|
|
689
691
|
orderedAccounts,
|
|
690
692
|
metricsByKey,
|
|
@@ -696,7 +698,10 @@ function selectClaudeProxyAccountOrder(args) {
|
|
|
696
698
|
sessionSoftLimit,
|
|
697
699
|
sessionResetToleranceMs,
|
|
698
700
|
rotationOffset,
|
|
699
|
-
})
|
|
701
|
+
});
|
|
702
|
+
if (routingDecision) {
|
|
703
|
+
setRoutingDecision(routingDecision);
|
|
704
|
+
}
|
|
700
705
|
return orderedAccounts;
|
|
701
706
|
}
|
|
702
707
|
// ---------------------------------------------------------------------------
|
|
@@ -4896,6 +4901,7 @@ export const __testHooks = {
|
|
|
4896
4901
|
rotationOffset: 0,
|
|
4897
4902
|
});
|
|
4898
4903
|
},
|
|
4904
|
+
buildRoutingDecision,
|
|
4899
4905
|
resetEpochToMs,
|
|
4900
4906
|
seedRuntimeQuotasFromDisk,
|
|
4901
4907
|
reconcileEligibleAccountRuntimeState,
|
|
@@ -1341,6 +1341,9 @@ export type ProxyAnalysisReport = {
|
|
|
1341
1341
|
initialAccounts: Record<string, number>;
|
|
1342
1342
|
finalAccountChanges: number;
|
|
1343
1343
|
finalOutsideCandidateSet: number;
|
|
1344
|
+
/** Number of routing decisions aggregated before sampling records. */
|
|
1345
|
+
totalRecords: number;
|
|
1346
|
+
/** Most recent bounded sample retained for offline inspection. */
|
|
1344
1347
|
records: ProxyAnalysisRoutingRecord[];
|
|
1345
1348
|
};
|
|
1346
1349
|
accounts: ProxyAnalysisAccount[];
|
|
@@ -20,6 +20,8 @@ const ROUTING_MODES = new Set(PROXY_ACCOUNT_ROUTING_MODES);
|
|
|
20
20
|
const ROUTING_REASONS = new Set(PROXY_ACCOUNT_ROUTING_REASONS);
|
|
21
21
|
const ROUTING_ACCOUNT_TYPES = new Set(PROXY_ACCOUNT_TYPES);
|
|
22
22
|
const COOLING_REASONS = new Set(ACCOUNT_COOLING_REASONS);
|
|
23
|
+
const MAX_RETAINED_ROUTING_RECORDS = 200;
|
|
24
|
+
const MAX_ROUTING_RECORDS_BEFORE_COMPACTION = MAX_RETAINED_ROUTING_RECORDS * 2;
|
|
23
25
|
function isContainedPath(root, candidate) {
|
|
24
26
|
const candidateRelative = relative(root, candidate);
|
|
25
27
|
return (candidateRelative.length > 0 &&
|
|
@@ -338,7 +340,8 @@ function summarizeRouting(finalRequests) {
|
|
|
338
340
|
const modes = {};
|
|
339
341
|
const selectionReasons = {};
|
|
340
342
|
const initialAccounts = {};
|
|
341
|
-
const
|
|
343
|
+
const retainedRecords = [];
|
|
344
|
+
let totalRecords = 0;
|
|
342
345
|
let finalAccountChanges = 0;
|
|
343
346
|
let finalOutsideCandidateSet = 0;
|
|
344
347
|
for (const [requestId, request] of finalRequests) {
|
|
@@ -357,21 +360,36 @@ function summarizeRouting(finalRequests) {
|
|
|
357
360
|
else if (decision.initialAccount !== request.account) {
|
|
358
361
|
finalAccountChanges += 1;
|
|
359
362
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
363
|
+
totalRecords += 1;
|
|
364
|
+
retainedRecords.push({
|
|
365
|
+
record: {
|
|
366
|
+
requestId,
|
|
367
|
+
timestamp: request.timestamp,
|
|
368
|
+
responseStatus: request.status,
|
|
369
|
+
finalAccount: request.account,
|
|
370
|
+
finalAccountType: request.accountType,
|
|
371
|
+
decision,
|
|
372
|
+
},
|
|
373
|
+
timestampMs: Date.parse(request.timestamp),
|
|
374
|
+
sequence: totalRecords,
|
|
367
375
|
});
|
|
376
|
+
if (retainedRecords.length > MAX_ROUTING_RECORDS_BEFORE_COMPACTION) {
|
|
377
|
+
retainedRecords.sort((left, right) => left.timestampMs - right.timestampMs ||
|
|
378
|
+
left.sequence - right.sequence);
|
|
379
|
+
retainedRecords.splice(0, retainedRecords.length - MAX_RETAINED_ROUTING_RECORDS);
|
|
380
|
+
}
|
|
368
381
|
}
|
|
382
|
+
retainedRecords.sort((left, right) => left.timestampMs - right.timestampMs || left.sequence - right.sequence);
|
|
383
|
+
const records = retainedRecords
|
|
384
|
+
.slice(-MAX_RETAINED_ROUTING_RECORDS)
|
|
385
|
+
.map(({ record }) => record);
|
|
369
386
|
return {
|
|
370
387
|
modes,
|
|
371
388
|
selectionReasons,
|
|
372
389
|
initialAccounts,
|
|
373
390
|
finalAccountChanges,
|
|
374
391
|
finalOutsideCandidateSet,
|
|
392
|
+
totalRecords,
|
|
375
393
|
records,
|
|
376
394
|
};
|
|
377
395
|
}
|
|
@@ -704,7 +722,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
704
722
|
attempts: totalAttempts > 0,
|
|
705
723
|
attemptLatency: attemptLatency.length > 0,
|
|
706
724
|
cacheUsage: finalSummary.cache.requestsWithUsage > 0,
|
|
707
|
-
routingDecisions: routingSummary.
|
|
725
|
+
routingDecisions: routingSummary.totalRecords > 0,
|
|
708
726
|
},
|
|
709
727
|
dataQuality: {
|
|
710
728
|
linesRead,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { buildTranslationOptions } from "../../proxy/proxyTranslationEngine.js";
|
|
13
13
|
import { ProxyTracer } from "../../proxy/proxyTracer.js";
|
|
14
14
|
import { isPermanentRefreshFailure } from "../../proxy/tokenRefresh.js";
|
|
15
|
-
import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ClaudeProxyRouteRuntimeOptions, ModelRouterInterface, ParsedClaudeError, ProxyAccountRoutingDecision, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
|
|
15
|
+
import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ClaudeProxyRouteRuntimeOptions, ModelRouterInterface, ParsedClaudeError, ProxyAccountRoutingDecision, ProxyAccountSortMetrics, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
|
|
16
16
|
/** Resolve the configured primary's stable key to its current index in the
|
|
17
17
|
* request's enabledAccounts list. Returns 0 (insertion-order fallback) when
|
|
18
18
|
* no key is configured or the key cannot be matched (account disabled/
|
|
@@ -85,6 +85,19 @@ declare function seedRuntimeQuotasFromDisk(accounts: ProxyPassthroughAccount[]):
|
|
|
85
85
|
* last resort.
|
|
86
86
|
*/
|
|
87
87
|
declare function orderAccountsByQuota(accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number): ProxyPassthroughAccount[];
|
|
88
|
+
declare function buildRoutingDecision(args: {
|
|
89
|
+
accounts: ProxyPassthroughAccount[];
|
|
90
|
+
orderedAccounts: ProxyPassthroughAccount[];
|
|
91
|
+
metricsByKey: ReadonlyMap<string, ProxyAccountSortMetrics>;
|
|
92
|
+
evaluatedAt: number;
|
|
93
|
+
strategy: "round-robin" | "fill-first";
|
|
94
|
+
primaryKey: string | undefined;
|
|
95
|
+
quotaRoutingEnabled: boolean;
|
|
96
|
+
quotaOrdered: boolean;
|
|
97
|
+
sessionSoftLimit: number;
|
|
98
|
+
sessionResetToleranceMs: number;
|
|
99
|
+
rotationOffset: number;
|
|
100
|
+
}): ProxyAccountRoutingDecision | undefined;
|
|
88
101
|
declare function trackUpstreamReadableStream(source: ReadableStream<Uint8Array>): {
|
|
89
102
|
stream: ReadableStream<Uint8Array>;
|
|
90
103
|
outcome: Promise<StreamTerminalOutcome>;
|
|
@@ -279,7 +292,8 @@ export declare const __testHooks: {
|
|
|
279
292
|
getStreamFailureDetails: typeof getStreamFailureDetails;
|
|
280
293
|
trackUpstreamReadableStream: typeof trackUpstreamReadableStream;
|
|
281
294
|
orderAccountsByQuota: typeof orderAccountsByQuota;
|
|
282
|
-
buildQuotaRoutingDecision: (accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number) => ProxyAccountRoutingDecision;
|
|
295
|
+
buildQuotaRoutingDecision: (accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number) => ProxyAccountRoutingDecision | undefined;
|
|
296
|
+
buildRoutingDecision: typeof buildRoutingDecision;
|
|
283
297
|
resetEpochToMs: typeof resetEpochToMs;
|
|
284
298
|
seedRuntimeQuotasFromDisk: typeof seedRuntimeQuotasFromDisk;
|
|
285
299
|
reconcileEligibleAccountRuntimeState: typeof reconcileEligibleAccountRuntimeState;
|
|
@@ -562,16 +562,18 @@ function buildRoutingDecision(args) {
|
|
|
562
562
|
const { accounts, orderedAccounts, metricsByKey, evaluatedAt, strategy, primaryKey, quotaRoutingEnabled, quotaOrdered, sessionSoftLimit, sessionResetToleranceMs, rotationOffset, } = args;
|
|
563
563
|
const sourceIndexes = new Map(accounts.map((account, index) => [account.key, index]));
|
|
564
564
|
const configuredPrimaryMatched = !!primaryKey && accounts.some((account) => account.key === primaryKey);
|
|
565
|
-
const candidates =
|
|
565
|
+
const candidates = [];
|
|
566
|
+
for (const account of orderedAccounts) {
|
|
566
567
|
const metrics = metricsByKey.get(account.key);
|
|
567
568
|
if (!metrics) {
|
|
568
|
-
|
|
569
|
+
logger.warn(`[proxy] routing evidence omitted because metrics are missing for account=${account.label}`);
|
|
570
|
+
return undefined;
|
|
569
571
|
}
|
|
570
|
-
|
|
572
|
+
candidates.push({
|
|
571
573
|
account: account.label,
|
|
572
574
|
accountType: account.type,
|
|
573
|
-
sourceIndex: sourceIndexes.get(account.key) ??
|
|
574
|
-
rank,
|
|
575
|
+
sourceIndex: sourceIndexes.get(account.key) ?? candidates.length,
|
|
576
|
+
rank: candidates.length,
|
|
575
577
|
configuredPrimary: !!primaryKey && account.key === primaryKey,
|
|
576
578
|
usable: metrics.usable,
|
|
577
579
|
saturated: metrics.saturated,
|
|
@@ -598,8 +600,8 @@ function buildRoutingDecision(args) {
|
|
|
598
600
|
weeklyResetAt: Number.isFinite(metrics.weeklyReset)
|
|
599
601
|
? metrics.weeklyReset
|
|
600
602
|
: null,
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
+
});
|
|
604
|
+
}
|
|
603
605
|
const initialAccount = orderedAccounts[0];
|
|
604
606
|
let mode;
|
|
605
607
|
let selectionReason;
|
|
@@ -684,7 +686,7 @@ function selectClaudeProxyAccountOrder(args) {
|
|
|
684
686
|
accountSortMetrics(account.key, evaluatedAt, sessionSoftLimit, sessionResetToleranceMs),
|
|
685
687
|
]));
|
|
686
688
|
}
|
|
687
|
-
|
|
689
|
+
const routingDecision = buildRoutingDecision({
|
|
688
690
|
accounts: enabledAccounts,
|
|
689
691
|
orderedAccounts,
|
|
690
692
|
metricsByKey,
|
|
@@ -696,7 +698,10 @@ function selectClaudeProxyAccountOrder(args) {
|
|
|
696
698
|
sessionSoftLimit,
|
|
697
699
|
sessionResetToleranceMs,
|
|
698
700
|
rotationOffset,
|
|
699
|
-
})
|
|
701
|
+
});
|
|
702
|
+
if (routingDecision) {
|
|
703
|
+
setRoutingDecision(routingDecision);
|
|
704
|
+
}
|
|
700
705
|
return orderedAccounts;
|
|
701
706
|
}
|
|
702
707
|
// ---------------------------------------------------------------------------
|
|
@@ -4896,6 +4901,7 @@ export const __testHooks = {
|
|
|
4896
4901
|
rotationOffset: 0,
|
|
4897
4902
|
});
|
|
4898
4903
|
},
|
|
4904
|
+
buildRoutingDecision,
|
|
4899
4905
|
resetEpochToMs,
|
|
4900
4906
|
seedRuntimeQuotasFromDisk,
|
|
4901
4907
|
reconcileEligibleAccountRuntimeState,
|
package/dist/types/proxy.d.ts
CHANGED
|
@@ -1341,6 +1341,9 @@ export type ProxyAnalysisReport = {
|
|
|
1341
1341
|
initialAccounts: Record<string, number>;
|
|
1342
1342
|
finalAccountChanges: number;
|
|
1343
1343
|
finalOutsideCandidateSet: number;
|
|
1344
|
+
/** Number of routing decisions aggregated before sampling records. */
|
|
1345
|
+
totalRecords: number;
|
|
1346
|
+
/** Most recent bounded sample retained for offline inspection. */
|
|
1344
1347
|
records: ProxyAnalysisRoutingRecord[];
|
|
1345
1348
|
};
|
|
1346
1349
|
accounts: ProxyAnalysisAccount[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.7.
|
|
3
|
+
"version": "10.7.1",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|