@juspay/neurolink 12.36.1 → 12.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -3
- package/dist/browser/neurolink.min.js +1 -1
- package/dist/proxy/argumentParsing.d.ts +12 -0
- package/dist/proxy/argumentParsing.js +23 -0
- package/dist/proxy/codexOutboundFallback.d.ts +10 -6
- package/dist/proxy/codexOutboundFallback.js +163 -43
- package/dist/proxy/codexResponsesFormat.d.ts +125 -0
- package/dist/proxy/codexResponsesFormat.js +591 -0
- package/dist/proxy/codexToAnthropicFallback.d.ts +54 -0
- package/dist/proxy/codexToAnthropicFallback.js +408 -0
- package/dist/proxy/proxyTracer.d.ts +21 -0
- package/dist/proxy/proxyTracer.js +45 -0
- package/dist/proxy/streamLimits.d.ts +16 -0
- package/dist/proxy/streamLimits.js +16 -0
- package/dist/types/codex.d.ts +113 -1
- package/dist/types/proxy.d.ts +12 -1
- package/docs-site/static/search-index.json +7 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
## [12.
|
|
1
|
+
## [12.37.0](https://github.com/juspay/neurolink/compare/v12.36.1...v12.37.0) (2026-09-28)
|
|
2
2
|
|
|
3
|
-
###
|
|
3
|
+
### Features
|
|
4
4
|
|
|
5
|
-
- **(
|
|
5
|
+
- **(proxy):** translate Anthropic responses and tool calls to the Codex wire format ([bef0c19](https://github.com/juspay/neurolink/commit/bef0c19db259cd2d5f6ee4816ef6d9bbf72c8271)), closes [#1842](https://github.com/juspay/neurolink/issues/1842)
|
|
6
6
|
|
|
7
7
|
## [11.2.3](https://github.com/juspay/neurolink/compare/v11.2.2...v11.2.3) (2026-08-19)
|
|
8
8
|
|
|
@@ -2352,7 +2352,7 @@ data: ${r}
|
|
|
2352
2352
|
|
|
2353
2353
|
`}else yield*o.emitError("Upstream generation failed")}}const u=l(),d=new TextEncoder,m=n.capture.accumulator("client_response","text/event-stream");let h=!1,f,g;const y=()=>{m.finish(n.signal.reason?.name==="TimeoutError"?504:499),h=!0,g?.error(n.signal.reason??new DOMException("Client disconnected","AbortError")),i.return().catch(()=>{}),u.return().catch(()=>{})},v=new ReadableStream({start(w){g=w,n.signal.addEventListener("abort",y,{once:!0}),n.signal.aborted&&y()},async pull(w){if(h)return;f??=u.next();let E;try{const _=await Promise.race([f,new Promise(C=>{E=setTimeout(()=>C(null),15e3),E.unref?.()})]);if(h)return;if(_===null){const C=d.encode(`: keep-alive
|
|
2354
2354
|
|
|
2355
|
-
`);m.append(C),w.enqueue(C);return}if(f=void 0,_.done)h=!0,n.signal.removeEventListener("abort",y),m.finish(200),w.close();else{const C=d.encode(_.value);m.append(C),w.enqueue(C)}}catch(_){h||(m.finish(502),h=!0,w.error(_))}finally{E&&clearTimeout(E)}},cancel(w){m.finish(499),h=!0,n.signal.removeEventListener("abort",y),n.cancel(w),u.return().catch(()=>{})}},{highWaterMark:0});return new Response(v,{headers:{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"}})}async function j$(e){const t=yfr({...e,stream:!1});let r="",n;try{for await(const a of vfr({...e,request:t}))a.reset&&(r=""),a.text!==void 0&&(r+=a.text),a.result&&(n=a.result);t.signal.throwIfAborted(),t.finalize(200);const o=n?.usage?ffr(n.usage):void 0,s={content:r,model:n?.model,finishReason:n?.finishReason??tue(e.format),usage:o,toolCalls:n?.toolCalls},i=e.format==="claude"?Gpr(s,e.requestModel):e.format==="gemini"?xcn(r,s.finishReason??tue(e.format),o??{input:0,output:0,total:0},s.model??e.requestModel,s.toolCalls):Thr(s,e.requestModel);return t.capture.json(i,200),i}catch(o){if(e.deferFinalOnError&&!t.signal.aborted)throw t.abandon(),o;const s=Jg(o),i=s?.message??lr(o instanceof Error?o.message:String(o),500),a=Wc(o),c=t.signal.reason?.name==="TimeoutError"||o instanceof Error&&o.name==="TimeoutError",l=a?.status??(o instanceof _r?o.status:c?504:t.signal.aborted?499:s?.status??e.terminalFailureStatus??502),u=a?.code??(o instanceof _r?o.code:s?.code);t.finalize(l,c?"upstream_timeout":t.signal.aborted?"client_cancelled":"generation_error",i,u,s?.retryable);const d=a?.message??(o instanceof _r?o.message:"Upstream generation failed");return wfr(e.format,l,d,u,t.capture,s?.retryable)}}function tun(e){const t=[];if(e){const r=e.getModelMappings?.()??[];for(const o of r)t.push({id:o.from,object:"model",created:0,owned_by:"neurolink"});const n=e.getPassthroughModels?.()??[];for(const o of n)t.push({id:o,object:"model",created:0,owned_by:"neurolink"})}if(t.length===0)for(const r of hfr)t.push({id:r,object:"model",created:0,owned_by:"neurolink"});return{object:"list",data:t}}function run(e){const t=[];if(e){const s=e.getModelMappings?.()??[];for(const a of s)a.from&&t.push(a.from);const i=e.getPassthroughModels?.()??[];for(const a of i)t.push(a)}t.length===0&&t.push(...hfr);const r=new Set,o=t.filter(s=>r.has(s)?!1:(r.add(s),!0)).map(s=>({type:"model",id:s,display_name:nun(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 nun(e){const r=e.replace(/-\d{8}$/,"").split("-"),n=[],o=[];for(const i of r)/^\d+$/.test(i)&&o.length>0&&o[0].toLowerCase()==="claude"?n.push(i):o.push(i.charAt(0).toUpperCase()+i.slice(1));const s=n.length>0?` ${n.join(".")}`:"";return o.length>0?`${o[0]}${s}${o.slice(1).length?" "+o.slice(1).join(" "):""}`:e}pr(),Or(),Xt(),np(),xDr(),qa(),Ub(),z();var oun="[ProxyTracer]",rue=null;function Ax(){if(rue)return rue;const e=nh.getMeter("neurolink.proxy","1.0.0"),t={requestsTotal:e.createCounter("proxy_requests_total",{description:"Total number of proxy requests",unit:"{request}"}),requestDuration:e.createHistogram("proxy_request_duration_ms",{description:"Proxy request duration in milliseconds",unit:"ms"}),tokensInput:e.createCounter("proxy_tokens_input",{description:"Total input tokens consumed via proxy",unit:"{token}"}),tokensOutput:e.createCounter("proxy_tokens_output",{description:"Total output tokens produced via proxy",unit:"{token}"}),tokensCacheRead:e.createCounter("proxy_tokens_cache_read",{description:"Total cache-read tokens via proxy",unit:"{token}"}),tokensCacheCreation:e.createCounter("proxy_tokens_cache_creation",{description:"Total cache-creation tokens via proxy",unit:"{token}"}),tokensReasoning:e.createCounter("proxy_tokens_reasoning",{description:"Total reasoning tokens via proxy",unit:"{token}"}),costTotal:e.createCounter("proxy_cost_usd_total",{description:"Total estimated cost in USD",unit:"USD"}),errorsTotal:e.createCounter("proxy_errors_total",{description:"Total proxy errors",unit:"{error}"}),retriesTotal:e.createCounter("proxy_retries_total",{description:"Total upstream retry attempts",unit:"{retry}"}),modelSubstitutionTotal:e.createCounter("proxy_model_substitution_total",{description:"Total proxy requests where the response model differs from the requested model",unit:"{substitution}"}),requestBodySize:e.createHistogram("proxy_request_body_bytes",{description:"Request body size in bytes sent upstream",unit:"By"}),responseBodySize:e.createHistogram("proxy_response_body_bytes",{description:"Response body size in bytes received from upstream",unit:"By"}),fallbackAttemptsTotal:e.createCounter("proxy_fallback_attempts_total",{description:"Total fallback provider attempts",unit:"{attempt}"}),fallbackSuccessTotal:e.createCounter("proxy_fallback_success_total",{description:"Total successful fallback provider responses",unit:"{success}"}),fallbackFailureTotal:e.createCounter("proxy_fallback_failure_total",{description:"Total failed fallback provider responses",unit:"{failure}"})};return rue=t,t}var sun=new Set(["authorization","proxy-authorization","x-api-key","cookie","set-cookie"]),iun=/token|secret|key|password|credential/i;function nue(e){const t={};for(const[r,n]of Object.entries(e)){const o=r.toLowerCase();sun.has(o)||iun.test(o)?t[r]="[REDACTED]":t[r]=n}return t}var aun=/api[_-]?key|token|secret|password|credential|authorization/i,V$=process.env.NEUROLINK_PROXY_TRACE_BODY_LOGGING==="true",oue=Number.parseInt(process.env.NEUROLINK_PROXY_TRACE_BODY_LOG_BYTES??"8192",10),Efr=200;function Sfr(e,t=8192){const r=e.length>t?e.slice(0,t)+"\u2026[truncated]":e;try{let o=function(i){if(i===null||typeof i!="object")return i;if(Array.isArray(i))return i.map(o);const a={};for(const[c,l]of Object.entries(i))a[c]=aun.test(c)?"[REDACTED]":o(l);return a};var n=o;const s=JSON.parse(r);return JSON.stringify(o(s))}catch{return r}}function sue(e){return{"proxy.body":Sfr(e,oue),"proxy.body.size":e.length,"proxy.body.logged":!0,"proxy.body.truncated":e.length>oue}}function cun(e){return e?e.startsWith("claude-cli/")?"cli":e.startsWith("ai/")?"sdk":"unknown":"unknown"}var kx=class I0r{rootSpan;proxyTracer=gO("neurolink.proxy");bridge=new wV;requestId;model;billingProvider;startTime;isStream;ended=!1;recordRequestMetrics=!0;recordUsageMetrics=!0;accountEmail;usage;mode="full";constructor(t,r,n,o,s){this.rootSpan=t,this.requestId=r,this.model=n,this.billingProvider=s,this.startTime=Date.now(),this.isStream=o}static startRequest(t,r){const n=gO("neurolink.proxy");let o=fr.active();if(r&&!lt.getSpan(fr.active())){const m=new wV().extractContext(r);m&&(o=lt.setSpanContext(fr.active(),m))}const s=t.clientApp??cun(t.userAgent),i=n.startSpan("proxy.request",{attributes:{"proxy.request_id":t.requestId,"http.method":t.method,"http.target":t.path,"gen_ai.request.model":t.model,"proxy.stream":t.stream,"proxy.tool_count":t.toolCount,"proxy.client_app":s}},o);t.sessionId&&i.setAttribute("session.id",t.sessionId),t.userAgent&&i.setAttribute("http.user_agent",t.userAgent),t.toolNames&&t.toolNames.length>0&&i.setAttribute("gen_ai.request.tool_names",JSON.stringify(t.toolNames));const a=r?.["x-neurolink-session-id"],c=r?.["x-neurolink-user-id"],l=r?.["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);const u=new I0r(i,t.requestId,t.model,t.stream,t.provider??"anthropic");return u.recordRequestMetrics=t.recordRequestMetrics!==!1,u.recordUsageMetrics=t.recordUsageMetrics??u.recordRequestMetrics,W0({sessionId:a??t.sessionId,userId:c,conversationId:l,requestId:t.requestId,traceName:`proxy:${t.model}`,operationName:"proxy.request",metadata:{clientApp:s,stream:t.stream,toolCount:t.toolCount}}).catch(d=>{p.debug(`${oun} 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}},lt.setSpan(fr.active(),this.rootSpan))}startAccountSelection(){return this.proxyTracer.startSpan("proxy.account_selection",{attributes:{"proxy.request_id":this.requestId}},lt.setSpan(fr.active(),this.rootSpan))}startUpstreamAttempt(t){return this.proxyTracer.startSpan("proxy.upstream",{attributes:{"proxy.request_id":this.requestId,"proxy.upstream.attempt":t.attempt,"proxy.upstream.account":t.account,"proxy.upstream.polyfill_headers":t.polyfillHeaders,"proxy.upstream.polyfill_body":t.polyfillBody,"http.url":t.upstreamUrl}},lt.setSpan(fr.active(),this.rootSpan))}startStream(){return this.proxyTracer.startSpan("proxy.stream",{attributes:{"proxy.request_id":this.requestId,"gen_ai.request.model":this.model}},lt.setSpan(fr.active(),this.rootSpan))}setAccountSelection(t){this.accountEmail=t.selectedAccount,this.rootSpan.setAttributes({"proxy.account.strategy":t.strategy,"proxy.account.total":t.accountsTotal,"proxy.account.healthy":t.accountsHealthy,"proxy.account.selected":t.selectedAccount,"proxy.account.type":t.accountType}),t.rateLimitBefore5h!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.before.5h",t.rateLimitBefore5h),t.rateLimitBefore7d!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.before.7d",t.rateLimitBefore7d),W0({userId:t.selectedAccount}).catch(()=>{})}setServedAccount(t,r){this.accountEmail=t,this.rootSpan.setAttributes({"proxy.account.served":t,"proxy.account.served_type":r})}setUsage(t,r={}){r.recordMetrics!==void 0&&(this.recordUsageMetrics=r.recordMetrics),this.usage=t;const n=Jp(t),o=n.total;this.rootSpan.setAttributes({"ai.tokens.input":n.input,"ai.tokens.output":t.outputTokens,"ai.tokens.total":o,...t.cacheCreationTokensObserved===!1?{}:{"ai.tokens.cache_creation":t.cacheCreationTokens},...t.cacheReadTokensObserved===!1?{}:{"ai.tokens.cache_read":t.cacheReadTokens}}),t.reasoningTokens!==void 0&&this.rootSpan.setAttribute("ai.tokens.reasoning",t.reasoningTokens),this.rootSpan.setAttributes({"gen_ai.usage.input_tokens":o-t.outputTokens,"gen_ai.usage.output_tokens":t.outputTokens,"gen_ai.usage.total_tokens":o});const s=hd(this.billingProvider,this.model)?_M(this.billingProvider,this.model)?"exact":"inferred":"unavailable";if(this.rootSpan.setAttributes({"ai.cost.basis":"api-equivalent","ai.cost.pricing_status":s}),s==="exact"){const i=Ei(this.billingProvider,this.model,n);this.rootSpan.setAttributes({"ai.cost.total":i,"ai.cost.currency":"USD"})}t.rateLimitAfter5h!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.after.5h",t.rateLimitAfter5h),t.rateLimitAfter7d!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.after.7d",t.rateLimitAfter7d)}setResponseInfo(t){t.responseModel&&this.rootSpan.setAttribute("gen_ai.response.model",t.responseModel),t.finishReason&&this.rootSpan.setAttribute("gen_ai.response.finish_reason",t.finishReason),t.stopSequence&&this.rootSpan.setAttribute("gen_ai.response.stop_sequence",t.stopSequence),t.toolCalls&&t.toolCalls.length>0&&(this.rootSpan.setAttributes({"gen_ai.response.tool_calls":JSON.stringify(t.toolCalls),"gen_ai.response.tool_call_count":t.toolCalls.length}),this.rootSpan.addEvent("proxy.response.tool_calls",{"gen_ai.response.tool_calls":JSON.stringify(t.toolCalls)}))}setError(t,r){this.rootSpan.setAttributes({"error.type":t,"error.message":r,error:!0})}setMode(t){this.mode=t,this.rootSpan.setAttribute("proxy.mode",t)}setModelSubstitution(t,r,n){this.model=r,n&&(this.billingProvider=n),this.rootSpan.setAttributes({"proxy.model_substituted":!0,"proxy.original_model":t,"proxy.actual_model":r,"gen_ai.response.model":r,...n?{"proxy.actual_provider":n}:{}}),this.recordRequestMetrics&&Ax().modelSubstitutionTotal.add(1,{requested_model:t,actual_model:r})}setFallbackInfo(t){this.rootSpan&&this.rootSpan.setAttributes({"proxy.fallback.triggered":t.triggered,...t.provider?{"proxy.fallback.provider":t.provider}:{},...t.model?{"proxy.fallback.model":t.model}:{},"proxy.fallback.attempt_count":t.attemptCount,"proxy.fallback.reason":t.reason})}logRequestBody(t){if(!V$){this.rootSpan.addEvent("proxy.client.request_body",{"proxy.body.size":t.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.client.request_body",{...sue(t)})}logRequestHeaders(t){this.rootSpan.addEvent("proxy.client.request_headers",{"proxy.headers":JSON.stringify(nue(t))})}logUpstreamRequestBody(t){if(!V$){this.rootSpan.addEvent("proxy.upstream.request_body",{"proxy.body.size":t.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.upstream.request_body",{...sue(t)})}logUpstreamRequestHeaders(t){this.rootSpan.addEvent("proxy.upstream.request_headers",{"proxy.headers":JSON.stringify(nue(t))})}logUpstreamResponseHeaders(t){this.rootSpan.addEvent("proxy.upstream.response_headers",{"proxy.headers":JSON.stringify(nue(t))})}logUpstreamResponseBody(t){if(!V$){this.rootSpan.addEvent("proxy.upstream.response_body",{"proxy.body.size":t.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.upstream.response_body",{...sue(t)})}logStreamEvents(t){if(!V$){this.rootSpan.addEvent("proxy.stream.events",{"proxy.stream.event_count":t.length,"proxy.body.logged":!1});return}const r=t.length>Efr,n=t.slice(0,Efr).map(o=>({...o,data:o.data?Sfr(o.data,oue):""}));r&&n.push({type:"truncated",timestamp:Date.now(),data:"\u2026[truncated]"}),this.rootSpan.addEvent("proxy.stream.events",{"proxy.stream.event_count":t.length,"proxy.stream.events":JSON.stringify(n),"proxy.body.logged":!0,"proxy.body.truncated":r})}recordRetry(t,r){Ax().retriesTotal.add(1,{model:this.model,account:t,reason:r})}recordBodySizes(t,r){const n=Ax(),o={model:this.model,account:this.accountEmail??"unknown"};t!==void 0&&t>0&&n.requestBodySize.record(t,o),r!==void 0&&r>0&&n.responseBodySize.record(r,o)}getTraceContext(){const t=this.rootSpan.spanContext();return{traceId:t.traceId,spanId:t.spanId,traceFlags:t.traceFlags}}getUsage(){return this.usage}end(t,r){if(this.ended||(this.ended=!0,this.rootSpan.setAttributes({"http.status_code":t,"proxy.duration_ms":r,"proxy.mode":this.mode,...this.accountEmail?{"proxy.account":this.accountEmail}:void 0}),t>=400?this.rootSpan.setStatus({code:Ue.ERROR,message:`HTTP ${t}`}):this.rootSpan.setStatus({code:Ue.OK}),this.rootSpan.end(),!this.recordRequestMetrics&&!this.recordUsageMetrics))return;const n=Ax(),o={model:this.model,account:this.accountEmail??"unknown",status:String(t),stream:String(this.isStream),mode:this.mode};if(this.recordRequestMetrics&&(n.requestsTotal.add(1,o),n.requestDuration.record(r,o)),this.recordUsageMetrics&&this.usage){const s={model:this.model,account:this.accountEmail??"unknown"};n.tokensInput.add(Jp(this.usage).input,s),n.tokensOutput.add(this.usage.outputTokens,s),this.usage.cacheReadTokensObserved!==!1&&n.tokensCacheRead.add(this.usage.cacheReadTokens,s),this.usage.cacheCreationTokensObserved!==!1&&n.tokensCacheCreation.add(this.usage.cacheCreationTokens,s),this.usage.reasoningTokens&&n.tokensReasoning.add(this.usage.reasoningTokens,s);const i=Jp(this.usage),a=_M(this.billingProvider,this.model)&&hd(this.billingProvider,this.model)?Ei(this.billingProvider,this.model,i):void 0;a!==void 0&&n.costTotal.add(a,s)}if(this.recordRequestMetrics&&t>=400){const s=t===429?"rate_limit":t===401?"auth":t>=500?"server":"client";n.errorsTotal.add(1,{model:this.model,account:this.accountEmail??"unknown",error_type:s,status:String(t)})}}recordMetrics(){if(!this.recordUsageMetrics||!this.usage)return;const t=Jp(this.usage),r=t.total,n=Date.now()-this.startTime,o=_M(this.billingProvider,this.model)&&hd(this.billingProvider,this.model)?Ei(this.billingProvider,this.model,t):void 0;Zh.getInstance().recordAIRequest(this.billingProvider,this.model,r,n,o)}getTraceHeaders(){return this.bridge.injectContext({},lt.setSpan(fr.active(),this.rootSpan))}},lun=20,uun=256,ey=new Map,H$=new Set;function dun(e,t){for(ey.delete(e),ey.set(e,t);ey.size>uun;){const r=ey.keys().next();if(r.done)break;ey.delete(r.value),H$.delete(r.value)}}function mun(e,t,r){if(t==="success"){ey.delete(e),H$.delete(e)&&p.always(`[proxy] fallback ${e} is serving again after being reported dead`);return}const n=(ey.get(e)??0)+1;dun(e,n),!(n<lun)&&(H$.has(e)||(p.always(`[proxy] fallback ${e} has failed ${n} consecutive attempts with no success \u2014 this leg is not serving. Traffic is falling through to the next leg in the chain, which may bill differently. Check the account's quota and credentials`+(r?`; last error: ${r.slice(0,200)}`:"")),H$.add(e)))}function Bw(e){try{mun(`${e.provider}/${e.model}`,e.status,e.errorMessage)}catch{}try{const t=Ax(),r={provider:e.provider,model:e.model};t.fallbackAttemptsTotal.add(1,r),e.status==="success"?t.fallbackSuccessTotal.add(1,r):t.fallbackFailureTotal.add(1,{...r,error:e.errorMessage?.slice(0,100)??"unknown"})}catch{}}var iue=1024*1024,pun=16*1024*1024,aue=0,hun=`
|
|
2355
|
+
`);m.append(C),w.enqueue(C);return}if(f=void 0,_.done)h=!0,n.signal.removeEventListener("abort",y),m.finish(200),w.close();else{const C=d.encode(_.value);m.append(C),w.enqueue(C)}}catch(_){h||(m.finish(502),h=!0,w.error(_))}finally{E&&clearTimeout(E)}},cancel(w){m.finish(499),h=!0,n.signal.removeEventListener("abort",y),n.cancel(w),u.return().catch(()=>{})}},{highWaterMark:0});return new Response(v,{headers:{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"}})}async function j$(e){const t=yfr({...e,stream:!1});let r="",n;try{for await(const a of vfr({...e,request:t}))a.reset&&(r=""),a.text!==void 0&&(r+=a.text),a.result&&(n=a.result);t.signal.throwIfAborted(),t.finalize(200);const o=n?.usage?ffr(n.usage):void 0,s={content:r,model:n?.model,finishReason:n?.finishReason??tue(e.format),usage:o,toolCalls:n?.toolCalls},i=e.format==="claude"?Gpr(s,e.requestModel):e.format==="gemini"?xcn(r,s.finishReason??tue(e.format),o??{input:0,output:0,total:0},s.model??e.requestModel,s.toolCalls):Thr(s,e.requestModel);return t.capture.json(i,200),i}catch(o){if(e.deferFinalOnError&&!t.signal.aborted)throw t.abandon(),o;const s=Jg(o),i=s?.message??lr(o instanceof Error?o.message:String(o),500),a=Wc(o),c=t.signal.reason?.name==="TimeoutError"||o instanceof Error&&o.name==="TimeoutError",l=a?.status??(o instanceof _r?o.status:c?504:t.signal.aborted?499:s?.status??e.terminalFailureStatus??502),u=a?.code??(o instanceof _r?o.code:s?.code);t.finalize(l,c?"upstream_timeout":t.signal.aborted?"client_cancelled":"generation_error",i,u,s?.retryable);const d=a?.message??(o instanceof _r?o.message:"Upstream generation failed");return wfr(e.format,l,d,u,t.capture,s?.retryable)}}function tun(e){const t=[];if(e){const r=e.getModelMappings?.()??[];for(const o of r)t.push({id:o.from,object:"model",created:0,owned_by:"neurolink"});const n=e.getPassthroughModels?.()??[];for(const o of n)t.push({id:o,object:"model",created:0,owned_by:"neurolink"})}if(t.length===0)for(const r of hfr)t.push({id:r,object:"model",created:0,owned_by:"neurolink"});return{object:"list",data:t}}function run(e){const t=[];if(e){const s=e.getModelMappings?.()??[];for(const a of s)a.from&&t.push(a.from);const i=e.getPassthroughModels?.()??[];for(const a of i)t.push(a)}t.length===0&&t.push(...hfr);const r=new Set,o=t.filter(s=>r.has(s)?!1:(r.add(s),!0)).map(s=>({type:"model",id:s,display_name:nun(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 nun(e){const r=e.replace(/-\d{8}$/,"").split("-"),n=[],o=[];for(const i of r)/^\d+$/.test(i)&&o.length>0&&o[0].toLowerCase()==="claude"?n.push(i):o.push(i.charAt(0).toUpperCase()+i.slice(1));const s=n.length>0?` ${n.join(".")}`:"";return o.length>0?`${o[0]}${s}${o.slice(1).length?" "+o.slice(1).join(" "):""}`:e}pr(),Or(),Xt(),np(),xDr(),qa(),Ub(),z();var oun="[ProxyTracer]",rue=null;function Ax(){if(rue)return rue;const e=nh.getMeter("neurolink.proxy","1.0.0"),t={requestsTotal:e.createCounter("proxy_requests_total",{description:"Total number of proxy requests",unit:"{request}"}),requestDuration:e.createHistogram("proxy_request_duration_ms",{description:"Proxy request duration in milliseconds",unit:"ms"}),tokensInput:e.createCounter("proxy_tokens_input",{description:"Total input tokens consumed via proxy",unit:"{token}"}),tokensOutput:e.createCounter("proxy_tokens_output",{description:"Total output tokens produced via proxy",unit:"{token}"}),tokensCacheRead:e.createCounter("proxy_tokens_cache_read",{description:"Total cache-read tokens via proxy",unit:"{token}"}),tokensCacheCreation:e.createCounter("proxy_tokens_cache_creation",{description:"Total cache-creation tokens via proxy",unit:"{token}"}),tokensReasoning:e.createCounter("proxy_tokens_reasoning",{description:"Total reasoning tokens via proxy",unit:"{token}"}),costTotal:e.createCounter("proxy_cost_usd_total",{description:"Total estimated cost in USD",unit:"USD"}),errorsTotal:e.createCounter("proxy_errors_total",{description:"Total proxy errors",unit:"{error}"}),retriesTotal:e.createCounter("proxy_retries_total",{description:"Total upstream retry attempts",unit:"{retry}"}),modelSubstitutionTotal:e.createCounter("proxy_model_substitution_total",{description:"Total proxy requests where the response model differs from the requested model",unit:"{substitution}"}),requestBodySize:e.createHistogram("proxy_request_body_bytes",{description:"Request body size in bytes sent upstream",unit:"By"}),responseBodySize:e.createHistogram("proxy_response_body_bytes",{description:"Response body size in bytes received from upstream",unit:"By"}),fallbackAttemptsTotal:e.createCounter("proxy_fallback_attempts_total",{description:"Total fallback provider attempts",unit:"{attempt}"}),fallbackSuccessTotal:e.createCounter("proxy_fallback_success_total",{description:"Total successful fallback provider responses",unit:"{success}"}),fallbackFailureTotal:e.createCounter("proxy_fallback_failure_total",{description:"Total failed fallback provider responses",unit:"{failure}"}),schemaDegradedTotal:e.createCounter("proxy_codex_outbound_schema_degraded_total",{description:"Total Codex-outbound tool declarations whose JSON Schema needed flattening or lost a feature on the way to a Claude tool",unit:"{tool}"}),unsupportedFieldTotal:e.createCounter("proxy_codex_outbound_unsupported_field_total",{description:"Total Codex-outbound request fields this repo cannot faithfully represent in the Claude request, dropped rather than failing the translation",unit:"{field}"})};return rue=t,t}var sun=new Set(["authorization","proxy-authorization","x-api-key","cookie","set-cookie"]),iun=/token|secret|key|password|credential/i;function nue(e){const t={};for(const[r,n]of Object.entries(e)){const o=r.toLowerCase();sun.has(o)||iun.test(o)?t[r]="[REDACTED]":t[r]=n}return t}var aun=/api[_-]?key|token|secret|password|credential|authorization/i,V$=process.env.NEUROLINK_PROXY_TRACE_BODY_LOGGING==="true",oue=Number.parseInt(process.env.NEUROLINK_PROXY_TRACE_BODY_LOG_BYTES??"8192",10),Efr=200;function Sfr(e,t=8192){const r=e.length>t?e.slice(0,t)+"\u2026[truncated]":e;try{let o=function(i){if(i===null||typeof i!="object")return i;if(Array.isArray(i))return i.map(o);const a={};for(const[c,l]of Object.entries(i))a[c]=aun.test(c)?"[REDACTED]":o(l);return a};var n=o;const s=JSON.parse(r);return JSON.stringify(o(s))}catch{return r}}function sue(e){return{"proxy.body":Sfr(e,oue),"proxy.body.size":e.length,"proxy.body.logged":!0,"proxy.body.truncated":e.length>oue}}function cun(e){return e?e.startsWith("claude-cli/")?"cli":e.startsWith("ai/")?"sdk":"unknown":"unknown"}var kx=class I0r{rootSpan;proxyTracer=gO("neurolink.proxy");bridge=new wV;requestId;model;billingProvider;startTime;isStream;ended=!1;recordRequestMetrics=!0;recordUsageMetrics=!0;accountEmail;usage;mode="full";constructor(t,r,n,o,s){this.rootSpan=t,this.requestId=r,this.model=n,this.billingProvider=s,this.startTime=Date.now(),this.isStream=o}static startRequest(t,r){const n=gO("neurolink.proxy");let o=fr.active();if(r&&!lt.getSpan(fr.active())){const m=new wV().extractContext(r);m&&(o=lt.setSpanContext(fr.active(),m))}const s=t.clientApp??cun(t.userAgent),i=n.startSpan("proxy.request",{attributes:{"proxy.request_id":t.requestId,"http.method":t.method,"http.target":t.path,"gen_ai.request.model":t.model,"proxy.stream":t.stream,"proxy.tool_count":t.toolCount,"proxy.client_app":s}},o);t.sessionId&&i.setAttribute("session.id",t.sessionId),t.userAgent&&i.setAttribute("http.user_agent",t.userAgent),t.toolNames&&t.toolNames.length>0&&i.setAttribute("gen_ai.request.tool_names",JSON.stringify(t.toolNames));const a=r?.["x-neurolink-session-id"],c=r?.["x-neurolink-user-id"],l=r?.["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);const u=new I0r(i,t.requestId,t.model,t.stream,t.provider??"anthropic");return u.recordRequestMetrics=t.recordRequestMetrics!==!1,u.recordUsageMetrics=t.recordUsageMetrics??u.recordRequestMetrics,W0({sessionId:a??t.sessionId,userId:c,conversationId:l,requestId:t.requestId,traceName:`proxy:${t.model}`,operationName:"proxy.request",metadata:{clientApp:s,stream:t.stream,toolCount:t.toolCount}}).catch(d=>{p.debug(`${oun} 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}},lt.setSpan(fr.active(),this.rootSpan))}startAccountSelection(){return this.proxyTracer.startSpan("proxy.account_selection",{attributes:{"proxy.request_id":this.requestId}},lt.setSpan(fr.active(),this.rootSpan))}startUpstreamAttempt(t){return this.proxyTracer.startSpan("proxy.upstream",{attributes:{"proxy.request_id":this.requestId,"proxy.upstream.attempt":t.attempt,"proxy.upstream.account":t.account,"proxy.upstream.polyfill_headers":t.polyfillHeaders,"proxy.upstream.polyfill_body":t.polyfillBody,"http.url":t.upstreamUrl}},lt.setSpan(fr.active(),this.rootSpan))}startStream(){return this.proxyTracer.startSpan("proxy.stream",{attributes:{"proxy.request_id":this.requestId,"gen_ai.request.model":this.model}},lt.setSpan(fr.active(),this.rootSpan))}setAccountSelection(t){this.accountEmail=t.selectedAccount,this.rootSpan.setAttributes({"proxy.account.strategy":t.strategy,"proxy.account.total":t.accountsTotal,"proxy.account.healthy":t.accountsHealthy,"proxy.account.selected":t.selectedAccount,"proxy.account.type":t.accountType}),t.rateLimitBefore5h!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.before.5h",t.rateLimitBefore5h),t.rateLimitBefore7d!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.before.7d",t.rateLimitBefore7d),W0({userId:t.selectedAccount}).catch(()=>{})}setServedAccount(t,r){this.accountEmail=t,this.rootSpan.setAttributes({"proxy.account.served":t,"proxy.account.served_type":r})}setUsage(t,r={}){r.recordMetrics!==void 0&&(this.recordUsageMetrics=r.recordMetrics),this.usage=t;const n=Jp(t),o=n.total;this.rootSpan.setAttributes({"ai.tokens.input":n.input,"ai.tokens.output":t.outputTokens,"ai.tokens.total":o,...t.cacheCreationTokensObserved===!1?{}:{"ai.tokens.cache_creation":t.cacheCreationTokens},...t.cacheReadTokensObserved===!1?{}:{"ai.tokens.cache_read":t.cacheReadTokens}}),t.reasoningTokens!==void 0&&this.rootSpan.setAttribute("ai.tokens.reasoning",t.reasoningTokens),this.rootSpan.setAttributes({"gen_ai.usage.input_tokens":o-t.outputTokens,"gen_ai.usage.output_tokens":t.outputTokens,"gen_ai.usage.total_tokens":o});const s=hd(this.billingProvider,this.model)?_M(this.billingProvider,this.model)?"exact":"inferred":"unavailable";if(this.rootSpan.setAttributes({"ai.cost.basis":"api-equivalent","ai.cost.pricing_status":s}),s==="exact"){const i=Ei(this.billingProvider,this.model,n);this.rootSpan.setAttributes({"ai.cost.total":i,"ai.cost.currency":"USD"})}t.rateLimitAfter5h!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.after.5h",t.rateLimitAfter5h),t.rateLimitAfter7d!==void 0&&this.rootSpan.setAttribute("proxy.ratelimit.after.7d",t.rateLimitAfter7d)}setResponseInfo(t){t.responseModel&&this.rootSpan.setAttribute("gen_ai.response.model",t.responseModel),t.finishReason&&this.rootSpan.setAttribute("gen_ai.response.finish_reason",t.finishReason),t.stopSequence&&this.rootSpan.setAttribute("gen_ai.response.stop_sequence",t.stopSequence),t.toolCalls&&t.toolCalls.length>0&&(this.rootSpan.setAttributes({"gen_ai.response.tool_calls":JSON.stringify(t.toolCalls),"gen_ai.response.tool_call_count":t.toolCalls.length}),this.rootSpan.addEvent("proxy.response.tool_calls",{"gen_ai.response.tool_calls":JSON.stringify(t.toolCalls)}))}setError(t,r){this.rootSpan.setAttributes({"error.type":t,"error.message":r,error:!0})}setMode(t){this.mode=t,this.rootSpan.setAttribute("proxy.mode",t)}setModelSubstitution(t,r,n){this.model=r,n&&(this.billingProvider=n),this.rootSpan.setAttributes({"proxy.model_substituted":!0,"proxy.original_model":t,"proxy.actual_model":r,"gen_ai.response.model":r,...n?{"proxy.actual_provider":n}:{}}),this.recordRequestMetrics&&Ax().modelSubstitutionTotal.add(1,{requested_model:t,actual_model:r})}setFallbackInfo(t){this.rootSpan&&this.rootSpan.setAttributes({"proxy.fallback.triggered":t.triggered,...t.provider?{"proxy.fallback.provider":t.provider}:{},...t.model?{"proxy.fallback.model":t.model}:{},"proxy.fallback.attempt_count":t.attemptCount,"proxy.fallback.reason":t.reason})}logRequestBody(t){if(!V$){this.rootSpan.addEvent("proxy.client.request_body",{"proxy.body.size":t.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.client.request_body",{...sue(t)})}logRequestHeaders(t){this.rootSpan.addEvent("proxy.client.request_headers",{"proxy.headers":JSON.stringify(nue(t))})}logUpstreamRequestBody(t){if(!V$){this.rootSpan.addEvent("proxy.upstream.request_body",{"proxy.body.size":t.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.upstream.request_body",{...sue(t)})}logUpstreamRequestHeaders(t){this.rootSpan.addEvent("proxy.upstream.request_headers",{"proxy.headers":JSON.stringify(nue(t))})}logUpstreamResponseHeaders(t){this.rootSpan.addEvent("proxy.upstream.response_headers",{"proxy.headers":JSON.stringify(nue(t))})}logUpstreamResponseBody(t){if(!V$){this.rootSpan.addEvent("proxy.upstream.response_body",{"proxy.body.size":t.length,"proxy.body.logged":!1});return}this.rootSpan.addEvent("proxy.upstream.response_body",{...sue(t)})}logStreamEvents(t){if(!V$){this.rootSpan.addEvent("proxy.stream.events",{"proxy.stream.event_count":t.length,"proxy.body.logged":!1});return}const r=t.length>Efr,n=t.slice(0,Efr).map(o=>({...o,data:o.data?Sfr(o.data,oue):""}));r&&n.push({type:"truncated",timestamp:Date.now(),data:"\u2026[truncated]"}),this.rootSpan.addEvent("proxy.stream.events",{"proxy.stream.event_count":t.length,"proxy.stream.events":JSON.stringify(n),"proxy.body.logged":!0,"proxy.body.truncated":r})}recordRetry(t,r){Ax().retriesTotal.add(1,{model:this.model,account:t,reason:r})}recordBodySizes(t,r){const n=Ax(),o={model:this.model,account:this.accountEmail??"unknown"};t!==void 0&&t>0&&n.requestBodySize.record(t,o),r!==void 0&&r>0&&n.responseBodySize.record(r,o)}getTraceContext(){const t=this.rootSpan.spanContext();return{traceId:t.traceId,spanId:t.spanId,traceFlags:t.traceFlags}}getUsage(){return this.usage}end(t,r){if(this.ended||(this.ended=!0,this.rootSpan.setAttributes({"http.status_code":t,"proxy.duration_ms":r,"proxy.mode":this.mode,...this.accountEmail?{"proxy.account":this.accountEmail}:void 0}),t>=400?this.rootSpan.setStatus({code:Ue.ERROR,message:`HTTP ${t}`}):this.rootSpan.setStatus({code:Ue.OK}),this.rootSpan.end(),!this.recordRequestMetrics&&!this.recordUsageMetrics))return;const n=Ax(),o={model:this.model,account:this.accountEmail??"unknown",status:String(t),stream:String(this.isStream),mode:this.mode};if(this.recordRequestMetrics&&(n.requestsTotal.add(1,o),n.requestDuration.record(r,o)),this.recordUsageMetrics&&this.usage){const s={model:this.model,account:this.accountEmail??"unknown"};n.tokensInput.add(Jp(this.usage).input,s),n.tokensOutput.add(this.usage.outputTokens,s),this.usage.cacheReadTokensObserved!==!1&&n.tokensCacheRead.add(this.usage.cacheReadTokens,s),this.usage.cacheCreationTokensObserved!==!1&&n.tokensCacheCreation.add(this.usage.cacheCreationTokens,s),this.usage.reasoningTokens&&n.tokensReasoning.add(this.usage.reasoningTokens,s);const i=Jp(this.usage),a=_M(this.billingProvider,this.model)&&hd(this.billingProvider,this.model)?Ei(this.billingProvider,this.model,i):void 0;a!==void 0&&n.costTotal.add(a,s)}if(this.recordRequestMetrics&&t>=400){const s=t===429?"rate_limit":t===401?"auth":t>=500?"server":"client";n.errorsTotal.add(1,{model:this.model,account:this.accountEmail??"unknown",error_type:s,status:String(t)})}}recordMetrics(){if(!this.recordUsageMetrics||!this.usage)return;const t=Jp(this.usage),r=t.total,n=Date.now()-this.startTime,o=_M(this.billingProvider,this.model)&&hd(this.billingProvider,this.model)?Ei(this.billingProvider,this.model,t):void 0;Zh.getInstance().recordAIRequest(this.billingProvider,this.model,r,n,o)}getTraceHeaders(){return this.bridge.injectContext({},lt.setSpan(fr.active(),this.rootSpan))}},lun=20,uun=256,ey=new Map,H$=new Set;function dun(e,t){for(ey.delete(e),ey.set(e,t);ey.size>uun;){const r=ey.keys().next();if(r.done)break;ey.delete(r.value),H$.delete(r.value)}}function mun(e,t,r){if(t==="success"){ey.delete(e),H$.delete(e)&&p.always(`[proxy] fallback ${e} is serving again after being reported dead`);return}const n=(ey.get(e)??0)+1;dun(e,n),!(n<lun)&&(H$.has(e)||(p.always(`[proxy] fallback ${e} has failed ${n} consecutive attempts with no success \u2014 this leg is not serving. Traffic is falling through to the next leg in the chain, which may bill differently. Check the account's quota and credentials`+(r?`; last error: ${r.slice(0,200)}`:"")),H$.add(e)))}function Bw(e){try{mun(`${e.provider}/${e.model}`,e.status,e.errorMessage)}catch{}try{const t=Ax(),r={provider:e.provider,model:e.model};t.fallbackAttemptsTotal.add(1,r),e.status==="success"?t.fallbackSuccessTotal.add(1,r):t.fallbackFailureTotal.add(1,{...r,error:e.errorMessage?.slice(0,100)??"unknown"})}catch{}}var iue=1024*1024,pun=16*1024*1024,aue=0,hun=`
|
|
2356
2356
|
...[TRUNCATED]`;function cue(){const e=new TextDecoder,t=[];let r=0,n=0,o=!1,s=!1,i;const a=new Promise(g=>{i=g});function c(){if(s)return;s=!0;const g=t.map(y=>e.decode(y,{stream:!0})).join("")+(o?"":e.decode());aue-=n,t.length=0,i({totalBytes:r,text:g+(o?hun:""),truncated:o})}const l=new TransformStream({transform(g,y){if(y.enqueue(g),r+=g.byteLength,!o&&n<iue){const v=Math.min(iue-n,Math.max(0,pun-aue)),w=Uint8Array.from(g.subarray(0,v));t.push(w),n+=w.byteLength,aue+=w.byteLength,o=w.byteLength<g.byteLength}o||=r>iue},flush(){c()}}),u=l.writable.getWriter();let d;const m=new WritableStream({start(g){d=g},write(g){return u.write(g)},close(){return u.close()},abort(g){return c(),u.abort(g)}});u.closed.catch(g=>{c();try{d.error(g)}catch{}});const h=l.readable.getReader();return{stream:{readable:new ReadableStream({async pull(g){try{const{done:y,value:v}=await h.read();y?g.close():g.enqueue(v)}catch(y){g.error(y)}},async cancel(g){c();try{d.error(g)}catch{}await Promise.allSettled([h.cancel(g),u.abort(g)])}}),writable:m},capture:a}}mMt(),Dr(),Vs(),zt(),Gc(),z(),tc();var fun="proxy-peers.json",gun=1e3,yun={exhausted:9e5,withheld:6e5,paused:3e5,revoked:864e5,expired:864e5,unreachable:6e4,upstream_error:12e4},vun=null,pm={},xx=0,Ix=-1,Rx=!1,bfr=new ka;function lue(){return vun??yt(pa(),".neurolink",fun)}function Tun(e){if(!e||typeof e!="object")return!1;const t=e;return typeof t.name=="string"&&typeof t.url=="string"&&typeof t.token=="string"&&typeof t.priority=="number"&&typeof t.enabled=="boolean"}function wun(e){return e?.code==="ENOENT"}async function uue(e={}){const t=Date.now();if(!e.force&&Rx&&t-xx<gun)return;const r=lue();let n;try{n=(await xs(r)).mtimeMs}catch(o){if(!wun(o))throw o;pm={},Ix=-1,xx=t,Rx=!0;return}if(!e.force&&Rx&&n===Ix){xx=t;return}try{const o=JSON.parse(await Fr(r,"utf8"));pm=Object.fromEntries(Object.entries(o?.peers??{}).filter(s=>Tun(s[1])))}catch(o){if(e.force)throw o;p.always(`[proxy] peer list unreadable, treating as empty: ${o instanceof Error?o.message:String(o)}`),pm={}}Ix=n,xx=t,Rx=!0}async function _fr(){const e={schemaVersion:1,peers:pm};await xa(lue(),e);try{Ix=(await xs(lue())).mtimeMs}catch{Ix=-1}xx=Date.now(),Rx=!0}function Cfr(e){return e.trim().toLowerCase()}async function Eun(){return await uue(),Object.values(pm).sort((e,t)=>e.priority-t.priority||e.createdAt-t.createdAt)}async function Sun(e=Date.now()){return(await Eun()).filter(r=>r.enabled&&!(r.cooldownUntil&&r.cooldownUntil>e))}function bun(e){return yun[e]}var _un=6048e5;async function due(e,t,r){await bfr.runExclusive(async()=>{await uue({force:!0});const n=Cfr(e),o=pm[n];if(!o)return;const s=(r??0)*1e3,i=Date.now()+Math.min(_un,Math.max(bun(t),Number.isFinite(s)?s:0));pm[n]={...o,cooldownUntil:i,cooldownReason:t,updatedAt:Date.now()},await _fr()})}async function Cun(e,t){await bfr.runExclusive(async()=>{await uue({force:!0});const r=Cfr(e),n=pm[r];n&&(pm[r]={...n,cooldownUntil:0,lastUsedAt:Date.now(),updatedAt:Date.now(),...t?{lastObservation:t}:{}},await _fr())})}Dr(),Vs(),zt(),Gc(),BF();var Aun=6048e5,kun=9e5,xun=864e5;function Iun(e){return!e.usable}function Afr(e){return{schemaVersion:e.schemaVersion,grantId:e.grantId,peerLabel:e.peerLabel,issuedAt:e.issuedAt,notAfter:e.notAfter,heartbeatEveryMs:e.heartbeatEveryMs,offlineGraceMs:e.offlineGraceMs,gates:e.gates,entitlementSnapshot:e.entitlementSnapshot}}function kfr(e,t){return Uae(e,t)}function xfr(e,t=Date.now()){const r=e.leasePolicy,n=e.leaseSecret;if(!n)throw new Error(`Grant ${e.id} has no lease secret \u2014 provision it before issuing a lease.`);const o=r?.ttlMs??Aun,s=Math.min(t+o,e.gates.notAfter??Number.POSITIVE_INFINITY),i={schemaVersion:1,grantId:e.id,peerLabel:e.peerLabel,issuedAt:t,notAfter:s,heartbeatEveryMs:r?.heartbeatEveryMs??kun,offlineGraceMs:r?.offlineGraceMs??xun,gates:e.gates,entitlementSnapshot:e.entitlement.ledger==="coins"?e.entitlement.coins??0:"unlimited"};return{...i,signature:kfr(Afr(i),n)}}function Run(e,t){const{signature:r,...n}=e;return oar(kfr(Afr(n),t),r)}function Pun(e){const t=e.now??Date.now();if(!Run(e.lease,e.secret))return{usable:!1,reason:"unsigned",detail:"lease signature does not match the lender's secret"};if(e.lease.notAfter<=t)return{usable:!1,reason:"expired",detail:"the lease's hard expiry has passed"};const r=e.lastHeartbeatAt??e.lease.issuedAt;return r+e.lease.offlineGraceMs<=t?{usable:!1,reason:"grace_elapsed",detail:"the lender has been unreachable for longer than this lease allows"}:{usable:!0,nextHeartbeatDueAt:r+e.lease.heartbeatEveryMs}}function Mun(e){const t=e.now??Date.now();if(!e.grant.leaseSecret)throw new Error(`Grant ${e.grant.id} has no lease secret \u2014 attach lease material first.`);return{code:e.code,state:e.state,accountLabel:`${e.grant.peerLabel}-via-${e.lenderName}`,leaseSecret:e.grant.leaseSecret,lease:xfr(e.grant,t),lenderUrl:(e.lenderUrl??"").replace(/\/+$/,"")}}tc();var Oun="proxy-resident-grants.json",Dun=1e3,Nun=null,ty={},Px=0,Mx=-1,Ox=!1,Lun=new ka;function mue(){return Nun??yt(pa(),".neurolink",Oun)}function Fun(e){if(!e||typeof e!="object")return!1;const t=e;return typeof t.accountLabel=="string"&&typeof t.grantId=="string"&&typeof t.leaseSecret=="string"&&!!t.lease}function $un(e){return e?.code==="ENOENT"}async function Ifr(e={}){const t=Date.now();if(!e.force&&Ox&&t-Px<Dun)return;const r=mue();let n;try{n=(await xs(r)).mtimeMs}catch(o){if(!$un(o))throw o;ty={},Mx=-1,Px=t,Ox=!0;return}if(!e.force&&Ox&&n===Mx){Px=t;return}try{const o=JSON.parse(await Fr(r,"utf8"));ty=Object.fromEntries(Object.entries(o?.grants??{}).filter(s=>Fun(s[1])))}catch(o){if(e.force)throw o;ty={}}Mx=n,Px=t,Ox=!0}async function Uun(){const e={schemaVersion:1,grants:ty};await xa(mue(),e);try{Mx=(await xs(mue())).mtimeMs}catch{Mx=-1}Px=Date.now(),Ox=!0}function Rfr(e){return e.toLowerCase()}async function pue(e){await Ifr();const t=e.toLowerCase(),r=t.includes(":")?t.slice(t.indexOf(":")+1):t;return ty[Rfr(r)]}async function zun(e,t=Date.now()){const r=await pue(e);if(r)return Pun({lease:r.lease,secret:r.leaseSecret,...r.lastHeartbeatAt!==void 0?{lastHeartbeatAt:r.lastHeartbeatAt}:{},now:t})}async function qun(e,t){await Lun.runExclusive(async()=>{await Ifr({force:!0});const r=Rfr(e),n=ty[r];n&&(ty[r]={...n,unreportedCoins:(n.unreportedCoins??0)+t,unreportedRequests:(n.unreportedRequests??0)+1},await Uun())})}z();var Gun=15e3,jun=12e4;function Vun(e){switch(e){case"exhausted":return"exhausted";case"paused":return"paused";case"revoked":return"revoked";case"expired":return"expired";case"reserve_floor":case"spillover_inactive":case"slice_exhausted":case"no_capacity":return"withheld";case"missing_token":case"unknown_token":case"malformed_token":return"revoked";default:return"upstream_error"}}function Pfr(e,t){const r=e.headers.get(t);if(r===null||r.trim()==="")return;const n=Number(r);return Number.isFinite(n)?n:void 0}function Hun(e){const t=Pfr(e,"x-neurolink-grant-remaining-coins");return{observedAt:Date.now(),...e.headers.get("x-neurolink-grant-status")?{grantStatus:e.headers.get("x-neurolink-grant-status")??""}:{},...e.headers.get("x-neurolink-grant-reason")?{grantReason:e.headers.get("x-neurolink-grant-reason")??""}:{},...t!==void 0?{remainingCoins:t}:{}}}function Wun(e,t,r){const n=e.body;if(!n)return e;let o;const s=()=>{o!==void 0&&(clearTimeout(o),o=void 0)},i=()=>{s(),o=setTimeout(()=>{p.always(`[proxy] peer=${t.name} went quiet mid-response; abandoning it`),due(t.name,"unreachable").catch(c=>{p.debug(`[proxy] could not cool peer=${t.name} after a stall: ${c instanceof Error?c.message:String(c)}`)}),r.abort()},jun),o.unref?.()},a=n.pipeThrough(new TransformStream({start:i,transform(c,l){i(),l.enqueue(c)},flush:s}));return r.signal.addEventListener("abort",s,{once:!0}),new Response(a,{status:e.status,statusText:e.statusText,headers:e.headers})}async function Kun(e){const{peer:t,body:r,stream:n}=e,o=new AbortController,s=setTimeout(()=>o.abort(),Gun);e.signal&&(e.signal.aborted?o.abort():e.signal.addEventListener("abort",()=>o.abort(),{once:!0}));try{const i=await fetch(`${t.url}/v1/messages`,{method:"POST",headers:{"content-type":"application/json","x-neurolink-share-token":t.token,accept:n?"text/event-stream":"application/json"},body:r,signal:o.signal});if(i.ok)return await Cun(t.name,Hun(i)).catch(u=>{p.debug(`[proxy] could not record success for peer=${t.name}: ${u instanceof Error?u.message:String(u)}`)}),{ok:!0,response:Wun(i,t,o),peer:t};const a=i.headers.get("x-neurolink-grant-reason"),c=Vun(a),l=Pfr(i,"retry-after");return await due(t.name,c,l),await i.text().catch(()=>""),p.always(`[proxy] peer=${t.name} declined (${c}); cooling before retry`),{ok:!1,peer:t,status:i.status,reason:c,message:`peer ${t.name} declined: ${c}`,...l!==void 0?{retryAfterSeconds:l}:{}}}catch(i){const a=i instanceof Error?i.message:String(i);return e.signal?.aborted?(p.debug(`[proxy] peer=${t.name} attempt cancelled by the caller: ${a}`),{ok:!1,peer:t,reason:"unreachable",message:`peer ${t.name} attempt cancelled`}):(await due(t.name,"unreachable").catch(c=>{p.debug(`[proxy] could not cool peer=${t.name}: ${c instanceof Error?c.message:String(c)}`)}),p.always(`[proxy] peer=${t.name} unreachable: ${a}`),{ok:!1,peer:t,reason:"unreachable",message:`peer ${t.name} unreachable`})}finally{clearTimeout(s)}}Xk();var Jun=36e5,Yun={missing_token:"No share token was presented.",unknown_token:"Share token is not recognized.",malformed_token:"Share token is malformed.",paused:"The lender has paused this share.",revoked:"This share has been revoked.",expired:"This share has expired.",out_of_window:"This share is outside its allowed hours.",model_not_allowed:"This share does not cover the requested model.",exhausted:"This share has no credit remaining.",rate_limited:"This share's request rate limit was exceeded.",concurrency_limited:"This share's concurrent request limit was reached.",reserve_floor:"The lender's reserved headroom is in force.",spillover_inactive:"This share serves only the lender's spare capacity, and none is spare yet.",slice_exhausted:"This share has used its allotted portion of the window.",no_capacity:"No lender account can currently serve this share."};function Xun(e){return Yun[e]}function Zun(e){switch(e){case"missing_token":case"unknown_token":case"malformed_token":return 401;case"paused":case"revoked":case"expired":case"out_of_window":case"model_not_allowed":return 403;default:return 429}}function Qun(e,t){const r=new Date(t).getHours(),{fromHour:n,toHour:o}=e;return n===o?!0:n<o?r>=n&&r<o:r>=n||r<o}function edn(e,t){if(!e||e.length===0)return!0;if(!t)return!1;const r=t.toLowerCase();return e.some(n=>r.includes(n.toLowerCase()))}function Mfr(e,t){const r=n=>n===void 0?t:t===void 0?n:Math.min(n,t);return{session:r(e?.session5hPct),weekly:r(e?.weekly7dPct)}}function Ofr(e,t,r){const n=e.spillover;if(!n)return!1;const o=n.beforeResetHours*Jun,s=n.whenUtilizationBelowPct/100,i=t.weeklyResetAt!==null&&t.weeklyResetAt-r<=o&&t.weeklyResetAt>r&&t.weeklyUsed!==null&&t.weeklyUsed<s,a=t.sessionResetAt!==null&&t.sessionResetAt-r<=o&&t.sessionResetAt>r&&t.sessionUsed!==null&&t.sessionUsed<s;return i||a}function hue(e,t){if(!e.accounts||e.accounts.length===0)return{inScope:[...t],outOfScope:[]};const r=new Set(e.accounts.map(s=>s.trim().toLowerCase())),n=[],o=[];for(const s of t){const i=s.accountKey.toLowerCase(),a=i.includes(":")?i.slice(i.indexOf(":")+1):i;r.has(i)||r.has(a)?n.push(s):o.push(s)}return{inScope:n,outOfScope:o}}function fue(e,t,r,n){const o=e.gates,{inScope:s,outOfScope:i}=hue(o,t),a=s.some(m=>Ofr(o,m,r)),c=Mfr(o.maxSlice,a?o.spillover?.maxSlicePct:void 0);if(c.session!==void 0&&n.sessionFraction*100>=c.session||c.weekly!==void 0&&n.weeklyFraction*100>=c.weekly)return{allowed:[],excluded:[...s.map(m=>({accountKey:m.accountKey,reason:"slice_exhausted"})),...i.map(m=>({accountKey:m.accountKey,reason:"no_capacity"}))]};const u=[],d=i.map(m=>({accountKey:m.accountKey,reason:"no_capacity"}));for(const m of s){const h=Ofr(o,m,r);if(o.spillover&&!h){d.push({accountKey:m.accountKey,reason:"spillover_inactive"});continue}const f=o.reserveFloor;if(f){const w=f.session5hPct!==void 0&&m.sessionUsed!==null&&m.sessionUsed*100>100-f.session5hPct,E=f.weekly7dPct!==void 0&&m.weeklyUsed!==null&&m.weeklyUsed*100>100-f.weekly7dPct;if(w||E){d.push({accountKey:m.accountKey,reason:"reserve_floor"});continue}}const g=Mfr(o.maxSlicePerAccount,h?o.spillover?.maxSlicePct:void 0),y=g.session!==void 0&&m.borrowedSessionFraction*100>=g.session,v=g.weekly!==void 0&&m.borrowedWeeklyFraction*100>=g.weekly;if(y||v){d.push({accountKey:m.accountKey,reason:"slice_exhausted"});continue}u.push(m.accountKey)}return{allowed:u,excluded:d}}function gue(e){return e.some(t=>t.reason==="reserve_floor")?"reserve_floor":e.some(t=>t.reason==="spillover_inactive")?"spillover_inactive":e.some(t=>t.reason==="slice_exhausted")?"slice_exhausted":"no_capacity"}var tdn="x-neurolink-share-token",rdn="x-neurolink-grant-status",ndn="x-neurolink-grant-reason",odn="x-neurolink-grant-remaining-coins",sdn="x-neurolink-grant-peer";function idn(e){const t=e[tdn];if(t?.trim())return t.trim();const r=e.authorization??e.Authorization;if(!r)return;const n=r.trim(),o=n.toLowerCase().startsWith("bearer ")?n.slice(7).trim():n;return etn(o)?o:void 0}function adn(e){return e===401?"authentication_error":e===403?"permission_error":"rate_limit_error"}function cdn(e,t){switch(e){case"paused":return"paused";case"revoked":return"revoked";case"expired":return"expired";case"exhausted":return"exhausted";case"out_of_window":return"out-of-window";case"missing_token":case"unknown_token":case"malformed_token":return"unauthorized";default:return t?.state??"active"}}function zw(e,t){const{status:r,grant:n,retryAfterSeconds:o}=t,s={[rdn]:cdn(e,n),[ndn]:e};return n&&(s[sdn]=n.peerLabel,n.entitlement.ledger==="coins"&&(s[odn]=String(Math.max(0,Math.floor(n.entitlement.coins??0))))),o!==void 0&&(s["retry-after"]=String(Math.max(1,Math.round(o)))),{status:r,headers:s,body:{type:"error",error:{type:adn(r),message:t.message??Xun(e)}}}}Xk(),Dr(),Vs(),zt(),Gc(),tc();var ldn="proxy-share-audit.json",udn=2,ddn=3,mdn=1e3,pdn=null,qw={},Dx=0,Nx=-1,Lx=!1,hdn=new ka;function yue(){return pdn??yt(pa(),".neurolink",ldn)}function fdn(e){return e?.code==="ENOENT"}async function gdn(e={}){const t=Date.now();if(!e.force&&Lx&&t-Dx<mdn)return;const r=yue();let n;try{n=(await xs(r)).mtimeMs}catch(o){if(!fdn(o))throw o;qw={},Nx=-1,Dx=t,Lx=!0;return}if(!e.force&&Lx&&n===Nx){Dx=t;return}try{qw=JSON.parse(await Fr(r,"utf8"))?.records??{}}catch(o){if(e.force)throw o;qw={}}Nx=n,Dx=t,Lx=!0}async function ydn(){const e={schemaVersion:1,records:qw};await xa(yue(),e);try{Nx=(await xs(yue())).mtimeMs}catch{Nx=-1}Dx=Date.now(),Lx=!0}function Dfr(e,t){return e===null||t===null?0:Math.max(0,(t-e)*100)}function vdn(e,t,r=udn){if(!e)return{drifted:!1,reason:"no_baseline"};if(t.lenderRequests>0)return{drifted:!1,reason:"attributable"};const n=Dfr(e.sessionUsed,t.sessionUsed),o=Dfr(e.weeklyUsed,t.weeklyUsed),s=Math.max(n,o);return s<=r?{drifted:!1,reason:"quiet"}:t.reportedCoins>0?{drifted:!1,reason:"attributable"}:{drifted:!0,unexplainedSessionPct:n,unexplainedWeeklyPct:o,detail:`the account moved ${s.toFixed(1)}% of a window since the last check-in while this node served none of it and the borrower reported no spend`}}async function Tdn(e){const t=e.streakLimit??ddn;return hdn.runExclusive(async()=>{await gdn({force:!0});const r=qw[e.grantId],n=e.lenderRequestsTotal===void 0?e.observation:{...e.observation,lenderRequests:Math.max(0,e.lenderRequestsTotal-(r?.lenderRequestsTotal??0))},o=vdn(r?.lastObservation,n,e.tolerancePct),s=o.drifted?(r?.driftStreak??0)+1:0,i={grantId:e.grantId,accountLabel:e.accountLabel,lastObservation:n,...e.lenderRequestsTotal!==void 0?{lenderRequestsTotal:e.lenderRequestsTotal}:r?.lenderRequestsTotal!==void 0?{lenderRequestsTotal:r.lenderRequestsTotal}:{},driftStreak:s,...o.drifted?{lastDriftAt:n.at,lastDriftDetail:o.detail}:{...r?.lastDriftAt!==void 0?{lastDriftAt:r.lastDriftAt}:{},...r?.lastDriftDetail!==void 0?{lastDriftDetail:r.lastDriftDetail}:{}},...r?.autoPausedAt!==void 0?{autoPausedAt:r.autoPausedAt}:{}},a=s>=t&&i.autoPausedAt===void 0;return a&&(i.autoPausedAt=n.at),qw[e.grantId]=i,await ydn(),{verdict:o,shouldPause:a}})}Wr(),Dr(),Vs(),zt(),Gc(),tc();var wdn="proxy-share-provisioning.json",Edn=9e5,Sdn=/^[A-Za-z0-9_-]{43}$/,bdn=/^[A-Za-z0-9_-]{16,128}$/,_dn=null,Gw={},Nfr=!1,Lfr=new ka;function Ffr(){return _dn??yt(pa(),".neurolink",wdn)}function Cdn(e){if(!e||typeof e!="object")return!1;const t=e;return typeof t.grantId=="string"&&typeof t.codeChallenge=="string"&&typeof t.state=="string"&&typeof t.expiresAt=="number"&&typeof t.status=="string"}async function $fr(e={}){if(!(Nfr&&!e.force)){try{const t=JSON.parse(await Fr(Ffr(),"utf8"));Gw=Object.fromEntries(Object.entries(t?.requests??{}).filter(r=>Cdn(r[1])))}catch{Gw={}}Nfr=!0}}async function Ufr(){const e={schemaVersion:1,requests:Gw};await xa(Ffr(),e)}function Adn(e,t=Date.now()){return e.status!=="consumed"&&e.expiresAt>t}async function kdn(e){if(!Sdn.test(e.codeChallenge))return{ok:!1,reason:"code_challenge must be a base64url S256 digest"};if(!bdn.test(e.state))return{ok:!1,reason:"state must be 16-128 base64url characters"};const t=e.now??Date.now();return Lfr.runExclusive(async()=>{await $fr({force:!0});const r={schemaVersion:1,grantId:e.grantId,codeChallenge:e.codeChallenge,challengeMethod:"S256",state:e.state,requestedAt:t,expiresAt:t+Edn,status:"pending"};return Gw[e.grantId]=r,await Ufr(),{ok:!0,request:r}})}async function xdn(e,t=Date.now()){return Lfr.runExclusive(async()=>{await $fr({force:!0});const r=Gw[e];if(!r||!Adn(r,t))return{status:"none"};if(r.status!=="authorized"||!r.code)return{status:"pending"};const{code:n,...o}=r;return Gw[e]={...o,status:"consumed",claimedAt:t},await Ufr(),{status:"ready",code:r.code,state:r.state}})}Tar(),Wr(),Dr(),Vs(),zt(),Gc(),Xk(),BF();var Idn="proxy-share-notes.json",Bfr="nln",Rdn=null,jw={},zfr=!1,Pdn=new ka;function qfr(){return Rdn??yt(pa(),".neurolink",Idn)}async function Gfr(e={}){if(!(zfr&&!e.force)){try{jw=JSON.parse(await Fr(qfr(),"utf8"))?.notes??{}}catch{jw={}}zfr=!0}}async function Mdn(){const{writeJsonSnapshotAtomically:e}=await Promise.resolve().then(()=>(tc(),kae)),t={schemaVersion:1,notes:jw};await e(qfr(),t)}function Odn(e){const t=e.trim();if(t.startsWith(`${Bfr}_`))try{const r=JSON.parse(Buffer.from(t.slice(Bfr.length+1),"base64url").toString("utf8"));return typeof r?.noteId!="string"||typeof r.coins!="number"||typeof r.signature!="string"||typeof r.notAfter!="number"?void 0:r}catch{return}}async function Ddn(e,t,r=Date.now()){const{signature:n,...o}=e;if(!t||!UF(o,n,t))return{status:"forged",coins:0};await Gfr({force:!0});const s=jw[e.noteId];return s?s.redeemedAt!==void 0?{status:"spent",coins:s.coins}:s.notAfter<=r?{status:"expired",coins:s.coins}:{status:"valid",coins:s.coins}:{status:"unknown",coins:0}}async function Ndn(e){const t=e.now??Date.now(),{signature:r,...n}=e.note;if(!e.secret||!UF(n,r,e.secret))return{ok:!1,status:"forged"};const o=await Pdn.runExclusive(async()=>{await Gfr({force:!0});const i=jw[e.note.noteId];return i?i.redeemedAt!==void 0?{status:"spent",coins:i.coins}:i.notAfter<=t?{status:"expired",coins:i.coins}:(jw[i.noteId]={...i,redeemedAt:t,redeemedByGrant:e.grantId},await Mdn(),{status:"valid",coins:i.coins}):{status:"unknown",coins:0}});if(o.status!=="valid")return{ok:!1,status:o.status};const s=await car(e.grantId,o.coins);return{ok:!0,coins:o.coins,balance:s}}BF(),Par();var Ldn=64*1024,Fdn=32;function jfr(e){try{const t=JSON.parse(e);return{errorType:t.error?.type??t.type??"stream_error",message:t.error?.message??t.message??"Upstream SSE error"}}catch{return{errorType:"stream_error",message:e.trim()||"Upstream SSE error"}}}function Vfr(e){if(e.event==="error")return!0;try{const t=JSON.parse(e.data);return t.type==="error"||t.error!==void 0}catch{return!1}}async function $dn(e){const t=new TextDecoder,r=[];let n="",o=0;for(;o<Ldn&&r.length<Fdn;){let s;try{s=await e.read()}catch(a){return{kind:"transport_error",chunks:r,error:a}}if(s.done){n+=t.decode();const{events:a}=b$(n),c=a.find(Vfr);return c?{kind:"sse_error",chunks:r,...jfr(c.data)}:r.length>0?{kind:"ready",chunks:r}:{kind:"empty",chunks:r}}if(!s.value||s.value.length===0)continue;r.push(s.value),o+=s.value.byteLength,n+=t.decode(s.value,{stream:!0});const i=b$(n);n=i.remainder;for(const a of i.events){if(Vfr(a))return{kind:"sse_error",chunks:r,...jfr(a.data)};if(a.event!=="ping"&&(a.event||a.data))return{kind:"ready",chunks:r}}}return r.length>0?{kind:"ready",chunks:r}:{kind:"empty",chunks:r}}function Hfr(){let e=!1,t;const r=new Promise(o=>{t=o}),n=o=>{e||(e=!0,t(o))};return{outcome:r,complete:()=>n({kind:"completed"}),fail:o=>n({kind:"upstream_error",message:o}),cancel:()=>n({kind:"client_cancelled"})}}function W$(e,t,r){return e.kind==="completed"&&t?{kind:"upstream_error",message:t}:e.kind==="completed"&&r===!1?{kind:"upstream_error",message:"Anthropic stream ended without a message_stop event"}:e}function Udn(e){const t=e.toLowerCase();return t.includes("opus")?"opus":t.includes("sonnet")?"sonnet":t.includes("haiku")?"haiku":"other"}function Vw(e,t,r,n,o=!1){const s=[{provider:e.provider,model:e.model,label:`${e.provider}/${e.model??"unknown"}`}];for(const i of t)i.provider===e.provider&&i.model===e.model||s.push({provider:i.provider,model:i.model,...i.reasoningEffort!==void 0?{reasoningEffort:i.reasoningEffort}:{},label:`${i.provider}/${i.model}`});return o&&(t.length===0||s.length===1)&&s.push({label:"auto-provider"}),{requestedModel:r,modelTier:Udn(r),attempts:s,skipped:[]}}function K$(e){if(!e)return 0;const t=parseInt(e,10);if(!Number.isNaN(t))return Math.max(1,t)*1e3;const r=new Date(e);return Number.isNaN(r.getTime())?0:Math.max(1e3,r.getTime()-Date.now())}var Bdn=1,zdn=20;function vue(e){return typeof e=="number"&&Number.isInteger(e)&&e>=Bdn&&e<=zdn?e:void 0}tc(),Kk(),Ut(),z(),Lr(),Pg(),Bg(),gl(),Kk(),Ut(),z();var Tue=900*1e3,wue=6e4,Wfr=900*1e3,Kfr=6e4,Xi="codex-oauth",Eue="neurolink.codexFallback";function Fx(e){if(!e||typeof e!="object")return;const t=e.code;if(typeof t=="string")return t;const r=e.cause;if(!r||typeof r!="object")return;const n=r.code;return typeof n=="string"?n:void 0}function qdn(e){const t=Fx(e);return t==="ENOTFOUND"||t==="EAI_AGAIN"?"shared_provider_transport":"connection_transport"}function Hw(e,t){return lr(e).slice(0,200)||t}var Sue=new Map;async function Gdn(e,t,r,n){const o=Sue.get(e);if(o)return o;const s=(async()=>{const i=await r.peekTokens(e).catch(()=>null),a=i?.refreshToken??t,c=await n(a),l={accessToken:c.accessToken,refreshToken:c.refreshToken??a,expiresAt:c.expiresAt??i?.expiresAt??Date.now()+36e5};return i&&await r.saveTokens(e,{...l,tokenType:"Bearer",...i.scope?{scope:i.scope}:{}}),l})().finally(()=>{Sue.delete(e)});return Sue.set(e,s),s}async function bue(e,t){return Gdn(e,t,li,qin)}var jdn=new Set(["host","connection","content-length","transfer-encoding","cookie","proxy-authorization","authorization","x-api-key","chatgpt-account-id","accept-encoding"]);function Zp(e,t,r){return new Response(JSON.stringify({error:{type:"proxy_error",message:t,...r?{code:r,retryable:!1}:{}}}),{status:e,headers:{"content-type":"application/json"}})}function Vdn(e,t){const r={type:"response.failed",response:{error:{type:"insufficient_quota",code:"insufficient_quota",message:e}}},n={"content-type":"text/event-stream"};return t!==void 0&&(n["retry-after"]=String(t)),new Response(`event: response.failed
|
|
2357
2357
|
data: ${JSON.stringify(r)}
|
|
2358
2358
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a Codex tool call's raw argument text into the record a Claude
|
|
3
|
+
* `tool_use.input` needs, kind-aware: a `function` tool's `arguments` is
|
|
4
|
+
* JSON-Schema-shaped JSON text; a `custom` tool has no JSON at all — only the
|
|
5
|
+
* raw grammar-constrained string that `mapCodexCustomToolToClaude`'s
|
|
6
|
+
* single-field `input_schema` (`codexOutboundFallback.ts` §3.4) expects
|
|
7
|
+
* wrapped as `{ input: raw }`. Centralized so both call sites (a
|
|
8
|
+
* `function_call` item's `arguments` and a `custom_tool_call` item's `input`)
|
|
9
|
+
* go through the same rule rather than two hand-rolled wrappings.
|
|
10
|
+
*/
|
|
11
|
+
import type { CodexNativeToolKind } from "../types/index.js";
|
|
12
|
+
export declare function parseToolArguments(raw: string, kind: CodexNativeToolKind): Record<string, unknown>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function isPlainRecord(value) {
|
|
2
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function parseToolArguments(raw, kind) {
|
|
5
|
+
if (kind === "custom") {
|
|
6
|
+
return { input: raw };
|
|
7
|
+
}
|
|
8
|
+
// Empty arguments is the documented zero-argument-call shape, not
|
|
9
|
+
// malformed input — it must not be wrapped as `{ input: "" }`.
|
|
10
|
+
if (raw === "") {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const parsed = JSON.parse(raw);
|
|
15
|
+
if (isPlainRecord(parsed)) {
|
|
16
|
+
return parsed;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// fall through — not JSON at all (e.g. a stray shell-command string)
|
|
21
|
+
}
|
|
22
|
+
return { input: raw };
|
|
23
|
+
}
|
|
@@ -8,14 +8,17 @@
|
|
|
8
8
|
* own target/model selection, response/stream translation back to Codex wire
|
|
9
9
|
* format, tool execution, or dispatch/HTTP.
|
|
10
10
|
*
|
|
11
|
-
* `parallel_tool_calls`
|
|
12
|
-
* `mapCodexToolChoiceToClaude
|
|
13
|
-
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
11
|
+
* `parallel_tool_calls` feeds `tool_choice.disable_parallel_tool_use` in
|
|
12
|
+
* `mapCodexToolChoiceToClaude`, and tool declarations are flattened through
|
|
13
|
+
* `inlineJsonSchema` (dropping `strict` and degrading a circular `$ref` to a
|
|
14
|
+
* bare `{type:"object"}`) — the tool-call-fidelity PR's changes to this file.
|
|
15
|
+
* A `toolKindByName` map is also returned alongside the translated request,
|
|
16
|
+
* so response serialization (which sees only Claude's `name`+`input` on a
|
|
17
|
+
* `tool_use` block, no kind discriminator) knows which declared tools were
|
|
18
|
+
* `custom` rather than `function`.
|
|
16
19
|
*/
|
|
17
20
|
import type { ClaudeRequest } from "../types/index.js";
|
|
18
|
-
import type { CodexNativeRequest, CodexTranslationError } from "../types/index.js";
|
|
21
|
+
import type { CodexNativeRequest, CodexNativeToolKind, CodexTranslationError } from "../types/index.js";
|
|
19
22
|
export declare function parseCodexNativeRequest(raw: unknown): {
|
|
20
23
|
ok: true;
|
|
21
24
|
value: CodexNativeRequest;
|
|
@@ -29,6 +32,7 @@ export declare function translateCodexRequestToClaude(request: CodexNativeReques
|
|
|
29
32
|
}): {
|
|
30
33
|
ok: true;
|
|
31
34
|
value: ClaudeRequest;
|
|
35
|
+
toolKindByName: ReadonlyMap<string, CodexNativeToolKind>;
|
|
32
36
|
} | {
|
|
33
37
|
ok: false;
|
|
34
38
|
error: CodexTranslationError;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { resolveClaudeMaxTokens } from "../utils/tokenLimits.js";
|
|
2
|
+
import { inlineJsonSchema } from "../utils/schemaConversion.js";
|
|
3
|
+
import { parseToolArguments } from "./argumentParsing.js";
|
|
4
|
+
import { recordCodexOutboundSchemaDegraded, recordCodexOutboundUnsupportedField, } from "./proxyTracer.js";
|
|
5
|
+
import { CODEX_STREAM_MAX_TOOL_CALLS, CODEX_STREAM_SIZE_CEILING_BYTES, } from "./streamLimits.js";
|
|
2
6
|
// ---------------------------------------------------------------------------
|
|
3
7
|
// §3.1 parseCodexNativeRequest — the untrusted-JSON -> typed boundary.
|
|
4
8
|
// ---------------------------------------------------------------------------
|
|
@@ -122,29 +126,82 @@ export function parseCodexNativeRequest(raw) {
|
|
|
122
126
|
// ---------------------------------------------------------------------------
|
|
123
127
|
// §3.3 tool_choice — exact inversion of codexFallback.ts's convertClaudeRequestToCodex.
|
|
124
128
|
// ---------------------------------------------------------------------------
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
// Absent tool_choice and "auto" both mean the same thing to Codex, and both
|
|
130
|
+
// now map to an *explicit* `{type:"auto"}` (previously: `undefined` for the
|
|
131
|
+
// absent case) so `disable_parallel_tool_use` always has a field on the
|
|
132
|
+
// output to attach to, regardless of whether the source request bothered to
|
|
133
|
+
// say "auto" out loud. `parallel_tool_calls: false` is inert on `"none"` —
|
|
134
|
+
// there is nothing running in parallel to disable.
|
|
135
|
+
function mapCodexToolChoiceToClaude(choice, parallelToolCalls) {
|
|
136
|
+
const disable = parallelToolCalls === false;
|
|
137
|
+
if (choice === undefined || choice === "auto") {
|
|
138
|
+
return disable
|
|
139
|
+
? { type: "auto", disable_parallel_tool_use: true }
|
|
140
|
+
: { type: "auto" };
|
|
128
141
|
}
|
|
129
142
|
if (choice === "required") {
|
|
130
|
-
return
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return { type: "auto" };
|
|
143
|
+
return disable
|
|
144
|
+
? { type: "any", disable_parallel_tool_use: true }
|
|
145
|
+
: { type: "any" };
|
|
134
146
|
}
|
|
135
147
|
if (choice === "none") {
|
|
136
148
|
return { type: "none" };
|
|
137
149
|
}
|
|
138
|
-
return
|
|
150
|
+
return disable
|
|
151
|
+
? { type: "tool", name: choice.name, disable_parallel_tool_use: true }
|
|
152
|
+
: { type: "tool", name: choice.name };
|
|
139
153
|
}
|
|
140
154
|
// ---------------------------------------------------------------------------
|
|
141
155
|
// §3.4 Tools: flattened across namespaces, split by each declaration's own type.
|
|
142
156
|
// ---------------------------------------------------------------------------
|
|
157
|
+
/**
|
|
158
|
+
* Detection-only walk of a schema's `$ref` chain, independent of
|
|
159
|
+
* `inlineJsonSchema`'s own flattening — the actual flattening stays fully
|
|
160
|
+
* delegated to that function unmodified (never reimplemented here), so this
|
|
161
|
+
* only answers "would a ref chain revisit itself" for the schemaDegraded
|
|
162
|
+
* counter's benefit.
|
|
163
|
+
*/
|
|
164
|
+
function hasCircularRef(schema, defs, seen = new Set()) {
|
|
165
|
+
if (typeof schema.$ref === "string" && schema.$ref.startsWith("#/")) {
|
|
166
|
+
if (seen.has(schema.$ref)) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
const key = schema.$ref.split("/").pop();
|
|
170
|
+
const target = defs && key ? defs[key] : undefined;
|
|
171
|
+
return target
|
|
172
|
+
? hasCircularRef(target, defs, new Set(seen).add(schema.$ref))
|
|
173
|
+
: false;
|
|
174
|
+
}
|
|
175
|
+
const properties = isRecord(schema.properties)
|
|
176
|
+
? Object.values(schema.properties)
|
|
177
|
+
: [];
|
|
178
|
+
const items = Array.isArray(schema.items)
|
|
179
|
+
? schema.items
|
|
180
|
+
: isRecord(schema.items)
|
|
181
|
+
? [schema.items]
|
|
182
|
+
: [];
|
|
183
|
+
return [...properties, ...items].some((value) => isRecord(value) && hasCircularRef(value, defs, seen));
|
|
184
|
+
}
|
|
143
185
|
function mapCodexFunctionToolToClaude(tool) {
|
|
186
|
+
const reasons = [];
|
|
187
|
+
const defs = (tool.parameters.definitions ?? tool.parameters.$defs);
|
|
188
|
+
if (defs && hasCircularRef(tool.parameters, defs)) {
|
|
189
|
+
reasons.push("circular_ref_flattened");
|
|
190
|
+
}
|
|
191
|
+
const input_schema = inlineJsonSchema(tool.parameters);
|
|
192
|
+
if (tool.strict) {
|
|
193
|
+
// Anthropic tool declarations have no `strict`-mode equivalent, so the
|
|
194
|
+
// flag is dropped rather than silently passed through as an unknown key.
|
|
195
|
+
reasons.push("strict_mode_flag_dropped");
|
|
196
|
+
}
|
|
144
197
|
return {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
198
|
+
tool: {
|
|
199
|
+
name: tool.name,
|
|
200
|
+
...(tool.description ? { description: tool.description } : {}),
|
|
201
|
+
input_schema,
|
|
202
|
+
},
|
|
203
|
+
kind: "function",
|
|
204
|
+
reasons,
|
|
148
205
|
};
|
|
149
206
|
}
|
|
150
207
|
function mapCodexCustomToolToClaude(tool) {
|
|
@@ -152,23 +209,27 @@ function mapCodexCustomToolToClaude(tool) {
|
|
|
152
209
|
// The model is no longer grammar-constrained after this mapping — needs
|
|
153
210
|
// product sign-off before shipping (§10 of the design).
|
|
154
211
|
return {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
212
|
+
tool: {
|
|
213
|
+
name: tool.name,
|
|
214
|
+
description: [
|
|
215
|
+
tool.description,
|
|
216
|
+
`Grammar (${tool.format.syntax}):\n${tool.format.definition}`,
|
|
217
|
+
]
|
|
218
|
+
.filter((s) => Boolean(s))
|
|
219
|
+
.join("\n\n"),
|
|
220
|
+
input_schema: {
|
|
221
|
+
type: "object",
|
|
222
|
+
properties: {
|
|
223
|
+
input: {
|
|
224
|
+
type: "string",
|
|
225
|
+
description: "Raw command text, constrained by the grammar in this tool's description.",
|
|
226
|
+
},
|
|
168
227
|
},
|
|
228
|
+
required: ["input"],
|
|
169
229
|
},
|
|
170
|
-
required: ["input"],
|
|
171
230
|
},
|
|
231
|
+
kind: "custom",
|
|
232
|
+
reasons: ["custom_tool_wrapped"],
|
|
172
233
|
};
|
|
173
234
|
}
|
|
174
235
|
function mapCodexToolDeclarationToClaude(tool) {
|
|
@@ -182,10 +243,14 @@ function mapCodexToolDeclarationToClaude(tool) {
|
|
|
182
243
|
}
|
|
183
244
|
function buildClaudeTools(additionalTools) {
|
|
184
245
|
if (!additionalTools) {
|
|
185
|
-
return undefined;
|
|
246
|
+
return { tools: undefined, toolKindByName: new Map(), reasons: [] };
|
|
186
247
|
}
|
|
187
|
-
const
|
|
188
|
-
return
|
|
248
|
+
const mapped = additionalTools.tools.flatMap((namespace) => namespace.tools.map(mapCodexToolDeclarationToClaude));
|
|
249
|
+
return {
|
|
250
|
+
tools: mapped.length > 0 ? mapped.map((m) => m.tool) : undefined,
|
|
251
|
+
toolKindByName: new Map(mapped.map((m) => [m.tool.name, m.kind])),
|
|
252
|
+
reasons: mapped.flatMap((m) => m.reasons.map((reason) => ({ toolName: m.tool.name, reason }))),
|
|
253
|
+
};
|
|
189
254
|
}
|
|
190
255
|
// ---------------------------------------------------------------------------
|
|
191
256
|
// §3.5 Reasoning: reasoning.effort -> thinking.
|
|
@@ -210,19 +275,23 @@ function mapCodexReasoningToThinking(reasoning, resolvedMaxTokens) {
|
|
|
210
275
|
return { type: "enabled", budget_tokens };
|
|
211
276
|
}
|
|
212
277
|
// ---------------------------------------------------------------------------
|
|
213
|
-
// §3.6 Non-JSON function_call.arguments — never throws.
|
|
278
|
+
// §3.6 Non-JSON function_call.arguments — never throws. Parsing itself is
|
|
279
|
+
// `parseToolArguments` (argumentParsing.ts); this is a cheap, separate,
|
|
280
|
+
// redundant check purely so a malformed (non-empty, non-record) arguments
|
|
281
|
+
// string can be reported via the unsupportedFieldTotal counter without
|
|
282
|
+
// polluting that pure function's return shape with a degrade flag.
|
|
214
283
|
// ---------------------------------------------------------------------------
|
|
215
|
-
function
|
|
284
|
+
function isMalformedFunctionArguments(raw) {
|
|
285
|
+
if (raw === "") {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
216
288
|
try {
|
|
217
289
|
const parsed = JSON.parse(raw);
|
|
218
|
-
|
|
219
|
-
return parsed;
|
|
220
|
-
}
|
|
290
|
+
return !isRecord(parsed);
|
|
221
291
|
}
|
|
222
292
|
catch {
|
|
223
|
-
|
|
293
|
+
return true;
|
|
224
294
|
}
|
|
225
|
-
return { input: raw };
|
|
226
295
|
}
|
|
227
296
|
// ---------------------------------------------------------------------------
|
|
228
297
|
// §3.7 Content parts, with the image data-URI fix.
|
|
@@ -299,8 +368,8 @@ function coalesceCodexInputToClaudeMessages(items) {
|
|
|
299
368
|
// A custom tool is declared with a single `input` string (§3.4), so
|
|
300
369
|
// its raw call text maps onto that field unchanged.
|
|
301
370
|
input: item.type === "function_call"
|
|
302
|
-
?
|
|
303
|
-
:
|
|
371
|
+
? parseToolArguments(item.arguments, "function")
|
|
372
|
+
: parseToolArguments(item.input, "custom"),
|
|
304
373
|
});
|
|
305
374
|
continue;
|
|
306
375
|
}
|
|
@@ -342,6 +411,32 @@ function hasFreshSessionPreamble(items) {
|
|
|
342
411
|
return items[0]?.type === "additional_tools";
|
|
343
412
|
}
|
|
344
413
|
// ---------------------------------------------------------------------------
|
|
414
|
+
// Tool-call history ceilings — the same streamLimits.ts numbers the response
|
|
415
|
+
// leg enforces, so a history is never accepted that the reply could not carry.
|
|
416
|
+
// ---------------------------------------------------------------------------
|
|
417
|
+
function toolHistoryText(item) {
|
|
418
|
+
switch (item.type) {
|
|
419
|
+
case "function_call":
|
|
420
|
+
return item.arguments;
|
|
421
|
+
case "custom_tool_call":
|
|
422
|
+
return item.input;
|
|
423
|
+
case "function_call_output":
|
|
424
|
+
case "custom_tool_call_output":
|
|
425
|
+
return item.output;
|
|
426
|
+
default:
|
|
427
|
+
return undefined;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function describeOversizedToolHistory(items) {
|
|
431
|
+
const calls = items.filter((item) => item.type === "function_call" || item.type === "custom_tool_call").length;
|
|
432
|
+
if (calls > CODEX_STREAM_MAX_TOOL_CALLS) {
|
|
433
|
+
return `the history carries ${calls} tool calls, over the limit of ${CODEX_STREAM_MAX_TOOL_CALLS}`;
|
|
434
|
+
}
|
|
435
|
+
return items.some((item) => (toolHistoryText(item)?.length ?? 0) > CODEX_STREAM_SIZE_CEILING_BYTES)
|
|
436
|
+
? `a tool call's arguments or output exceed the limit of ${CODEX_STREAM_SIZE_CEILING_BYTES} characters`
|
|
437
|
+
: undefined;
|
|
438
|
+
}
|
|
439
|
+
// ---------------------------------------------------------------------------
|
|
345
440
|
// Inputs Codex accepts but the Messages API rejects — fail loud, never guess.
|
|
346
441
|
// ---------------------------------------------------------------------------
|
|
347
442
|
function describeUntranslatableItem(item, provider) {
|
|
@@ -423,6 +518,13 @@ function lastAssistantMessageUsesTool(messages) {
|
|
|
423
518
|
// §3.2 translateCodexRequestToClaude — the full field-by-field mapping.
|
|
424
519
|
// ---------------------------------------------------------------------------
|
|
425
520
|
export function translateCodexRequestToClaude(request, target) {
|
|
521
|
+
const oversized = describeOversizedToolHistory(request.input);
|
|
522
|
+
if (oversized) {
|
|
523
|
+
return {
|
|
524
|
+
ok: false,
|
|
525
|
+
error: { code: "REQUEST_TOO_LARGE", message: oversized },
|
|
526
|
+
};
|
|
527
|
+
}
|
|
426
528
|
// Read from client_metadata, not top-level session_id/thread_id: the real
|
|
427
529
|
// capture carries neither at top level (only nested in client_metadata),
|
|
428
530
|
// which is why CodexNativeRequest has no top-level fields for them.
|
|
@@ -451,9 +553,9 @@ export function translateCodexRequestToClaude(request, target) {
|
|
|
451
553
|
const additionalTools = request.input
|
|
452
554
|
.filter((item) => item.type === "additional_tools")
|
|
453
555
|
.at(-1);
|
|
454
|
-
const tools = buildClaudeTools(additionalTools);
|
|
455
|
-
const toolChoice = mapCodexToolChoiceToClaude(request.tool_choice);
|
|
456
|
-
const forcesTool = toolChoice
|
|
556
|
+
const { tools, toolKindByName, reasons: schemaReasons, } = buildClaudeTools(additionalTools);
|
|
557
|
+
const toolChoice = mapCodexToolChoiceToClaude(request.tool_choice, request.parallel_tool_calls);
|
|
558
|
+
const forcesTool = toolChoice.type === "any" || toolChoice.type === "tool";
|
|
457
559
|
if (forcesTool && !tools) {
|
|
458
560
|
return {
|
|
459
561
|
ok: false,
|
|
@@ -463,7 +565,7 @@ export function translateCodexRequestToClaude(request, target) {
|
|
|
463
565
|
},
|
|
464
566
|
};
|
|
465
567
|
}
|
|
466
|
-
if (toolChoice
|
|
568
|
+
if (toolChoice.type === "tool" &&
|
|
467
569
|
!tools?.some((tool) => tool.name === toolChoice.name)) {
|
|
468
570
|
return {
|
|
469
571
|
ok: false,
|
|
@@ -507,9 +609,27 @@ export function translateCodexRequestToClaude(request, target) {
|
|
|
507
609
|
...(systemBlocks.length > 0 ? { system: systemBlocks } : {}),
|
|
508
610
|
...(tools ? { tools } : {}),
|
|
509
611
|
// The Messages API accepts tool_choice only alongside tools.
|
|
510
|
-
...(
|
|
612
|
+
...(tools ? { tool_choice: toolChoice } : {}),
|
|
511
613
|
...(thinking ? { thinking } : {}),
|
|
512
614
|
stream: request.stream ?? true,
|
|
513
615
|
};
|
|
514
|
-
|
|
616
|
+
// Recorded only once translation has fully succeeded, so a request that is
|
|
617
|
+
// rejected earlier (malformed tool_choice, untranslatable content, a
|
|
618
|
+
// pairing gap) never fires a degrade counter for work that was discarded.
|
|
619
|
+
for (const reason of schemaReasons) {
|
|
620
|
+
recordCodexOutboundSchemaDegraded({
|
|
621
|
+
toolName: reason.toolName,
|
|
622
|
+
reason: reason.reason,
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
for (const item of request.input) {
|
|
626
|
+
if (item.type === "function_call" &&
|
|
627
|
+
isMalformedFunctionArguments(item.arguments)) {
|
|
628
|
+
recordCodexOutboundUnsupportedField({
|
|
629
|
+
field: "function_call.arguments",
|
|
630
|
+
reason: "malformed_arguments_wrapped",
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return { ok: true, value: claudeRequest, toolKindByName };
|
|
515
635
|
}
|