@juspay/neurolink 12.36.1 → 12.37.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 CHANGED
@@ -1,8 +1,8 @@
1
- ## [12.36.1](https://github.com/juspay/neurolink/compare/v12.36.0...v12.36.1) (2026-09-28)
1
+ ## [12.37.1](https://github.com/juspay/neurolink/compare/v12.37.0...v12.37.1) (2026-09-29)
2
2
 
3
3
  ### Bug Fixes
4
4
 
5
- - **(tools):** harden file-tool symlink containment and gate its suite in CI ([58871f5](https://github.com/juspay/neurolink/commit/58871f5a01be556cc0be1fedca95fef6b04fafd9))
5
+ - **(deps):** move fast-uri to 3.1.7 for two high advisories ([dfa011e](https://github.com/juspay/neurolink/commit/dfa011ea14697563beb6b4dc7e48dbb78f5c2150))
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` is parsed and validated but not yet consumed here —
12
- * `mapCodexToolChoiceToClaude` stays the base bijection this PR ships.
13
- * Threading it into `tool_choice.disable_parallel_tool_use` (and the matching
14
- * `ClaudeRequest.tool_choice` type change) is the tool-call-fidelity build-order
15
- * PR's explicit modification to this same function, not a gap in this one.
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
- function mapCodexToolChoiceToClaude(choice) {
126
- if (choice === undefined) {
127
- return undefined;
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 { type: "any" };
131
- }
132
- if (choice === "auto") {
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 { type: "tool", name: choice.name };
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
- name: tool.name,
146
- ...(tool.description ? { description: tool.description } : {}),
147
- input_schema: tool.parameters,
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
- name: tool.name,
156
- description: [
157
- tool.description,
158
- `Grammar (${tool.format.syntax}):\n${tool.format.definition}`,
159
- ]
160
- .filter((s) => Boolean(s))
161
- .join("\n\n"),
162
- input_schema: {
163
- type: "object",
164
- properties: {
165
- input: {
166
- type: "string",
167
- description: "Raw command text, constrained by the grammar in this tool's description.",
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 tools = additionalTools.tools.flatMap((namespace) => namespace.tools.map(mapCodexToolDeclarationToClaude));
188
- return tools.length > 0 ? tools : undefined;
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 parseInboundToolArguments(raw) {
284
+ function isMalformedFunctionArguments(raw) {
285
+ if (raw === "") {
286
+ return false;
287
+ }
216
288
  try {
217
289
  const parsed = JSON.parse(raw);
218
- if (isRecord(parsed)) {
219
- return parsed;
220
- }
290
+ return !isRecord(parsed);
221
291
  }
222
292
  catch {
223
- // fall through — not JSON at all (e.g. exec's raw shell command)
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
- ? parseInboundToolArguments(item.arguments)
303
- : { input: item.input },
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?.type === "any" || toolChoice?.type === "tool";
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?.type === "tool" &&
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
- ...(toolChoice && tools ? { tool_choice: toolChoice } : {}),
612
+ ...(tools ? { tool_choice: toolChoice } : {}),
511
613
  ...(thinking ? { thinking } : {}),
512
614
  stream: request.stream ?? true,
513
615
  };
514
- return { ok: true, value: claudeRequest };
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
  }