@urun-sh/openai 0.2.50 → 0.2.52

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.
@@ -1,26 +1,33 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var pe=Object.create;var x=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var me=Object.getPrototypeOf,fe=Object.prototype.hasOwnProperty;var ge=(e,n)=>{for(var t in n)x(e,t,{get:n[t],enumerable:!0})},B=(e,n,t,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of de(n))!fe.call(e,o)&&o!==t&&x(e,o,{get:()=>n[o],enumerable:!(r=le(n,o))||r.enumerable});return e};var ye=(e,n,t)=>(t=e!=null?pe(me(e)):{},B(n||!e||!e.__esModule?x(t,"default",{value:e,enumerable:!0}):t,e)),_e=e=>B(x({},"__esModule",{value:!0}),e);var je={};ge(je,{buildClients:()=>ae,resolveSessionFromEnv:()=>ie});module.exports=_e(je);var se=require("child_process"),g=ye(require("process"),1),R=require("@urun-sh/core");function q(e,n,t,r){let o=e.response??{},s={request_id:t,consumer_id:r,stream:!0,kind:"chat",messages:n};return typeof o.instructions=="string"&&(s.instructions=o.instructions),Array.isArray(o.modalities)&&(s.modalities=o.modalities),typeof o.temperature=="number"&&(s.temperature=o.temperature),typeof o.max_output_tokens=="number"&&(s.max_output_tokens=o.max_output_tokens),o.tools!==void 0&&(s.tools=o.tools),s}function K(e,n,t){let r={request_id:n,consumer_id:t,stream:!!e.stream,kind:"responses",input:e.input};return e.model&&(r.model=e.model),e.tools!==void 0&&(r.tools=e.tools),typeof e.temperature=="number"&&(r.temperature=e.temperature),typeof e.max_output_tokens=="number"&&(r.max_output_tokens=e.max_output_tokens),r}function D(e){if(e instanceof Error)return{type:"error",error:{type:"urun_error",code:e.name||null,message:e.message}};if(e&&typeof e=="object"&&e.t==="error"){let n=e,t=n.body??{};return{type:"error",error:{type:"urun_error",code:n.code??null,message:t.message??"unknown error"}}}return{type:"error",error:{type:"urun_error",code:null,message:String(e)}}}var he="llm-resp";async function*P(e,n){let t=`${he}:${n}`,r=`resp_${n}`;yield{type:"response.created",response:{id:r,status:"in_progress"}};for await(let o of e.stream(t).messages()){let s=o;if(s.t==="delta")yield{type:"response.output_text.delta",item_id:r,delta:s.delta};else if(s.t==="response"){yield{type:"response.completed",response:{id:r,status:"completed",...s.body}};return}else if(s.t==="error"){yield D(s);return}}}var we="llm",S=class{constructor(n){this.session=n}session;get consumerId(){return this.session.consumerId}write(n){this.session.doc(we).set({requests:{[n.request_id]:{payload:n,consumer_id:n.consumer_id,stream:n.stream}}})}sendResponses(n,t){let r=K(n,t,this.consumerId);return this.write(r),P(this.session,t)}sendResponseCreate(n,t,r){let o=q(n,t,r,this.consumerId);return this.write(o),P(this.session,r)}};var G=0;function ke(){return G+=1,`req_${Date.now().toString(36)}_${G.toString(36)}`}var A=class{transport;constructor(n){this.transport=new S(n)}responses={create:async n=>{let t=ke(),r=this.transport.sendResponses(n,t);return Object.assign((async function*(){yield*r})(),{requestId:t})}}};async function F(e){let t=await(e.fetchImpl??fetch)(`${e.catalogUrl}/model_catalog?select=model_id,variant`,{headers:{apikey:e.anonKey,Authorization:`Bearer ${e.anonKey}`}});if(!t.ok)throw new Error(`model_catalog fetch failed: ${t.status}`);return{object:"list",data:(await t.json()).map(o=>({id:`${o.model_id}:${o.variant}`,object:"model",created:0,owned_by:"urun"}))}}var X=require("http"),$=class e{startedAt=Date.now();requests={};ttftMs=[];tokRates=[];tokensOut=0;charsOut=0;localInBytes=0;naiveInBytes=0;request(n,t,r){this.requests[n]=(this.requests[n]??0)+1,this.localInBytes+=t,this.naiveInBytes+=r}track(n){let t=this,r=performance.now(),o=null,s=0;return(async function*(){for await(let a of n)a.type==="response.output_text.delta"&&typeof a.delta=="string"&&(o===null&&(o=performance.now(),t.ttftMs.push(o-r),t.ttftMs.length>512&&t.ttftMs.shift()),s+=1,t.tokensOut+=1,t.charsOut+=a.delta.length),yield a;let i=(performance.now()-(o??r))/1e3;s>0&&i>0&&(t.tokRates.push(s/i),t.tokRates.length>512&&t.tokRates.shift())})()}static p50(n){if(!n.length)return null;let t=[...n].sort((r,o)=>r-o);return t[Math.floor(t.length/2)]}snapshot(){let n=Object.values(this.requests).reduce((t,r)=>t+r,0);return{uptime_s:Math.round((Date.now()-this.startedAt)/1e3),requests:this.requests,tokens_out:this.tokensOut,chars_out:this.charsOut,ttft_ms:{p50:e.p50(this.ttftMs),last:this.ttftMs.at(-1)??null},tok_per_s:{p50:e.p50(this.tokRates),last:this.tokRates.at(-1)??null},traffic:{local_request_bytes:this.localInBytes,naive_baseline:{request_bytes:this.naiveInBytes,connections:n},persistent_connections:1,history_bytes_saved:Math.max(0,this.naiveInBytes-this.localInBytes),history_bytes_saved_pct:this.naiveInBytes>0?Math.round((1-this.localInBytes/this.naiveInBytes)*1e3)/10:null}}}};function M(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function w(e,n,t){e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(t))}function f(e,n,t,r="invalid_request_error"){w(e,n,{error:{message:t,type:r}})}var Y=64*1024*1024,b=class extends Error{};async function ve(e){let n=[],t=0;for await(let o of e){if(t+=o.length,t>Y)throw new b(`request body exceeds ${Y} bytes`);n.push(o)}let r=Buffer.concat(n).toString("utf8");return r?JSON.parse(r):{}}function E(e,n,t,r){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:n,choices:[{index:0,delta:t,finish_reason:r}]}}var Re=256;function xe(e){if(typeof e=="string")return[{role:"user",content:e}];if(Array.isArray(e))return e;throw new Error("responses input must be a string or an array of messages/items")}var T=class{conversations=new Map;thread(n,t){let r=xe(t);if(n==null)return r;let o=this.conversations.get(String(n));if(!o)throw new Error(`unknown previous_response_id ${String(n)} (proxy restarts drop stored responses)`);return[...o,...r]}remember(n,t,r){this.conversations.set(n,[...t,{role:"assistant",content:r}]);for(let o of this.conversations.keys()){if(this.conversations.size<=Re)break;this.conversations.delete(o)}}};function V(e){let n=e?.output;return Array.isArray(n)?n.filter(t=>t.type==="function_call"):[]}function v(e){return e.find(n=>n.type==="response.completed")?.response??null}function Se(e){if(Array.isArray(e))return e.map(n=>{let t=n.function;return!t||typeof t!="object"?n:{type:"function",name:t.name,description:t.description,parameters:t.parameters,strict:t.strict}})}var U=class extends Error{};function Ae(e,n){return Array.isArray(n)?n.map(t=>{let r=t;if(r.type==="text")return{type:e==="assistant"?"output_text":"input_text",text:r.text};if(r.type==="image_url"){let o=r.image_url??{};return{type:"input_image",image_url:o.url,detail:o.detail}}throw new U(`unsupported chat content part type "${String(r.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function Ee(e){let n=[];for(let t of e){if(t.role==="tool"){n.push({type:"function_call_output",call_id:t.tool_call_id,output:typeof t.content=="string"?t.content:JSON.stringify(t.content??"")});continue}if(t.role==="assistant"&&Array.isArray(t.tool_calls)){typeof t.content=="string"&&t.content&&n.push({role:"assistant",content:t.content});for(let r of t.tool_calls){let o=r.function??{};n.push({type:"function_call",call_id:r.id,name:o.name,arguments:o.arguments})}continue}n.push({...t,content:Ae(t.role,t.content)})}return n}function W(e){return V(e).map((n,t)=>({index:t,id:n.call_id??n.id??`call_${t}`,type:"function",function:{name:n.name??"",arguments:n.arguments??"{}"}}))}function z(e,n){let t=n?.output_text;return typeof t=="string"?t:e.filter(r=>r.type==="response.output_text.delta"&&typeof r.delta=="string").map(r=>r.delta).join("")}async function be(e,n,t,r,o){let s=e.stream===!0,i;try{i=t.thread(e.previous_response_id,e.input)}catch(u){f(r,400,String(u instanceof Error?u.message:u));return}e.previous_response_id!=null&&(o.naiveInBytes+=Buffer.byteLength(JSON.stringify(i))-Buffer.byteLength(JSON.stringify(e.input)));let a=`resp_${Math.random().toString(36).slice(2,14)}`,l=e.store!==!1,p=await n.createResponse({model:e.model,input:i,stream:s,tools:e.tools,temperature:e.temperature,max_output_tokens:e.max_output_tokens}),m=[];if(s){M(r);for await(let u of o.track(p)){m.push(u);let c=u.response&&typeof u.response=="object"?{...u,response:{...u.response,id:a}}:u;r.write(`event: ${String(u.type??"message")}
3
- data: ${JSON.stringify(c)}
2
+ "use strict";var Xe=Object.create;var M=Object.defineProperty;var Ve=Object.getOwnPropertyDescriptor;var Qe=Object.getOwnPropertyNames;var Ze=Object.getPrototypeOf,et=Object.prototype.hasOwnProperty;var tt=(e,n)=>{for(var t in n)M(e,t,{get:n[t],enumerable:!0})},ce=(e,n,t,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of Qe(n))!et.call(e,o)&&o!==t&&M(e,o,{get:()=>n[o],enumerable:!(r=Ve(n,o))||r.enumerable});return e};var D=(e,n,t)=>(t=e!=null?Xe(Ze(e)):{},ce(n||!e||!e.__esModule?M(t,"default",{value:e,enumerable:!0}):t,e)),nt=e=>ce(M({},"__esModule",{value:!0}),e);var Ot={};tt(Ot,{buildClients:()=>Fe,buildRouter:()=>Ye});module.exports=nt(Ot);var rt=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,v=rt();var pe=require("child_process"),I=require("fs"),Ge=D(require("path"),1),m=D(require("process"),1),T=require("@urun-sh/core");function le(e,n,t,r){let o=e.response??{},s={request_id:t,consumer_id:r,stream:!0,kind:"chat",messages:n};return typeof o.instructions=="string"&&(s.instructions=o.instructions),Array.isArray(o.modalities)&&(s.modalities=o.modalities),typeof o.temperature=="number"&&(s.temperature=o.temperature),typeof o.max_output_tokens=="number"&&(s.max_output_tokens=o.max_output_tokens),o.tools!==void 0&&(s.tools=o.tools),s}function de(e,n,t){let r={request_id:n,consumer_id:t,stream:!!e.stream,kind:"responses",input:e.input};return e.model&&(r.model=e.model),e.tools!==void 0&&(r.tools=e.tools),typeof e.temperature=="number"&&(r.temperature=e.temperature),typeof e.max_output_tokens=="number"&&(r.max_output_tokens=e.max_output_tokens),r}function me(e){if(e instanceof Error)return{type:"error",error:{type:"urun_error",code:e.name||null,message:e.message}};if(e&&typeof e=="object"&&e.t==="error"){let n=e,t=n.body??{};return{type:"error",error:{type:"urun_error",code:n.code??null,message:t.message??"unknown error"}}}return{type:"error",error:{type:"urun_error",code:null,message:String(e)}}}var ot="llm-resp";async function*z(e,n){let t=`${ot}:${n}`,r=`resp_${n}`;yield{type:"response.created",response:{id:r,status:"in_progress"}};for await(let o of e.stream(t).messages()){let s=o;if(s.t==="delta")yield{type:"response.output_text.delta",item_id:r,delta:s.delta};else if(s.t==="response"){yield{type:"response.completed",response:{id:r,status:"completed",...s.body}};return}else if(s.t==="error"){yield me(s);return}}}var st="llm",B=class{constructor(n){this.session=n}session;get consumerId(){return this.session.consumerId}write(n){this.session.doc(st).set({requests:{[n.request_id]:{payload:n,consumer_id:n.consumer_id,stream:n.stream}}})}sendResponses(n,t){let r=de(n,t,this.consumerId);return this.write(r),z(this.session,t)}sendResponseCreate(n,t,r){let o=le(n,t,r,this.consumerId);return this.write(o),z(this.session,r)}};var fe=0;function it(){return fe+=1,`req_${Date.now().toString(36)}_${fe.toString(36)}`}var N=class{transport;constructor(n){this.transport=new B(n)}responses={create:async n=>{let t=it(),r=this.transport.sendResponses(n,t);return Object.assign((async function*(){yield*r})(),{requestId:t})}}};async function ye(e){let t=await(e.fetchImpl??fetch)(`${e.catalogUrl}/model_catalog?select=model_id,variant`,{headers:{apikey:e.anonKey,Authorization:`Bearer ${e.anonKey}`}});if(!t.ok)throw new Error(`model_catalog fetch failed: ${t.status}`);return await t.json()}var ke=require("http");var ge="https://api.urun.sh/v1";function H(e){return e.toLowerCase().replace(/[^\p{L}\p{N}-]/gu,"-").replace(/^-+|-+$/g,"")}var k=class extends Error{};async function he(e){let n=e.fetchImpl??fetch,t=`${e.apiUrl.replace(/\/+$/,"")}/apps`,r=await n(t,{headers:{Authorization:`Bearer ${e.apiKey}`,Accept:"application/json"}});if(!r.ok)throw new Error(`org apps listing failed: GET ${t} \u2192 ${r.status}`);let o=await r.json();if(!Array.isArray(o.apps))throw new Error(`org apps listing returned no "apps" array (GET ${t})`);if(o.truncated===!0)throw new Error(`org apps listing was truncated (GET ${t} returned ${o.apps.length} of more) \u2014 model discovery would silently omit deployed apps`);return o.apps}var at=6e4,J=class{constructor(n){this.opts=n}opts;pool=new Map;appsCache=null;seed(n,t){this.pool.set(n,Promise.resolve(t))}async deployedApps(){if(!this.opts.listApps)return[];let n=this.opts.appsTtlMs??at;if(this.appsCache&&Date.now()-this.appsCache.at<n)return this.appsCache.apps;let t=await this.opts.listApps();return this.appsCache={at:Date.now(),apps:t},t}servable(n){return n.filter(t=>t.function_name===this.opts.fnName&&t.deployment_status==="active").map(t=>t.app_slug)}async availableIds(){let n=new Set([this.opts.defaultApp]);if(this.opts.listApps)for(let t of this.servable(await this.deployedApps()))n.add(t);for(let t of this.pool.keys())n.add(t);return[this.opts.defaultApp,...[...n].filter(t=>t!==this.opts.defaultApp).sort()]}async resolveApp(n){let t=(n??"").trim();if(!t||t==="urun")return this.opts.defaultApp;let r=H(t);if(r===this.opts.defaultApp)return this.opts.defaultApp;if(this.pool.has(r))return r;if(this.opts.listApps){let o=await this.deployedApps(),s=this.servable(o);if(s.includes(r))return r;let a=s.filter(u=>u.startsWith(`${r}-`));if(a.length===1)return a[0];if(a.length>1)throw new k(`model "${t}" is ambiguous across deployed apps ${a.join(", ")} \u2014 name the exact app slug (or catalog id:variant)`);let i=o.find(u=>u.app_slug===r||u.app_slug.startsWith(`${r}-`));if(i)throw new k(`model "${t}" maps to app "${i.app_slug}", which is not an active "${this.opts.fnName}" app \u2014 deploy it with \`urun serve ${t}\`; available models: ${(await this.availableIds()).join(", ")}`)}if(this.opts.listCatalog){let s=(await this.opts.listCatalog()).find(a=>t===a.model_id||t===`${a.model_id}:${a.variant}`||r===H(a.model_id)||r===H(`${a.model_id}-${a.variant}`));if(s)throw new k(`model "${t}" is in the uRun catalog but not deployed \u2014 deploy it with \`urun serve ${s.model_id}\`; available models: ${(await this.availableIds()).join(", ")}`)}return this.opts.defaultApp}async sessionFor(n){let t=await this.resolveApp(n),r=this.pool.get(t);return r||(r=Promise.resolve(this.opts.openSession(t)),this.pool.set(t,r),r.catch(()=>this.pool.delete(t))),{app:t,entry:await r}}async modelList(){return{object:"list",data:(await this.availableIds()).map(t=>({id:t,object:"model",created:0,owned_by:"urun"}))}}async closeAll(){let n=[...this.pool.values()];this.pool.clear();let t=[];if(await Promise.all(n.map(async r=>{try{await this.opts.closeSession(await r)}catch(o){t.push(String(o instanceof Error?o.message:o))}})),t.length>0)throw new Error(`failed to close ${t.length} pooled session(s): ${t.join("; ")}`)}};var X=class e{startedAt=Date.now();requests={};models={};ttftMs=[];tokRates=[];tokensOut=0;charsOut=0;localInBytes=0;naiveInBytes=0;request(n,t,r){this.requests[n]=(this.requests[n]??0)+1,this.localInBytes+=t,this.naiveInBytes+=r}modelEntry(n){let t=this.models[n];if(t)return t;let r=Object.keys(this.models).length>=pt?"(other)":n;return this.models[r]??={requests:0,tokens_out:0}}model(n){this.modelEntry(n).requests+=1}track(n,t){let r=this,o=performance.now(),s=null,a=0;return(async function*(){for await(let u of n)u.type==="response.output_text.delta"&&typeof u.delta=="string"&&(s===null&&(s=performance.now(),r.ttftMs.push(s-o),r.ttftMs.length>512&&r.ttftMs.shift()),a+=1,r.tokensOut+=1,r.charsOut+=u.delta.length,t!==void 0&&(r.modelEntry(t).tokens_out+=1)),yield u;let i=(performance.now()-(s??o))/1e3;a>0&&i>0&&(r.tokRates.push(a/i),r.tokRates.length>512&&r.tokRates.shift())})()}static p50(n){if(!n.length)return null;let t=[...n].sort((r,o)=>r-o);return t[Math.floor(t.length/2)]}snapshot(){let n=Object.values(this.requests).reduce((t,r)=>t+r,0);return{uptime_s:Math.round((Date.now()-this.startedAt)/1e3),requests:this.requests,models:this.models,tokens_out:this.tokensOut,chars_out:this.charsOut,ttft_ms:{p50:e.p50(this.ttftMs),last:this.ttftMs.at(-1)??null},tok_per_s:{p50:e.p50(this.tokRates),last:this.tokRates.at(-1)??null},traffic:{local_request_bytes:this.localInBytes,naive_baseline:{request_bytes:this.naiveInBytes,connections:n},persistent_connections:1,history_bytes_saved:Math.max(0,this.naiveInBytes-this.localInBytes),history_bytes_saved_pct:this.naiveInBytes>0?Math.round((1-this.localInBytes/this.naiveInBytes)*1e3)/10:null}}}};function Q(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function R(e,n,t){e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(t))}function _(e,n,t,r="invalid_request_error"){R(e,n,{error:{message:t,type:r}})}function Z(e,n,t){if(n==="anthropic"){R(e,404,{type:"error",error:{type:"not_found_error",message:t.message}});return}R(e,404,{error:{message:t.message,type:"invalid_request_error",code:"model_not_found"}})}var pt=256,ut=128;function ee(e){return typeof e.model!="string"||!e.model.trim()?"(default)":e.model.trim().slice(0,ut)}var _e=64*1024*1024,q=class extends Error{};async function ct(e){let n=[],t=0;for await(let o of e){if(t+=o.length,t>_e)throw new q(`request body exceeds ${_e} bytes`);n.push(o)}let r=Buffer.concat(n).toString("utf8");return r?JSON.parse(r):{}}function K(e,n,t,r){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:n,choices:[{index:0,delta:t,finish_reason:r}]}}var lt=256;function dt(e){if(typeof e=="string")return[{role:"user",content:e}];if(Array.isArray(e))return e;throw new Error("responses input must be a string or an array of messages/items")}var V=class{conversations=new Map;thread(n,t){let r=dt(t);if(n==null)return r;let o=this.conversations.get(String(n));if(!o)throw new Error(`unknown previous_response_id ${String(n)} (proxy restarts drop stored responses)`);return[...o,...r]}remember(n,t,r){this.conversations.set(n,[...t,{role:"assistant",content:r}]);for(let o of this.conversations.keys()){if(this.conversations.size<=lt)break;this.conversations.delete(o)}}};function te(e){let n=e?.output;return Array.isArray(n)?n.filter(t=>t.type==="function_call"):[]}function L(e){return e.find(n=>n.type==="response.completed")?.response??null}function mt(e){if(Array.isArray(e))return e.map(n=>{let t=n.function;return!t||typeof t!="object"?n:{type:"function",name:t.name,description:t.description,parameters:t.parameters,strict:t.strict}})}var G=class extends Error{};function ft(e,n){return Array.isArray(n)?n.map(t=>{let r=t;if(r.type==="text")return{type:e==="assistant"?"output_text":"input_text",text:r.text};if(r.type==="image_url"){let o=r.image_url??{};return{type:"input_image",image_url:o.url,detail:o.detail}}throw new G(`unsupported chat content part type "${String(r.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function yt(e){let n=[];for(let t of e){if(t.role==="tool"){n.push({type:"function_call_output",call_id:t.tool_call_id,output:typeof t.content=="string"?t.content:JSON.stringify(t.content??"")});continue}if(t.role==="assistant"&&Array.isArray(t.tool_calls)){typeof t.content=="string"&&t.content&&n.push({role:"assistant",content:t.content});for(let r of t.tool_calls){let o=r.function??{};n.push({type:"function_call",call_id:r.id,name:o.name,arguments:o.arguments})}continue}n.push({...t,content:ft(t.role,t.content)})}return n}function we(e){return te(e).map((n,t)=>({index:t,id:n.call_id??n.id??`call_${t}`,type:"function",function:{name:n.name??"",arguments:n.arguments??"{}"}}))}function xe(e,n){let t=n?.output_text;return typeof t=="string"?t:e.filter(r=>r.type==="response.output_text.delta"&&typeof r.delta=="string").map(r=>r.delta).join("")}async function gt(e,n,t,r,o){let s=e.stream===!0,a;try{a=t.thread(e.previous_response_id,e.input)}catch(p){_(r,400,String(p instanceof Error?p.message:p));return}e.previous_response_id!=null&&(o.naiveInBytes+=Buffer.byteLength(JSON.stringify(a))-Buffer.byteLength(JSON.stringify(e.input)));let i=`resp_${Math.random().toString(36).slice(2,14)}`,u=e.store!==!1,d=ee(e);o.model(d);let l;try{l=await n.createResponse({model:e.model,input:a,stream:s,tools:e.tools,temperature:e.temperature,max_output_tokens:e.max_output_tokens})}catch(p){if(p instanceof k){Z(r,"openai",p);return}throw p}let f=[];if(s){Q(r);let p=g=>{r.write(`event: ${String(g.type??"message")}
3
+ data: ${JSON.stringify(g)}
4
4
 
5
- `)}l&&t.remember(a,i,z(m,v(m))),r.write(`data: [DONE]
5
+ `)},c=g=>g.response&&typeof g.response=="object"?{...g,response:{...g.response,id:i}}:g,y=`item_${i.slice(5)}`,S=!1,b=!1,h=!1,E="",P=g=>{h&&(h=!1,p({type:"response.output_text.done",item_id:y,output_index:0,content_index:0,text:E}),p({type:"response.content_part.done",item_id:y,output_index:0,content_index:0,part:{type:"output_text",text:E}}),p({type:"response.output_item.done",output_index:0,item:{id:y,type:"message",role:"assistant",status:g,content:[{type:"output_text",text:E}]}}))};for await(let g of o.track(l,d)){f.push(g);let U=String(g.type??"");if(U==="response.created"||U==="response.in_progress"){S=!0,p(c(g));continue}if(U==="response.output_item.added"){b=!0,p(c(g));continue}if(U==="response.output_text.delta"&&!b){S||(S=!0,p({type:"response.created",response:{id:i,object:"response",status:"in_progress"}})),h||(h=!0,p({type:"response.output_item.added",output_index:0,item:{id:y,type:"message",role:"assistant",status:"in_progress",content:[]}}),p({type:"response.content_part.added",item_id:y,output_index:0,content_index:0,part:{type:"output_text",text:""}})),E+=String(g.delta??""),p({type:U,item_id:y,output_index:0,content_index:0,delta:g.delta});continue}if(U==="response.completed"&&!b){let ze=h;P("completed"),te(g.response).forEach((O,He)=>{let $=(ze?1:0)+He,j=O.id??O.call_id??`fc_${$}`,W=O.arguments??"",ue={id:j,type:"function_call",call_id:O.call_id??j,name:O.name??""};p({type:"response.output_item.added",output_index:$,item:{...ue,arguments:"",status:"in_progress"}}),p({type:"response.function_call_arguments.delta",item_id:j,output_index:$,delta:W}),p({type:"response.function_call_arguments.done",item_id:j,output_index:$,arguments:W}),p({type:"response.output_item.done",output_index:$,item:{...ue,arguments:W,status:"completed"}})}),p(c(g));continue}p(c(g))}P("incomplete"),u&&t.remember(i,a,xe(f,L(f))),r.write(`data: [DONE]
6
6
 
7
- `),r.end();return}let d=null;for await(let u of o.track(p)){if(m.push(u),u.type==="error"){f(r,502,JSON.stringify(u),"upstream_error");return}u.type==="response.completed"&&(d=u.response)}if(d==null){f(r,502,"upstream produced no response.completed event","upstream_error");return}let y=z(m,d);l&&t.remember(a,i,y),w(r,200,{...d,id:a})}async function Ue(e,n,t,r){let o=e.messages;if(!Array.isArray(o)){f(t,400,"chat/completions requires a messages array");return}let s=String(e.model??"urun"),i=`chatcmpl-${Math.random().toString(36).slice(2,14)}`,a;try{a=Ee(o)}catch(u){if(u instanceof U){f(t,400,u.message);return}throw u}let l=await n.createResponse({model:e.model,input:a,stream:!0,tools:Se(e.tools),temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens});if(e.stream===!0){M(t);let u=[];t.write(`data: ${JSON.stringify(E(i,s,{role:"assistant"},null))}
7
+ `),r.end();return}let w=null;for await(let p of o.track(l,d)){if(f.push(p),p.type==="error"){_(r,502,JSON.stringify(p),"upstream_error");return}p.type==="response.completed"&&(w=p.response)}if(w==null){_(r,502,"upstream produced no response.completed event","upstream_error");return}let x=xe(f,w);u&&t.remember(i,a,x),R(r,200,{...w,id:i})}async function ht(e,n,t,r){let o=e.messages;if(!Array.isArray(o)){_(t,400,"chat/completions requires a messages array");return}let s=String(e.model??"urun"),a=`chatcmpl-${Math.random().toString(36).slice(2,14)}`,i;try{i=yt(o)}catch(p){if(p instanceof G){_(t,400,p.message);return}throw p}let u=ee(e);r.model(u);let d;try{d=await n.createResponse({model:e.model,input:i,stream:!0,tools:mt(e.tools),temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens})}catch(p){if(p instanceof k){Z(t,"openai",p);return}throw p}if(e.stream===!0){Q(t);let p=[];t.write(`data: ${JSON.stringify(K(a,s,{role:"assistant"},null))}
8
8
 
9
- `);for await(let h of r.track(l))if(u.push(h),h.type==="response.output_text.delta"&&typeof h.delta=="string")t.write(`data: ${JSON.stringify(E(i,s,{content:h.delta},null))}
9
+ `);for await(let y of r.track(d,u))if(p.push(y),y.type==="response.output_text.delta"&&typeof y.delta=="string")t.write(`data: ${JSON.stringify(K(a,s,{content:y.delta},null))}
10
10
 
11
- `);else if(h.type==="error"){t.write(`data: ${JSON.stringify({error:h})}
11
+ `);else if(y.type==="error"){t.write(`data: ${JSON.stringify({error:y})}
12
12
 
13
- `),t.end();return}let c=W(v(u));c.length>0&&t.write(`data: ${JSON.stringify(E(i,s,{tool_calls:c},null))}
13
+ `),t.end();return}let c=we(L(p));c.length>0&&t.write(`data: ${JSON.stringify(K(a,s,{tool_calls:c},null))}
14
14
 
15
- `),t.write(`data: ${JSON.stringify(E(i,s,{},c.length>0?"tool_calls":"stop"))}
15
+ `),t.write(`data: ${JSON.stringify(K(a,s,{},c.length>0?"tool_calls":"stop"))}
16
16
 
17
17
  `),t.write(`data: [DONE]
18
18
 
19
- `),t.end();return}let p="",m=[];for await(let u of r.track(l))if(m.push(u),u.type==="response.output_text.delta"&&typeof u.delta=="string"&&(p+=u.delta),u.type==="error"){f(t,502,JSON.stringify(u),"upstream_error");return}let d=W(v(m)).map(({index:u,...c})=>c),y={role:"assistant",content:p||null};d.length>0&&(y.tool_calls=d),w(t,200,{id:i,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:s,choices:[{index:0,message:y,finish_reason:d.length>0?"tool_calls":"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}function Ie(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>n.type==="text").map(n=>String(n.text??"")).join(""):""}var k=class extends Error{constructor(n){super(`unsupported anthropic content block type "${n}" \u2014 the proxy translates text, tool_use and tool_result blocks`)}};function Oe(e){if(Array.isArray(e))return e.map(n=>{let t=n;return{type:"function",name:t.name,description:t.description,parameters:t.input_schema}})}function Ne(e){if(typeof e=="string")return e;if(e==null)return"";if(!Array.isArray(e))throw new k(typeof e);let n="";for(let t of e){let r=String(t.type??"");if(r!=="text")throw new k(`tool_result > ${r}`);n+=String(t.text??"")}return n}function Pe(e){let{role:n,content:t}=e;if(typeof t=="string")return[{role:n,content:t}];if(t==null)return[];if(!Array.isArray(t))throw new k(typeof t);let r=[],o="",s=()=>{o&&(r.push({role:n,content:o}),o="")};for(let i of t){let a=String(i.type??"");if(a==="text")o+=String(i.text??"");else if(a==="tool_use")s(),r.push({type:"function_call",call_id:i.id,name:i.name,arguments:JSON.stringify(i.input??{})});else if(a==="tool_result")s(),r.push({type:"function_call_output",call_id:i.tool_use_id,output:Ne(i.content)});else{if(a==="thinking"||a==="redacted_thinking")continue;throw new k(a)}}return s(),r}function H(e){return V(e).map((n,t)=>{let r;try{r=JSON.parse(n.arguments||"{}")}catch{throw new Error(`upstream function_call "${n.name??""}" arguments are not valid JSON`)}return{type:"tool_use",id:n.call_id??n.id??`toolu_${t}`,name:n.name??"",input:r}})}async function $e(e,n,t,r){let o=e.messages;if(!Array.isArray(o)){f(t,400,"messages requires a messages array");return}let s=String(e.model??"urun"),i=`msg_${Math.random().toString(36).slice(2,14)}`,a=[];try{e.system&&a.push({role:"system",content:Ie(e.system)});for(let c of o)a.push(...Pe(c))}catch(c){if(c instanceof k){f(t,400,c.message);return}throw c}let l=await n.createResponse({model:e.model,input:a,stream:!0,tools:Oe(e.tools),temperature:e.temperature,max_output_tokens:e.max_tokens}),p=(c,h)=>{t.write(`event: ${c}
20
- data: ${JSON.stringify({type:c,...h})}
21
-
22
- `)};if(e.stream===!0){let c=r.track(l);M(t),p("message_start",{message:{id:i,type:"message",role:"assistant",content:[],model:s,stop_reason:null,usage:{input_tokens:0,output_tokens:0}}}),p("content_block_start",{index:0,content_block:{type:"text",text:""}});let h=0,J=[];for await(let _ of c)if(J.push(_),_.type==="response.output_text.delta"&&typeof _.delta=="string")h+=1,p("content_block_delta",{index:0,delta:{type:"text_delta",text:_.delta}});else if(_.type==="error"){p("error",{error:{type:"api_error",message:JSON.stringify(_)}}),t.end();return}let O;try{O=H(v(J))}catch(_){p("error",{error:{type:"api_error",message:String(_ instanceof Error?_.message:_)}}),t.end();return}p("content_block_stop",{index:0}),O.forEach((_,ce)=>{let N=1+ce;p("content_block_start",{index:N,content_block:{..._,input:{}}}),p("content_block_delta",{index:N,delta:{type:"input_json_delta",partial_json:JSON.stringify(_.input??{})}}),p("content_block_stop",{index:N})}),p("message_delta",{delta:{stop_reason:O.length>0?"tool_use":"end_turn"},usage:{output_tokens:h}}),p("message_stop",{}),t.end();return}let m="",d=[];for await(let c of r.track(l))if(d.push(c),c.type==="response.output_text.delta"&&typeof c.delta=="string"&&(m+=c.delta),c.type==="error"){f(t,502,JSON.stringify(c),"upstream_error");return}let y;try{y=H(v(d))}catch(c){f(t,502,String(c instanceof Error?c.message:c),"upstream_error");return}let u=[];(m||y.length===0)&&u.push({type:"text",text:m}),u.push(...y),w(t,200,{id:i,type:"message",role:"assistant",content:u,model:s,stop_reason:y.length>0?"tool_use":"end_turn",usage:{input_tokens:0,output_tokens:0}})}function Q(e){let{clients:n,apiKey:t}=e,r=new T,o=new $;return(0,X.createServer)((s,i)=>{(async()=>{let a=new URL(s.url??"/","http://localhost");if(s.method==="GET"&&a.pathname==="/healthz"){w(i,200,{ok:!0});return}if(s.method==="GET"&&a.pathname==="/stats"){w(i,200,o.snapshot());return}if(t&&(s.headers.authorization??"")!==`Bearer ${t}`){f(i,401,"invalid local proxy api key","authentication_error");return}if(s.method==="GET"&&a.pathname==="/v1/models"){w(i,200,await n.listModels());return}if(s.method!=="POST"){f(i,404,`no route for ${s.method} ${a.pathname}`);return}let l;try{l=await ve(s)}catch(m){if(m instanceof b){f(i,413,m.message,"request_too_large");return}f(i,400,"request body is not valid JSON");return}let p=Buffer.byteLength(JSON.stringify(l));if(a.pathname==="/v1/responses"){o.request("responses",p,p),await be(l,n,r,i,o);return}if(a.pathname==="/v1/chat/completions"){o.request("chat_completions",p,p),await Ue(l,n,i,o);return}if(a.pathname==="/v1/messages"){o.request("messages",p,p),await $e(l,n,i,o);return}f(i,404,`no route for POST ${a.pathname}`)})().catch(a=>{i.headersSent?i.end():f(i,500,String(a),"proxy_error")})})}var I={claude:{bin:"claude",env:"anthropic"},codex:{bin:"codex",env:"openai"},pi:{bin:"pi",env:"openai"},aider:{bin:"aider",env:"openai"},opencode:{bin:"opencode",env:"openai"},crush:{bin:"crush",env:"openai"}};function j(e,n="openai"){if(n==="anthropic")return{ANTHROPIC_BASE_URL:`http://127.0.0.1:${e}`,ANTHROPIC_API_KEY:"urun-local"};let t=`http://127.0.0.1:${e}/v1`;return{OPENAI_BASE_URL:t,OPENAI_API_BASE:t,OPENAI_API_KEY:"urun-local"}}function Z(e,n,t){let r={...e,...j(n,t)};return delete r.URUN_API_KEY,delete r.URUN_JWT,r}function ee(e){let n=Number(e);if(!Number.isInteger(n)||n<=0)throw new Error(`--port needs a positive integer, got ${e}`);return n}function te(e){if(e[0]!=="--port")return null;let n=ee(e[1]);return e.splice(0,2),n}function C(e){let n=e.indexOf("--port");if(n===-1)return 4141;let t=ee(e[n+1]);return e.splice(n,2),t}function L(e,n){let t=(e[n]??"").trim();if(!t)throw new Error(`${n} is not set. The proxy needs URUN_BASE_URL, URUN_ORG_ID, URUN_APP and either URUN_API_KEY (the org key; the proxy vends short-lived function-scoped client tokens from it via the SDK) or URUN_JWT (an explicit pre-vended token override) \u2014 plus optional URUN_FUNCTION, default "serve" \u2014 to open the backhaul session.`);return t}function ne(e){let n=L(e,"URUN_BASE_URL"),t=L(e,"URUN_ORG_ID"),r=L(e,"URUN_APP"),o=(e.URUN_FUNCTION??"serve").trim()||"serve",s=(e.URUN_JWT??"").trim();if(s)return{baseUrl:n,orgId:t,appId:r,fnName:o,auth:{lane:"jwt",jwt:s}};let i=(e.URUN_API_KEY??"").trim();if(i){let a=(e.URUN_GATEWAY_URL??"").trim(),l=a?Te(a):void 0;return{baseUrl:n,orgId:t,appId:r,fnName:o,auth:{lane:"api-key",apiKey:i,gatewayUrl:l}}}throw new Error("neither URUN_API_KEY nor URUN_JWT is set. Set URUN_API_KEY (the org API key \u2014 the proxy vends short-lived, function-scoped client tokens from it via the SDK, so the key never reaches the agent process) or URUN_JWT (an explicit pre-vended token; when set it always wins). URUN_BASE_URL, URUN_ORG_ID and URUN_APP are also required.")}function Te(e){let n=new URL(e),t=n.hostname==="localhost"||n.hostname==="127.0.0.1"||n.hostname==="[::1]";if(n.protocol!=="https:"&&!t)throw new Error(`URUN_GATEWAY_URL must be https (got ${e}) \u2014 the org API key rides the mint call's Authorization header`);return e}function re(e,n,t){let r=e[t];if(typeof r!="function")throw new Error(`app "${n}" has no function "${t}" (set URUN_FUNCTION)`);let o=r();if(typeof o.end!="function")throw new Error(`app "${n}" function "${t}" returned a session without end()`);return o}function ie(){let{baseUrl:e,orgId:n,appId:t,fnName:r,auth:o}=ne(g.default.env);if(o.lane==="jwt"){let l=(0,R.App)(t,{baseUrl:e,orgId:n,jwt:o.jwt});return re(l,t,r)}let{apiKey:s,gatewayUrl:i}=o,a=(0,R.App)(t,{baseUrl:e,orgId:n,getAccessToken:async()=>(await(0,R.createClientToken)(s,{baseUrl:i,expiresIn:300,allowedFunctions:[`${t}/${r}`]})).token});return re(a,t,r)}function ae(e){let n=new A(e);return{createResponse:t=>n.responses.create(t),listModels:async()=>{let t=(g.default.env.URUN_CATALOG_URL??"").trim(),r=(g.default.env.URUN_CATALOG_ANON_KEY??"").trim();return!t||!r?{object:"list",data:[{id:"urun",object:"model",owned_by:"urun"}]}:F({catalogUrl:t,anonKey:r})}}}function ue(e){for(let[n,t]of Object.entries(j(e)))g.default.stdout.write(`export ${n}=${t}
23
- `)}async function oe(e){let n=ie(),t=Q({clients:ae(n)});return await new Promise((r,o)=>{t.once("error",o),t.listen(e,"127.0.0.1",r)}),g.default.stdout.write(`urun openai proxy listening on http://127.0.0.1:${e}/v1
24
- `),ue(e),{close:async()=>{let r=new Promise(o=>t.close(()=>o()));t.closeAllConnections(),await r,await n.end()}}}async function Le(){let e=g.default.argv.slice(2),n=te(e),t=e.shift()??"proxy";if(t==="env")return ue(n??C(e)),0;if(t==="proxy"){let o=n??C(e),s=await oe(o);return await new Promise(i=>{g.default.once("SIGINT",i),g.default.once("SIGTERM",i)}),await s.close(),0}let r=t==="run"?e.shift():t;{if(!r)throw new Error(`launch needs an agent (${Object.keys(I).join("|")}) or \`-- <cmd>\``);let o=n??4141,s,i,a="openai";if(r==="--"){if(s=e.shift()??"",i=e,!s)throw new Error("`-- <cmd>` needs a command to launch")}else{let d=I[r];if(!d)throw new Error(`unknown command/agent ${r}; commands: proxy | env; agents: ${Object.keys(I).join(" | ")} \u2014 or \`-- <cmd>\``);s=d.bin,i=[...d.args??[],...e],a=d.env}let l=await oe(o),p=(0,se.spawn)(s,i,{stdio:"inherit",env:Z(g.default.env,o,a)}),m=await new Promise(d=>{p.once("exit",y=>d(y??1)),p.once("error",y=>{g.default.stderr.write(`failed to launch ${s}: ${String(y)}
25
- `),d(127)})});return await l.close(),m}}Le().then(e=>g.default.exit(e),e=>{g.default.stderr.write(`${String(e instanceof Error?e.message:e)}
26
- `),g.default.exit(1)});0&&(module.exports={buildClients,resolveSessionFromEnv});
19
+ `),t.end();return}let l="",f=[];for await(let p of r.track(d,u))if(f.push(p),p.type==="response.output_text.delta"&&typeof p.delta=="string"&&(l+=p.delta),p.type==="error"){_(t,502,JSON.stringify(p),"upstream_error");return}let w=we(L(f)).map(({index:p,...c})=>c),x={role:"assistant",content:l||null};w.length>0&&(x.tool_calls=w),R(t,200,{id:a,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:s,choices:[{index:0,message:x,finish_reason:w.length>0?"tool_calls":"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}function _t(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>n.type==="text").map(n=>String(n.text??"")).join(""):""}var A=class extends Error{constructor(n){super(`unsupported anthropic content block type "${n}" \u2014 the proxy translates text, tool_use and tool_result blocks`)}};function wt(e){if(Array.isArray(e))return e.map(n=>{let t=n;return{type:"function",name:t.name,description:t.description,parameters:t.input_schema}})}function xt(e){if(typeof e=="string")return e;if(e==null)return"";if(!Array.isArray(e))throw new A(typeof e);let n="";for(let t of e){let r=String(t.type??"");if(r!=="text")throw new A(`tool_result > ${r}`);n+=String(t.text??"")}return n}function vt(e){let{role:n,content:t}=e;if(typeof t=="string")return[{role:n,content:t}];if(t==null)return[];if(!Array.isArray(t))throw new A(typeof t);let r=[],o="",s=()=>{o&&(r.push({role:n,content:o}),o="")};for(let a of t){let i=String(a.type??"");if(i==="text")o+=String(a.text??"");else if(i==="tool_use")s(),r.push({type:"function_call",call_id:a.id,name:a.name,arguments:JSON.stringify(a.input??{})});else if(i==="tool_result")s(),r.push({type:"function_call_output",call_id:a.tool_use_id,output:xt(a.content)});else{if(i==="thinking"||i==="redacted_thinking")continue;throw new A(i)}}return s(),r}function ve(e){return te(e).map((n,t)=>{let r;try{r=JSON.parse(n.arguments||"{}")}catch{throw new Error(`upstream function_call "${n.name??""}" arguments are not valid JSON`)}return{type:"tool_use",id:n.call_id??n.id??`toolu_${t}`,name:n.name??"",input:r}})}async function kt(e,n,t,r){let o=e.messages;if(!Array.isArray(o)){_(t,400,"messages requires a messages array");return}let s=String(e.model??"urun"),a=`msg_${Math.random().toString(36).slice(2,14)}`,i=[];try{e.system&&i.push({role:"system",content:_t(e.system)});for(let c of o)i.push(...vt(c))}catch(c){if(c instanceof A){_(t,400,c.message);return}throw c}let u=ee(e);r.model(u);let d;try{d=await n.createResponse({model:e.model,input:i,stream:!0,tools:wt(e.tools),temperature:e.temperature,max_output_tokens:e.max_tokens})}catch(c){if(c instanceof k){Z(t,"anthropic",c);return}throw c}let l=(c,y)=>{t.write(`event: ${c}
20
+ data: ${JSON.stringify({type:c,...y})}
21
+
22
+ `)};if(e.stream===!0){let c=r.track(d,u);Q(t),l("message_start",{message:{id:a,type:"message",role:"assistant",content:[],model:s,stop_reason:null,usage:{input_tokens:0,output_tokens:0}}}),l("content_block_start",{index:0,content_block:{type:"text",text:""}});let y=0,S=[];for await(let h of c)if(S.push(h),h.type==="response.output_text.delta"&&typeof h.delta=="string")y+=1,l("content_block_delta",{index:0,delta:{type:"text_delta",text:h.delta}});else if(h.type==="error"){l("error",{error:{type:"api_error",message:JSON.stringify(h)}}),t.end();return}let b;try{b=ve(L(S))}catch(h){l("error",{error:{type:"api_error",message:String(h instanceof Error?h.message:h)}}),t.end();return}l("content_block_stop",{index:0}),b.forEach((h,E)=>{let P=1+E;l("content_block_start",{index:P,content_block:{...h,input:{}}}),l("content_block_delta",{index:P,delta:{type:"input_json_delta",partial_json:JSON.stringify(h.input??{})}}),l("content_block_stop",{index:P})}),l("message_delta",{delta:{stop_reason:b.length>0?"tool_use":"end_turn"},usage:{output_tokens:y}}),l("message_stop",{}),t.end();return}let f="",w=[];for await(let c of r.track(d,u))if(w.push(c),c.type==="response.output_text.delta"&&typeof c.delta=="string"&&(f+=c.delta),c.type==="error"){_(t,502,JSON.stringify(c),"upstream_error");return}let x;try{x=ve(L(w))}catch(c){_(t,502,String(c instanceof Error?c.message:c),"upstream_error");return}let p=[];(f||x.length===0)&&p.push({type:"text",text:f}),p.push(...x),R(t,200,{id:a,type:"message",role:"assistant",content:p,model:s,stop_reason:x.length>0?"tool_use":"end_turn",usage:{input_tokens:0,output_tokens:0}})}function Re(e){let{clients:n,apiKey:t,identity:r}=e,o=new V,s=new X;return(0,ke.createServer)((a,i)=>{(async()=>{let u=new URL(a.url??"/","http://localhost");if(a.method==="GET"&&u.pathname==="/healthz"){R(i,200,{ok:!0});return}if(a.method==="GET"&&u.pathname==="/stats"){R(i,200,r?{identity:r,...s.snapshot()}:s.snapshot());return}if(t&&(a.headers.authorization??"")!==`Bearer ${t}`){_(i,401,"invalid local proxy api key","authentication_error");return}if(a.method==="GET"&&u.pathname==="/v1/models"){R(i,200,await n.listModels());return}if(a.method!=="POST"){_(i,404,`no route for ${a.method} ${u.pathname}`);return}let d;try{d=await ct(a)}catch(f){if(f instanceof q){_(i,413,f.message,"request_too_large");return}_(i,400,"request body is not valid JSON");return}let l=Buffer.byteLength(JSON.stringify(d));if(u.pathname==="/v1/responses"){s.request("responses",l,l),await gt(d,n,o,i,s);return}if(u.pathname==="/v1/chat/completions"){s.request("chat_completions",l,l),await ht(d,n,i,s);return}if(u.pathname==="/v1/messages"){s.request("messages",l,l),await kt(d,n,i,s);return}_(i,404,`no route for POST ${u.pathname}`)})().catch(u=>{i.headersSent?i.end():_(i,500,String(u),"proxy_error")})})}var Ae=D(require("os"),1),Se=D(require("path"),1),Ee=require("url"),Pe=require("util");var be="0.2.52";var Ue=4141,bt=be,F={claude:{bin:"claude",env:"anthropic"},codex:{bin:"codex",env:"openai"},pi:{bin:"pi",env:"openai"},aider:{bin:"aider",env:"openai"},opencode:{bin:"opencode",env:"openai"},crush:{bin:"crush",env:"openai"}};function oe(e,n="openai"){if(n==="anthropic")return{ANTHROPIC_BASE_URL:`http://127.0.0.1:${e}`,ANTHROPIC_API_KEY:"urun-local"};let t=`http://127.0.0.1:${e}/v1`;return{OPENAI_BASE_URL:t,OPENAI_API_BASE:t,OPENAI_API_KEY:"urun-local"}}function Ie(e,n,t){let r={...e,...oe(n,t)};return delete r.URUN_API_KEY,delete r.URUN_JWT,r}function Oe(e,n,t){let r=["-c","model_providers.urun.name=urun","-c",`model_providers.urun.base_url="http://127.0.0.1:${e}/v1"`,"-c",'model_providers.urun.wire_api="responses"',"-c",'model_provider="urun"'],o=t.indexOf("--"),s=o===-1?t:t.slice(0,o),a=s.some(l=>l==="-m"||l==="--model"||l.startsWith("--model=")),i=t[0]==="exec",u=s.includes("--skip-git-repo-check"),d=i&&!u?["exec","--skip-git-repo-check",...t.slice(1)]:t;return[...r,...a?[]:["-m",n],...d]}function $e(e,n){return n.some(r=>r==="--model"||r==="--provider"||r.startsWith("--model=")||r.startsWith("--provider="))?n:["--provider","urun","--model",e,...n]}function Ne(e,n,t){let r=(e.URUN_PI_EXTENSION_ENTRY??"").trim();if(r){if(!t(r))throw new Error(`URUN_PI_EXTENSION_ENTRY points at ${r}, which does not exist \u2014 the launcher that injected it (the vendored urun CLI shim) must materialize the pi extension bundle before spawning pi`);return r}let o=(0,Ee.fileURLToPath)(new URL("../pi-extension/standalone.cjs",n));if(!t(o))throw new Error(`pi extension entry not found at ${o} \u2014 the pi lane loads the self-contained @urun-sh/openai dist/pi-extension/standalone.cjs from the installed package (run \`urun compat pi\` via the npm-installed CLI, e.g. \`npx @urun-sh/openai\`), or pass an entry to pi yourself: \`pi -e <path-to-@urun-sh/openai>/dist/pi-extension/standalone.cjs\``);return o}function Le(e){let n=Number(e);if(!Number.isInteger(n)||n<0)throw new Error(`--port needs a non-negative integer (0 = OS-assigned ephemeral), got ${e}`);return n}function Ce(e){if(e[0]!=="--port")return null;let n=Le(e[1]);return e.splice(0,2),n}function se(e){let n=e.indexOf("--port");if(n===-1)return Ue;let t=Le(e[n+1]);return e.splice(n,2),t}function Te(e){if(e===0)throw new Error("`env` cannot use --port 0: it starts no proxy, so the OS never assigns the ephemeral port \u2014 pass the actual port of the running proxy");return e}function ne(e,n){let t=(e[n]??"").trim();if(!t)throw new Error(`${n} is not set. The proxy needs URUN_BASE_URL, URUN_ORG_ID, URUN_APP and either URUN_API_KEY (the org key; the proxy vends short-lived function-scoped client tokens from it via the SDK) or URUN_JWT (an explicit pre-vended token override) \u2014 plus optional URUN_FUNCTION, default "serve" \u2014 to open the backhaul session.`);return t}function C(e){let n=At(ne(e,"URUN_BASE_URL")),t=ne(e,"URUN_ORG_ID"),r=ne(e,"URUN_APP"),o=(e.URUN_FUNCTION??"serve").trim()||"serve",s=(e.URUN_API_URL??"").trim(),a=s?Y(s,"URUN_API_URL"):ge,i=(e.URUN_JWT??"").trim();if(i)return{baseUrl:n,orgId:t,appId:r,fnName:o,apiUrl:a,auth:{lane:"jwt",jwt:i}};let u=(e.URUN_API_KEY??"").trim();if(u){let d=(e.URUN_GATEWAY_URL??"").trim(),l=d?Y(d):void 0;return{baseUrl:n,orgId:t,appId:r,fnName:o,apiUrl:a,auth:{lane:"api-key",apiKey:u,gatewayUrl:l}}}throw new Error("neither URUN_API_KEY nor URUN_JWT is set. Set URUN_API_KEY (the org API key \u2014 the proxy vends short-lived, function-scoped client tokens from it via the SDK, so the key never reaches the agent process) or URUN_JWT (an explicit pre-vended token; when set it always wins). URUN_BASE_URL, URUN_ORG_ID and URUN_APP are also required.")}function At(e,n="URUN_BASE_URL"){if(/\/v1\/*$/.test(new URL(e).pathname))throw new Error(`${n} must be the session-gateway base (e.g. https://api.urun.sh), got ${e} \u2014 a trailing /v1 is the org control-plane API form (that belongs in URUN_API_URL); session allocation 404s against it. Drop the /v1.`);return e}function Y(e,n="URUN_GATEWAY_URL"){let t=new URL(e),r=t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]";if(t.protocol!=="https:"&&!r)throw new Error(`${n} must be https (got ${e}) \u2014 the org API key rides the request's Authorization header`);return e}function ie(e){return{app:e.appId,org:e.orgId,fn:e.fnName,base_url:e.baseUrl,proxy_version:bt}}function St(e,n){return e.app===n.app&&e.org===n.org&&e.fn===n.fn&&e.base_url===n.base_url&&e.proxy_version===n.proxy_version}var Et=250;async function ae(e,n=Et){try{let t=await fetch(`http://127.0.0.1:${e}/stats`,{signal:AbortSignal.timeout(n)});if(!t.ok)return null;let r=(await t.json()).identity;if(r==null||typeof r!="object")return null;let{app:o,org:s,fn:a,base_url:i,proxy_version:u}=r;return typeof o!="string"||typeof s!="string"||typeof a!="string"||typeof i!="string"||typeof u!="string"?null:{app:o,org:s,fn:a,base_url:i,proxy_version:u}}catch{return null}}async function je(e,n,t=Ue){if(e!=null)return{mode:"spawn",port:e};let r=await ae(t);return r!==null&&St(r,n)?{mode:"reuse",port:t,identity:r}:{mode:"spawn",port:0}}function Me(e,n=Ae.default.homedir()){return Se.default.join(n,".urun","logs",`compat-proxy-${e}.log`)}var re=["log","info","warn","error","debug","trace"];function De(e,n=process,t=console){let r=n.stdout.write,o=n.stderr.write,s=(i,...u)=>e.write(i,...u);n.stdout.write=s,n.stderr.write=s;let a=Object.fromEntries(re.map(i=>[i,t[i]]));for(let i of re)t[i]=(...u)=>{e.write(`${(0,Pe.format)(...u)}
23
+ `)};return()=>{n.stdout.write=r,n.stderr.write=o;for(let i of re)t[i]=a[i]}}function Be(e,n){let t="pass --port 0 for an OS-assigned ephemeral port";return n?`port ${e} is held by another urun-openai proxy serving app ${n.app} (org ${n.org}, fn ${n.fn}, version ${n.proxy_version}) \u2014 reuse it by pointing your agent at http://127.0.0.1:${e}, or ${t}`:`port ${e} is already in use and does not answer the urun-openai /stats identity probe \u2014 ${t}`}function Je(e,n,t){let r=e[t];if(typeof r!="function")throw new Error(`app "${n}" has no function "${t}" (set URUN_FUNCTION)`);let o=r();if(typeof o.end!="function")throw new Error(`app "${n}" function "${t}" returned a session without end()`);return o}function Ke(e,n){let{baseUrl:t,orgId:r,fnName:o,auth:s}=e;if(s.lane==="jwt"){let l=(0,T.App)(n,{baseUrl:t,orgId:r,jwt:s.jwt}),f=Je(l,n,o);return{session:f,responses:new N(f)}}let{apiKey:a,gatewayUrl:i}=s,u=(0,T.App)(n,{baseUrl:t,orgId:r,getAccessToken:async()=>(await(0,T.createClientToken)(a,{baseUrl:i,expiresIn:300,allowedFunctions:[`${n}/${o}`]})).token}),d=Je(u,n,o);return{session:d,responses:new N(d)}}function Ye(e){let n=(m.default.env.URUN_CATALOG_URL??"").trim(),t=n?Y(n,"URUN_CATALOG_URL"):"",r=(m.default.env.URUN_CATALOG_ANON_KEY??"").trim();(!t||!r)&&m.default.stderr.write(`urun compat: catalog oracle off (URUN_CATALOG_URL/URUN_CATALOG_ANON_KEY unset) \u2014 an undeployed uRun CATALOG model name falls through to the default app instead of a loud 404; deployed apps still resolve exactly, and /stats.models records every mapping
24
+ `);let o=e.auth,s=new J({defaultApp:e.appId,fnName:e.fnName,openSession:a=>Ke(e,a),closeSession:async a=>{await a.session.end()},listApps:o.lane==="api-key"?()=>he({apiUrl:e.apiUrl,apiKey:o.apiKey}):null,listCatalog:t&&r?()=>ye({catalogUrl:t,anonKey:r}):null});return s.seed(e.appId,Ke(e,e.appId)),s}function Fe(e){return{createResponse:async n=>{let{entry:t}=await e.sessionFor(n.model);return t.responses.responses.create(n)},listModels:()=>e.modelList()}}async function Pt(e,n,t){let r=(0,pe.spawn)(e,n,{stdio:"inherit",env:t});return new Promise(o=>{r.once("exit",s=>o(s??1)),r.once("error",s=>{m.default.stderr.write(`failed to launch ${e}: ${String(s)}
25
+ `),o(127)})})}function Ut(){return Ne(m.default.env,v,I.existsSync)}function We(e){for(let[n,t]of Object.entries(oe(e)))m.default.stdout.write(`export ${n}=${t}
26
+ `)}async function qe(e,n){let t=C(m.default.env),r=n?ie(t):void 0,o=Ye(t),s=Re({clients:Fe(o),identity:r});try{await new Promise((i,u)=>{s.once("error",u),s.listen(e,"127.0.0.1",i)})}catch(i){throw await o.closeAll().catch(()=>{}),i.code==="EADDRINUSE"?new Error(Be(e,await ae(e))):i}let a=s.address().port;return n&&(m.default.stdout.write(`urun openai proxy listening on http://127.0.0.1:${a}/v1
27
+ `),We(a)),{port:a,close:async()=>{let i=new Promise(u=>s.close(()=>u()));s.closeAllConnections(),await i,await o.closeAll()}}}async function It(){let e=m.default.argv.slice(2),n=Ce(e),t=e.shift()??"proxy";if(t==="env")return We(Te(n??se(e))),0;if(t==="proxy"){let o=n??se(e),s=await qe(o,!0);return await new Promise(a=>{m.default.once("SIGINT",a),m.default.once("SIGTERM",a)}),await s.close(),0}let r=t==="run"?e.shift():t;{if(!r)throw new Error(`launch needs an agent (${Object.keys(F).join("|")}) or \`-- <cmd>\``);if(r==="pi"){let c=C(m.default.env);return Pt("pi",["-e",Ut(),...$e(c.appId,e)],m.default.env)}let o,s,a="openai";if(r==="--"){if(o=e.shift()??"",s=e,!o)throw new Error("`-- <cmd>` needs a command to launch")}else{let c=F[r];if(!c)throw new Error(`unknown command/agent ${r}; commands: proxy | env; agents: ${Object.keys(F).join(" | ")} \u2014 or \`-- <cmd>\``);o=c.bin,s=[...c.args??[],...e],a=c.env}let i=await je(n,ie(C(m.default.env))),u=null,d=i.port;i.mode==="reuse"&&m.default.stdout.write(`reusing the running urun openai proxy on http://127.0.0.1:${d} (app ${i.identity.app}, fn ${i.identity.fn}, v${i.identity.proxy_version})
28
+ `);let l=null,f=null;if(i.mode!=="reuse"){u=await qe(i.port,!1),d=u.port;let c=Me(d);(0,I.mkdirSync)(Ge.default.dirname(c),{recursive:!0}),f=(0,I.createWriteStream)(c,{flags:"a"}),f.on("error",y=>{l?.(),l=null,m.default.stderr.write(`urun compat: proxy log ${c} failed: ${String(y)} \u2014 proxy output continues on the terminal
29
+ `)}),m.default.stdout.write(`urun openai proxy on http://127.0.0.1:${d}/v1 \u2014 proxy logs: ${c}
30
+ `),l=De(f)}r==="codex"&&(s=Oe(d,C(m.default.env).appId,s));let w=(0,pe.spawn)(o,s,{stdio:"inherit",env:Ie(m.default.env,d,a)}),x=await new Promise(c=>{w.once("exit",y=>c(y??1)),w.once("error",y=>{l?.(),l=null,m.default.stderr.write(`failed to launch ${o}: ${String(y)}
31
+ `),c(127)})}),p=null;try{u&&await u.close()}catch(c){p=c}finally{l?.(),l=null,f?.end()}return p!==null&&m.default.stderr.write(`urun compat: proxy teardown failed after the harness exited (harness exit code ${x} preserved): ${String(p instanceof Error?p.message:p)}
32
+ `),x}}It().then(e=>m.default.exit(e),e=>{m.default.stderr.write(`${String(e instanceof Error?e.message:e)}
33
+ `),m.default.exit(1)});0&&(module.exports={buildClients,buildRouter});
package/dist/proxy/cli.js CHANGED
@@ -1,6 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import{c as h,d as v}from"../chunk-GUQC3NSG.js";import{a as g}from"../chunk-YDXG2QGW.js";import{spawn as k}from"child_process";import s from"process";import{App as R,createClientToken as O}from"@urun-sh/core";var d={claude:{bin:"claude",env:"anthropic"},codex:{bin:"codex",env:"openai"},pi:{bin:"pi",env:"openai"},aider:{bin:"aider",env:"openai"},opencode:{bin:"opencode",env:"openai"},crush:{bin:"crush",env:"openai"}};function w(e,n="openai"){if(n==="anthropic")return{ANTHROPIC_BASE_URL:`http://127.0.0.1:${e}`,ANTHROPIC_API_KEY:"urun-local"};let t=`http://127.0.0.1:${e}/v1`;return{OPENAI_BASE_URL:t,OPENAI_API_BASE:t,OPENAI_API_KEY:"urun-local"}}function E(e,n,t){let o={...e,...w(n,t)};return delete o.URUN_API_KEY,delete o.URUN_JWT,o}function y(e){let n=Number(e);if(!Number.isInteger(n)||n<=0)throw new Error(`--port needs a positive integer, got ${e}`);return n}function _(e){if(e[0]!=="--port")return null;let n=y(e[1]);return e.splice(0,2),n}function f(e){let n=e.indexOf("--port");if(n===-1)return 4141;let t=y(e[n+1]);return e.splice(n,2),t}function U(e,n){let t=(e[n]??"").trim();if(!t)throw new Error(`${n} is not set. The proxy needs URUN_BASE_URL, URUN_ORG_ID, URUN_APP and either URUN_API_KEY (the org key; the proxy vends short-lived function-scoped client tokens from it via the SDK) or URUN_JWT (an explicit pre-vended token override) \u2014 plus optional URUN_FUNCTION, default "serve" \u2014 to open the backhaul session.`);return t}function N(e){let n=U(e,"URUN_BASE_URL"),t=U(e,"URUN_ORG_ID"),o=U(e,"URUN_APP"),r=(e.URUN_FUNCTION??"serve").trim()||"serve",i=(e.URUN_JWT??"").trim();if(i)return{baseUrl:n,orgId:t,appId:o,fnName:r,auth:{lane:"jwt",jwt:i}};let a=(e.URUN_API_KEY??"").trim();if(a){let c=(e.URUN_GATEWAY_URL??"").trim(),u=c?b(c):void 0;return{baseUrl:n,orgId:t,appId:o,fnName:r,auth:{lane:"api-key",apiKey:a,gatewayUrl:u}}}throw new Error("neither URUN_API_KEY nor URUN_JWT is set. Set URUN_API_KEY (the org API key \u2014 the proxy vends short-lived, function-scoped client tokens from it via the SDK, so the key never reaches the agent process) or URUN_JWT (an explicit pre-vended token; when set it always wins). URUN_BASE_URL, URUN_ORG_ID and URUN_APP are also required.")}function b(e){let n=new URL(e),t=n.hostname==="localhost"||n.hostname==="127.0.0.1"||n.hostname==="[::1]";if(n.protocol!=="https:"&&!t)throw new Error(`URUN_GATEWAY_URL must be https (got ${e}) \u2014 the org API key rides the mint call's Authorization header`);return e}function P(e,n,t){let o=e[t];if(typeof o!="function")throw new Error(`app "${n}" has no function "${t}" (set URUN_FUNCTION)`);let r=o();if(typeof r.end!="function")throw new Error(`app "${n}" function "${t}" returned a session without end()`);return r}function T(){let{baseUrl:e,orgId:n,appId:t,fnName:o,auth:r}=N(s.env);if(r.lane==="jwt"){let u=R(t,{baseUrl:e,orgId:n,jwt:r.jwt});return P(u,t,o)}let{apiKey:i,gatewayUrl:a}=r,c=R(t,{baseUrl:e,orgId:n,getAccessToken:async()=>(await O(i,{baseUrl:a,expiresIn:300,allowedFunctions:[`${t}/${o}`]})).token});return P(c,t,o)}function $(e){let n=new h(e);return{createResponse:t=>n.responses.create(t),listModels:async()=>{let t=(s.env.URUN_CATALOG_URL??"").trim(),o=(s.env.URUN_CATALOG_ANON_KEY??"").trim();return!t||!o?{object:"list",data:[{id:"urun",object:"model",owned_by:"urun"}]}:v({catalogUrl:t,anonKey:o})}}}function S(e){for(let[n,t]of Object.entries(w(e)))s.stdout.write(`export ${n}=${t}
3
- `)}async function A(e){let n=T(),t=g({clients:$(n)});return await new Promise((o,r)=>{t.once("error",r),t.listen(e,"127.0.0.1",o)}),s.stdout.write(`urun openai proxy listening on http://127.0.0.1:${e}/v1
4
- `),S(e),{close:async()=>{let o=new Promise(r=>t.close(()=>r()));t.closeAllConnections(),await o,await n.end()}}}async function L(){let e=s.argv.slice(2),n=_(e),t=e.shift()??"proxy";if(t==="env")return S(n??f(e)),0;if(t==="proxy"){let r=n??f(e),i=await A(r);return await new Promise(a=>{s.once("SIGINT",a),s.once("SIGTERM",a)}),await i.close(),0}let o=t==="run"?e.shift():t;{if(!o)throw new Error(`launch needs an agent (${Object.keys(d).join("|")}) or \`-- <cmd>\``);let r=n??4141,i,a,c="openai";if(o==="--"){if(i=e.shift()??"",a=e,!i)throw new Error("`-- <cmd>` needs a command to launch")}else{let p=d[o];if(!p)throw new Error(`unknown command/agent ${o}; commands: proxy | env; agents: ${Object.keys(d).join(" | ")} \u2014 or \`-- <cmd>\``);i=p.bin,a=[...p.args??[],...e],c=p.env}let u=await A(r),m=k(i,a,{stdio:"inherit",env:E(s.env,r,c)}),x=await new Promise(p=>{m.once("exit",l=>p(l??1)),m.once("error",l=>{s.stderr.write(`failed to launch ${i}: ${String(l)}
5
- `),p(127)})});return await u.close(),x}}L().then(e=>s.exit(e),e=>{s.stderr.write(`${String(e instanceof Error?e.message:e)}
6
- `),s.exit(1)});export{$ as buildClients,T as resolveSessionFromEnv};
2
+ import{a as S}from"../chunk-OLE2YJO3.js";import{a as k}from"../chunk-KJ25VEMG.js";import{c as w}from"../chunk-FSS2A7IU.js";import{a as A,c as I,d as O}from"../chunk-PS4BLX7J.js";import{spawn as V}from"child_process";import{createWriteStream as ce,existsSync as ue,mkdirSync as de}from"fs";import le from"path";import p from"process";import{App as F,createClientToken as me}from"@urun-sh/core";import te from"os";import ne from"path";import{fileURLToPath as re}from"url";import{format as oe}from"util";var $="0.2.52";var L=4141,se=$,x={claude:{bin:"claude",env:"anthropic"},codex:{bin:"codex",env:"openai"},pi:{bin:"pi",env:"openai"},aider:{bin:"aider",env:"openai"},opencode:{bin:"opencode",env:"openai"},crush:{bin:"crush",env:"openai"}};function E(e,t="openai"){if(t==="anthropic")return{ANTHROPIC_BASE_URL:`http://127.0.0.1:${e}`,ANTHROPIC_API_KEY:"urun-local"};let n=`http://127.0.0.1:${e}/v1`;return{OPENAI_BASE_URL:n,OPENAI_API_BASE:n,OPENAI_API_KEY:"urun-local"}}function T(e,t,n){let r={...e,...E(t,n)};return delete r.URUN_API_KEY,delete r.URUN_JWT,r}function j(e,t,n){let r=["-c","model_providers.urun.name=urun","-c",`model_providers.urun.base_url="http://127.0.0.1:${e}/v1"`,"-c",'model_providers.urun.wire_api="responses"',"-c",'model_provider="urun"'],o=n.indexOf("--"),s=o===-1?n:n.slice(0,o),a=s.some(u=>u==="-m"||u==="--model"||u.startsWith("--model=")),i=n[0]==="exec",c=s.includes("--skip-git-repo-check"),l=i&&!c?["exec","--skip-git-repo-check",...n.slice(1)]:n;return[...r,...a?[]:["-m",t],...l]}function C(e,t){return t.some(r=>r==="--model"||r==="--provider"||r.startsWith("--model=")||r.startsWith("--provider="))?t:["--provider","urun","--model",e,...t]}function G(e,t,n){let r=(e.URUN_PI_EXTENSION_ENTRY??"").trim();if(r){if(!n(r))throw new Error(`URUN_PI_EXTENSION_ENTRY points at ${r}, which does not exist \u2014 the launcher that injected it (the vendored urun CLI shim) must materialize the pi extension bundle before spawning pi`);return r}let o=re(new URL("../pi-extension/standalone.cjs",t));if(!n(o))throw new Error(`pi extension entry not found at ${o} \u2014 the pi lane loads the self-contained @urun-sh/openai dist/pi-extension/standalone.cjs from the installed package (run \`urun compat pi\` via the npm-installed CLI, e.g. \`npx @urun-sh/openai\`), or pass an entry to pi yourself: \`pi -e <path-to-@urun-sh/openai>/dist/pi-extension/standalone.cjs\``);return o}function K(e){let t=Number(e);if(!Number.isInteger(t)||t<0)throw new Error(`--port needs a non-negative integer (0 = OS-assigned ephemeral), got ${e}`);return t}function D(e){if(e[0]!=="--port")return null;let t=K(e[1]);return e.splice(0,2),t}function _(e){let t=e.indexOf("--port");if(t===-1)return L;let n=K(e[t+1]);return e.splice(t,2),n}function W(e){if(e===0)throw new Error("`env` cannot use --port 0: it starts no proxy, so the OS never assigns the ephemeral port \u2014 pass the actual port of the running proxy");return e}function U(e,t){let n=(e[t]??"").trim();if(!n)throw new Error(`${t} is not set. The proxy needs URUN_BASE_URL, URUN_ORG_ID, URUN_APP and either URUN_API_KEY (the org key; the proxy vends short-lived function-scoped client tokens from it via the SDK) or URUN_JWT (an explicit pre-vended token override) \u2014 plus optional URUN_FUNCTION, default "serve" \u2014 to open the backhaul session.`);return n}function h(e){let t=ie(U(e,"URUN_BASE_URL")),n=U(e,"URUN_ORG_ID"),r=U(e,"URUN_APP"),o=(e.URUN_FUNCTION??"serve").trim()||"serve",s=(e.URUN_API_URL??"").trim(),a=s?g(s,"URUN_API_URL"):A,i=(e.URUN_JWT??"").trim();if(i)return{baseUrl:t,orgId:n,appId:r,fnName:o,apiUrl:a,auth:{lane:"jwt",jwt:i}};let c=(e.URUN_API_KEY??"").trim();if(c){let l=(e.URUN_GATEWAY_URL??"").trim(),u=l?g(l):void 0;return{baseUrl:t,orgId:n,appId:r,fnName:o,apiUrl:a,auth:{lane:"api-key",apiKey:c,gatewayUrl:u}}}throw new Error("neither URUN_API_KEY nor URUN_JWT is set. Set URUN_API_KEY (the org API key \u2014 the proxy vends short-lived, function-scoped client tokens from it via the SDK, so the key never reaches the agent process) or URUN_JWT (an explicit pre-vended token; when set it always wins). URUN_BASE_URL, URUN_ORG_ID and URUN_APP are also required.")}function ie(e,t="URUN_BASE_URL"){if(/\/v1\/*$/.test(new URL(e).pathname))throw new Error(`${t} must be the session-gateway base (e.g. https://api.urun.sh), got ${e} \u2014 a trailing /v1 is the org control-plane API form (that belongs in URUN_API_URL); session allocation 404s against it. Drop the /v1.`);return e}function g(e,t="URUN_GATEWAY_URL"){let n=new URL(e),r=n.hostname==="localhost"||n.hostname==="127.0.0.1"||n.hostname==="[::1]";if(n.protocol!=="https:"&&!r)throw new Error(`${t} must be https (got ${e}) \u2014 the org API key rides the request's Authorization header`);return e}function P(e){return{app:e.appId,org:e.orgId,fn:e.fnName,base_url:e.baseUrl,proxy_version:se}}function ae(e,t){return e.app===t.app&&e.org===t.org&&e.fn===t.fn&&e.base_url===t.base_url&&e.proxy_version===t.proxy_version}var pe=250;async function R(e,t=pe){try{let n=await fetch(`http://127.0.0.1:${e}/stats`,{signal:AbortSignal.timeout(t)});if(!n.ok)return null;let r=(await n.json()).identity;if(r==null||typeof r!="object")return null;let{app:o,org:s,fn:a,base_url:i,proxy_version:c}=r;return typeof o!="string"||typeof s!="string"||typeof a!="string"||typeof i!="string"||typeof c!="string"?null:{app:o,org:s,fn:a,base_url:i,proxy_version:c}}catch{return null}}async function Y(e,t,n=L){if(e!=null)return{mode:"spawn",port:e};let r=await R(n);return r!==null&&ae(r,t)?{mode:"reuse",port:n,identity:r}:{mode:"spawn",port:0}}function J(e,t=te.homedir()){return ne.join(t,".urun","logs",`compat-proxy-${e}.log`)}var v=["log","info","warn","error","debug","trace"];function M(e,t=process,n=console){let r=t.stdout.write,o=t.stderr.write,s=(i,...c)=>e.write(i,...c);t.stdout.write=s,t.stderr.write=s;let a=Object.fromEntries(v.map(i=>[i,n[i]]));for(let i of v)n[i]=(...c)=>{e.write(`${oe(...c)}
3
+ `)};return()=>{t.stdout.write=r,t.stderr.write=o;for(let i of v)n[i]=a[i]}}function B(e,t){let n="pass --port 0 for an OS-assigned ephemeral port";return t?`port ${e} is held by another urun-openai proxy serving app ${t.app} (org ${t.org}, fn ${t.fn}, version ${t.proxy_version}) \u2014 reuse it by pointing your agent at http://127.0.0.1:${e}, or ${n}`:`port ${e} is already in use and does not answer the urun-openai /stats identity probe \u2014 ${n}`}function q(e,t,n){let r=e[n];if(typeof r!="function")throw new Error(`app "${t}" has no function "${n}" (set URUN_FUNCTION)`);let o=r();if(typeof o.end!="function")throw new Error(`app "${t}" function "${n}" returned a session without end()`);return o}function H(e,t){let{baseUrl:n,orgId:r,fnName:o,auth:s}=e;if(s.lane==="jwt"){let u=F(t,{baseUrl:n,orgId:r,jwt:s.jwt}),m=q(u,t,o);return{session:m,responses:new w(m)}}let{apiKey:a,gatewayUrl:i}=s,c=F(t,{baseUrl:n,orgId:r,getAccessToken:async()=>(await me(a,{baseUrl:i,expiresIn:300,allowedFunctions:[`${t}/${o}`]})).token}),l=q(c,t,o);return{session:l,responses:new w(l)}}function fe(e){let t=(p.env.URUN_CATALOG_URL??"").trim(),n=t?g(t,"URUN_CATALOG_URL"):"",r=(p.env.URUN_CATALOG_ANON_KEY??"").trim();(!n||!r)&&p.stderr.write(`urun compat: catalog oracle off (URUN_CATALOG_URL/URUN_CATALOG_ANON_KEY unset) \u2014 an undeployed uRun CATALOG model name falls through to the default app instead of a loud 404; deployed apps still resolve exactly, and /stats.models records every mapping
4
+ `);let o=e.auth,s=new O({defaultApp:e.appId,fnName:e.fnName,openSession:a=>H(e,a),closeSession:async a=>{await a.session.end()},listApps:o.lane==="api-key"?()=>I({apiUrl:e.apiUrl,apiKey:o.apiKey}):null,listCatalog:n&&r?()=>S({catalogUrl:n,anonKey:r}):null});return s.seed(e.appId,H(e,e.appId)),s}function ye(e){return{createResponse:async t=>{let{entry:n}=await e.sessionFor(t.model);return n.responses.responses.create(t)},listModels:()=>e.modelList()}}async function he(e,t,n){let r=V(e,t,{stdio:"inherit",env:n});return new Promise(o=>{r.once("exit",s=>o(s??1)),r.once("error",s=>{p.stderr.write(`failed to launch ${e}: ${String(s)}
5
+ `),o(127)})})}function ge(){return G(p.env,import.meta.url,ue)}function X(e){for(let[t,n]of Object.entries(E(e)))p.stdout.write(`export ${t}=${n}
6
+ `)}async function z(e,t){let n=h(p.env),r=t?P(n):void 0,o=fe(n),s=k({clients:ye(o),identity:r});try{await new Promise((i,c)=>{s.once("error",c),s.listen(e,"127.0.0.1",i)})}catch(i){throw await o.closeAll().catch(()=>{}),i.code==="EADDRINUSE"?new Error(B(e,await R(e))):i}let a=s.address().port;return t&&(p.stdout.write(`urun openai proxy listening on http://127.0.0.1:${a}/v1
7
+ `),X(a)),{port:a,close:async()=>{let i=new Promise(c=>s.close(()=>c()));s.closeAllConnections(),await i,await o.closeAll()}}}async function xe(){let e=p.argv.slice(2),t=D(e),n=e.shift()??"proxy";if(n==="env")return X(W(t??_(e))),0;if(n==="proxy"){let o=t??_(e),s=await z(o,!0);return await new Promise(a=>{p.once("SIGINT",a),p.once("SIGTERM",a)}),await s.close(),0}let r=n==="run"?e.shift():n;{if(!r)throw new Error(`launch needs an agent (${Object.keys(x).join("|")}) or \`-- <cmd>\``);if(r==="pi"){let d=h(p.env);return he("pi",["-e",ge(),...C(d.appId,e)],p.env)}let o,s,a="openai";if(r==="--"){if(o=e.shift()??"",s=e,!o)throw new Error("`-- <cmd>` needs a command to launch")}else{let d=x[r];if(!d)throw new Error(`unknown command/agent ${r}; commands: proxy | env; agents: ${Object.keys(x).join(" | ")} \u2014 or \`-- <cmd>\``);o=d.bin,s=[...d.args??[],...e],a=d.env}let i=await Y(t,P(h(p.env))),c=null,l=i.port;i.mode==="reuse"&&p.stdout.write(`reusing the running urun openai proxy on http://127.0.0.1:${l} (app ${i.identity.app}, fn ${i.identity.fn}, v${i.identity.proxy_version})
8
+ `);let u=null,m=null;if(i.mode!=="reuse"){c=await z(i.port,!1),l=c.port;let d=J(l);de(le.dirname(d),{recursive:!0}),m=ce(d,{flags:"a"}),m.on("error",y=>{u?.(),u=null,p.stderr.write(`urun compat: proxy log ${d} failed: ${String(y)} \u2014 proxy output continues on the terminal
9
+ `)}),p.stdout.write(`urun openai proxy on http://127.0.0.1:${l}/v1 \u2014 proxy logs: ${d}
10
+ `),u=M(m)}r==="codex"&&(s=j(l,h(p.env).appId,s));let b=V(o,s,{stdio:"inherit",env:T(p.env,l,a)}),N=await new Promise(d=>{b.once("exit",y=>d(y??1)),b.once("error",y=>{u?.(),u=null,p.stderr.write(`failed to launch ${o}: ${String(y)}
11
+ `),d(127)})}),f=null;try{c&&await c.close()}catch(d){f=d}finally{u?.(),u=null,m?.end()}return f!==null&&p.stderr.write(`urun compat: proxy teardown failed after the harness exited (harness exit code ${N} preserved): ${String(f instanceof Error?f.message:f)}
12
+ `),N}}xe().then(e=>p.exit(e),e=>{p.stderr.write(`${String(e instanceof Error?e.message:e)}
13
+ `),p.exit(1)});export{ye as buildClients,fe as buildRouter};
@@ -1,21 +1,21 @@
1
- "use strict";var O=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var F=(e,n)=>{for(var t in n)O(e,t,{get:n[t],enumerable:!0})},G=(e,n,t,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of D(n))!z.call(e,s)&&s!==t&&O(e,s,{get:()=>n[s],enumerable:!(r=q(n,s))||r.enumerable});return e};var L=e=>G(O({},"__esModule",{value:!0}),e);var st={};F(st,{createOpenAIProxy:()=>C});module.exports=L(st);var P=require("http"),b=class e{startedAt=Date.now();requests={};ttftMs=[];tokRates=[];tokensOut=0;charsOut=0;localInBytes=0;naiveInBytes=0;request(n,t,r){this.requests[n]=(this.requests[n]??0)+1,this.localInBytes+=t,this.naiveInBytes+=r}track(n){let t=this,r=performance.now(),s=null,c=0;return(async function*(){for await(let i of n)i.type==="response.output_text.delta"&&typeof i.delta=="string"&&(s===null&&(s=performance.now(),t.ttftMs.push(s-r),t.ttftMs.length>512&&t.ttftMs.shift()),c+=1,t.tokensOut+=1,t.charsOut+=i.delta.length),yield i;let o=(performance.now()-(s??r))/1e3;c>0&&o>0&&(t.tokRates.push(c/o),t.tokRates.length>512&&t.tokRates.shift())})()}static p50(n){if(!n.length)return null;let t=[...n].sort((r,s)=>r-s);return t[Math.floor(t.length/2)]}snapshot(){let n=Object.values(this.requests).reduce((t,r)=>t+r,0);return{uptime_s:Math.round((Date.now()-this.startedAt)/1e3),requests:this.requests,tokens_out:this.tokensOut,chars_out:this.charsOut,ttft_ms:{p50:e.p50(this.ttftMs),last:this.ttftMs.at(-1)??null},tok_per_s:{p50:e.p50(this.tokRates),last:this.tokRates.at(-1)??null},traffic:{local_request_bytes:this.localInBytes,naive_baseline:{request_bytes:this.naiveInBytes,connections:n},persistent_connections:1,history_bytes_saved:Math.max(0,this.naiveInBytes-this.localInBytes),history_bytes_saved_pct:this.naiveInBytes>0?Math.round((1-this.localInBytes/this.naiveInBytes)*1e3)/10:null}}}};function E(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function _(e,n,t){e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(t))}function f(e,n,t,r="invalid_request_error"){_(e,n,{error:{message:t,type:r}})}var M=64*1024*1024,R=class extends Error{};async function H(e){let n=[],t=0;for await(let s of e){if(t+=s.length,t>M)throw new R(`request body exceeds ${M} bytes`);n.push(s)}let r=Buffer.concat(n).toString("utf8");return r?JSON.parse(r):{}}function v(e,n,t,r){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:n,choices:[{index:0,delta:t,finish_reason:r}]}}var K=256;function X(e){if(typeof e=="string")return[{role:"user",content:e}];if(Array.isArray(e))return e;throw new Error("responses input must be a string or an array of messages/items")}var I=class{conversations=new Map;thread(n,t){let r=X(t);if(n==null)return r;let s=this.conversations.get(String(n));if(!s)throw new Error(`unknown previous_response_id ${String(n)} (proxy restarts drop stored responses)`);return[...s,...r]}remember(n,t,r){this.conversations.set(n,[...t,{role:"assistant",content:r}]);for(let s of this.conversations.keys()){if(this.conversations.size<=K)break;this.conversations.delete(s)}}};function T(e){let n=e?.output;return Array.isArray(n)?n.filter(t=>t.type==="function_call"):[]}function k(e){return e.find(n=>n.type==="response.completed")?.response??null}function Y(e){if(Array.isArray(e))return e.map(n=>{let t=n.function;return!t||typeof t!="object"?n:{type:"function",name:t.name,description:t.description,parameters:t.parameters,strict:t.strict}})}var x=class extends Error{};function Q(e,n){return Array.isArray(n)?n.map(t=>{let r=t;if(r.type==="text")return{type:e==="assistant"?"output_text":"input_text",text:r.text};if(r.type==="image_url"){let s=r.image_url??{};return{type:"input_image",image_url:s.url,detail:s.detail}}throw new x(`unsupported chat content part type "${String(r.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function U(e){let n=[];for(let t of e){if(t.role==="tool"){n.push({type:"function_call_output",call_id:t.tool_call_id,output:typeof t.content=="string"?t.content:JSON.stringify(t.content??"")});continue}if(t.role==="assistant"&&Array.isArray(t.tool_calls)){typeof t.content=="string"&&t.content&&n.push({role:"assistant",content:t.content});for(let r of t.tool_calls){let s=r.function??{};n.push({type:"function_call",call_id:r.id,name:s.name,arguments:s.arguments})}continue}n.push({...t,content:Q(t.role,t.content)})}return n}function N(e){return T(e).map((n,t)=>({index:t,id:n.call_id??n.id??`call_${t}`,type:"function",function:{name:n.name??"",arguments:n.arguments??"{}"}}))}function J(e,n){let t=n?.output_text;return typeof t=="string"?t:e.filter(r=>r.type==="response.output_text.delta"&&typeof r.delta=="string").map(r=>r.delta).join("")}async function V(e,n,t,r,s){let c=e.stream===!0,o;try{o=t.thread(e.previous_response_id,e.input)}catch(a){f(r,400,String(a instanceof Error?a.message:a));return}e.previous_response_id!=null&&(s.naiveInBytes+=Buffer.byteLength(JSON.stringify(o))-Buffer.byteLength(JSON.stringify(e.input)));let i=`resp_${Math.random().toString(36).slice(2,14)}`,d=e.store!==!1,l=await n.createResponse({model:e.model,input:o,stream:c,tools:e.tools,temperature:e.temperature,max_output_tokens:e.max_output_tokens}),p=[];if(c){E(r);for await(let a of s.track(l)){p.push(a);let u=a.response&&typeof a.response=="object"?{...a,response:{...a.response,id:i}}:a;r.write(`event: ${String(a.type??"message")}
2
- data: ${JSON.stringify(u)}
1
+ "use strict";var B=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var et=Object.prototype.hasOwnProperty;var nt=(e,n)=>{for(var t in n)B(e,t,{get:n[t],enumerable:!0})},st=(e,n,t,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of tt(n))!et.call(e,o)&&o!==t&&B(e,o,{get:()=>n[o],enumerable:!(s=Z(n,o))||s.enumerable});return e};var rt=e=>st(B({},"__esModule",{value:!0}),e);var kt={};nt(kt,{createOpenAIProxy:()=>W});module.exports=rt(kt);var H=require("http");var x=class extends Error{};var j=class e{startedAt=Date.now();requests={};models={};ttftMs=[];tokRates=[];tokensOut=0;charsOut=0;localInBytes=0;naiveInBytes=0;request(n,t,s){this.requests[n]=(this.requests[n]??0)+1,this.localInBytes+=t,this.naiveInBytes+=s}modelEntry(n){let t=this.models[n];if(t)return t;let s=Object.keys(this.models).length>=ot?"(other)":n;return this.models[s]??={requests:0,tokens_out:0}}model(n){this.modelEntry(n).requests+=1}track(n,t){let s=this,o=performance.now(),p=null,u=0;return(async function*(){for await(let l of n)l.type==="response.output_text.delta"&&typeof l.delta=="string"&&(p===null&&(p=performance.now(),s.ttftMs.push(p-o),s.ttftMs.length>512&&s.ttftMs.shift()),u+=1,s.tokensOut+=1,s.charsOut+=l.delta.length,t!==void 0&&(s.modelEntry(t).tokens_out+=1)),yield l;let i=(performance.now()-(p??o))/1e3;u>0&&i>0&&(s.tokRates.push(u/i),s.tokRates.length>512&&s.tokRates.shift())})()}static p50(n){if(!n.length)return null;let t=[...n].sort((s,o)=>s-o);return t[Math.floor(t.length/2)]}snapshot(){let n=Object.values(this.requests).reduce((t,s)=>t+s,0);return{uptime_s:Math.round((Date.now()-this.startedAt)/1e3),requests:this.requests,models:this.models,tokens_out:this.tokensOut,chars_out:this.charsOut,ttft_ms:{p50:e.p50(this.ttftMs),last:this.ttftMs.at(-1)??null},tok_per_s:{p50:e.p50(this.tokRates),last:this.tokRates.at(-1)??null},traffic:{local_request_bytes:this.localInBytes,naive_baseline:{request_bytes:this.naiveInBytes,connections:n},persistent_connections:1,history_bytes_saved:Math.max(0,this.naiveInBytes-this.localInBytes),history_bytes_saved_pct:this.naiveInBytes>0?Math.round((1-this.localInBytes/this.naiveInBytes)*1e3)/10:null}}}};function D(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function k(e,n,t){e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(t))}function h(e,n,t,s="invalid_request_error"){k(e,n,{error:{message:t,type:s}})}function q(e,n,t){if(n==="anthropic"){k(e,404,{type:"error",error:{type:"not_found_error",message:t.message}});return}k(e,404,{error:{message:t.message,type:"invalid_request_error",code:"model_not_found"}})}var ot=256,it=128;function L(e){return typeof e.model!="string"||!e.model.trim()?"(default)":e.model.trim().slice(0,it)}var F=64*1024*1024,N=class extends Error{};async function at(e){let n=[],t=0;for await(let o of e){if(t+=o.length,t>F)throw new N(`request body exceeds ${F} bytes`);n.push(o)}let s=Buffer.concat(n).toString("utf8");return s?JSON.parse(s):{}}function M(e,n,t,s){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:n,choices:[{index:0,delta:t,finish_reason:s}]}}var ut=256;function pt(e){if(typeof e=="string")return[{role:"user",content:e}];if(Array.isArray(e))return e;throw new Error("responses input must be a string or an array of messages/items")}var J=class{conversations=new Map;thread(n,t){let s=pt(t);if(n==null)return s;let o=this.conversations.get(String(n));if(!o)throw new Error(`unknown previous_response_id ${String(n)} (proxy restarts drop stored responses)`);return[...o,...s]}remember(n,t,s){this.conversations.set(n,[...t,{role:"assistant",content:s}]);for(let o of this.conversations.keys()){if(this.conversations.size<=ut)break;this.conversations.delete(o)}}};function K(e){let n=e?.output;return Array.isArray(n)?n.filter(t=>t.type==="function_call"):[]}function $(e){return e.find(n=>n.type==="response.completed")?.response??null}function lt(e){if(Array.isArray(e))return e.map(n=>{let t=n.function;return!t||typeof t!="object"?n:{type:"function",name:t.name,description:t.description,parameters:t.parameters,strict:t.strict}})}var T=class extends Error{};function ct(e,n){return Array.isArray(n)?n.map(t=>{let s=t;if(s.type==="text")return{type:e==="assistant"?"output_text":"input_text",text:s.text};if(s.type==="image_url"){let o=s.image_url??{};return{type:"input_image",image_url:o.url,detail:o.detail}}throw new T(`unsupported chat content part type "${String(s.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function dt(e){let n=[];for(let t of e){if(t.role==="tool"){n.push({type:"function_call_output",call_id:t.tool_call_id,output:typeof t.content=="string"?t.content:JSON.stringify(t.content??"")});continue}if(t.role==="assistant"&&Array.isArray(t.tool_calls)){typeof t.content=="string"&&t.content&&n.push({role:"assistant",content:t.content});for(let s of t.tool_calls){let o=s.function??{};n.push({type:"function_call",call_id:s.id,name:o.name,arguments:o.arguments})}continue}n.push({...t,content:ct(t.role,t.content)})}return n}function z(e){return K(e).map((n,t)=>({index:t,id:n.call_id??n.id??`call_${t}`,type:"function",function:{name:n.name??"",arguments:n.arguments??"{}"}}))}function X(e,n){let t=n?.output_text;return typeof t=="string"?t:e.filter(s=>s.type==="response.output_text.delta"&&typeof s.delta=="string").map(s=>s.delta).join("")}async function ft(e,n,t,s,o){let p=e.stream===!0,u;try{u=t.thread(e.previous_response_id,e.input)}catch(r){h(s,400,String(r instanceof Error?r.message:r));return}e.previous_response_id!=null&&(o.naiveInBytes+=Buffer.byteLength(JSON.stringify(u))-Buffer.byteLength(JSON.stringify(e.input)));let i=`resp_${Math.random().toString(36).slice(2,14)}`,l=e.store!==!1,y=L(e);o.model(y);let c;try{c=await n.createResponse({model:e.model,input:u,stream:p,tools:e.tools,temperature:e.temperature,max_output_tokens:e.max_output_tokens})}catch(r){if(r instanceof x){q(s,"openai",r);return}throw r}let g=[];if(p){D(s);let r=d=>{s.write(`event: ${String(d.type??"message")}
2
+ data: ${JSON.stringify(d)}
3
3
 
4
- `)}d&&t.remember(i,o,J(p,k(p))),r.write(`data: [DONE]
4
+ `)},a=d=>d.response&&typeof d.response=="object"?{...d,response:{...d.response,id:i}}:d,m=`item_${i.slice(5)}`,R=!1,v=!1,f=!1,S="",b=d=>{f&&(f=!1,r({type:"response.output_text.done",item_id:m,output_index:0,content_index:0,text:S}),r({type:"response.content_part.done",item_id:m,output_index:0,content_index:0,part:{type:"output_text",text:S}}),r({type:"response.output_item.done",output_index:0,item:{id:m,type:"message",role:"assistant",status:d,content:[{type:"output_text",text:S}]}}))};for await(let d of o.track(c,y)){g.push(d);let O=String(d.type??"");if(O==="response.created"||O==="response.in_progress"){R=!0,r(a(d));continue}if(O==="response.output_item.added"){v=!0,r(a(d));continue}if(O==="response.output_text.delta"&&!v){R||(R=!0,r({type:"response.created",response:{id:i,object:"response",status:"in_progress"}})),f||(f=!0,r({type:"response.output_item.added",output_index:0,item:{id:m,type:"message",role:"assistant",status:"in_progress",content:[]}}),r({type:"response.content_part.added",item_id:m,output_index:0,content_index:0,part:{type:"output_text",text:""}})),S+=String(d.delta??""),r({type:O,item_id:m,output_index:0,content_index:0,delta:d.delta});continue}if(O==="response.completed"&&!v){let Q=f;b("completed"),K(d.response).forEach((E,V)=>{let I=(Q?1:0)+V,P=E.id??E.call_id??`fc_${I}`,C=E.arguments??"",G={id:P,type:"function_call",call_id:E.call_id??P,name:E.name??""};r({type:"response.output_item.added",output_index:I,item:{...G,arguments:"",status:"in_progress"}}),r({type:"response.function_call_arguments.delta",item_id:P,output_index:I,delta:C}),r({type:"response.function_call_arguments.done",item_id:P,output_index:I,arguments:C}),r({type:"response.output_item.done",output_index:I,item:{...G,arguments:C,status:"completed"}})}),r(a(d));continue}r(a(d))}b("incomplete"),l&&t.remember(i,u,X(g,$(g))),s.write(`data: [DONE]
5
5
 
6
- `),r.end();return}let y=null;for await(let a of s.track(l)){if(p.push(a),a.type==="error"){f(r,502,JSON.stringify(a),"upstream_error");return}a.type==="response.completed"&&(y=a.response)}if(y==null){f(r,502,"upstream produced no response.completed event","upstream_error");return}let h=J(p,y);d&&t.remember(i,o,h),_(r,200,{...y,id:i})}async function W(e,n,t,r){let s=e.messages;if(!Array.isArray(s)){f(t,400,"chat/completions requires a messages array");return}let c=String(e.model??"urun"),o=`chatcmpl-${Math.random().toString(36).slice(2,14)}`,i;try{i=U(s)}catch(a){if(a instanceof x){f(t,400,a.message);return}throw a}let d=await n.createResponse({model:e.model,input:i,stream:!0,tools:Y(e.tools),temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens});if(e.stream===!0){E(t);let a=[];t.write(`data: ${JSON.stringify(v(o,c,{role:"assistant"},null))}
6
+ `),s.end();return}let _=null;for await(let r of o.track(c,y)){if(g.push(r),r.type==="error"){h(s,502,JSON.stringify(r),"upstream_error");return}r.type==="response.completed"&&(_=r.response)}if(_==null){h(s,502,"upstream produced no response.completed event","upstream_error");return}let w=X(g,_);l&&t.remember(i,u,w),k(s,200,{..._,id:i})}async function mt(e,n,t,s){let o=e.messages;if(!Array.isArray(o)){h(t,400,"chat/completions requires a messages array");return}let p=String(e.model??"urun"),u=`chatcmpl-${Math.random().toString(36).slice(2,14)}`,i;try{i=dt(o)}catch(r){if(r instanceof T){h(t,400,r.message);return}throw r}let l=L(e);s.model(l);let y;try{y=await n.createResponse({model:e.model,input:i,stream:!0,tools:lt(e.tools),temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens})}catch(r){if(r instanceof x){q(t,"openai",r);return}throw r}if(e.stream===!0){D(t);let r=[];t.write(`data: ${JSON.stringify(M(u,p,{role:"assistant"},null))}
7
7
 
8
- `);for await(let g of r.track(d))if(a.push(g),g.type==="response.output_text.delta"&&typeof g.delta=="string")t.write(`data: ${JSON.stringify(v(o,c,{content:g.delta},null))}
8
+ `);for await(let m of s.track(y,l))if(r.push(m),m.type==="response.output_text.delta"&&typeof m.delta=="string")t.write(`data: ${JSON.stringify(M(u,p,{content:m.delta},null))}
9
9
 
10
- `);else if(g.type==="error"){t.write(`data: ${JSON.stringify({error:g})}
10
+ `);else if(m.type==="error"){t.write(`data: ${JSON.stringify({error:m})}
11
11
 
12
- `),t.end();return}let u=N(k(a));u.length>0&&t.write(`data: ${JSON.stringify(v(o,c,{tool_calls:u},null))}
12
+ `),t.end();return}let a=z($(r));a.length>0&&t.write(`data: ${JSON.stringify(M(u,p,{tool_calls:a},null))}
13
13
 
14
- `),t.write(`data: ${JSON.stringify(v(o,c,{},u.length>0?"tool_calls":"stop"))}
14
+ `),t.write(`data: ${JSON.stringify(M(u,p,{},a.length>0?"tool_calls":"stop"))}
15
15
 
16
16
  `),t.write(`data: [DONE]
17
17
 
18
- `),t.end();return}let l="",p=[];for await(let a of r.track(d))if(p.push(a),a.type==="response.output_text.delta"&&typeof a.delta=="string"&&(l+=a.delta),a.type==="error"){f(t,502,JSON.stringify(a),"upstream_error");return}let y=N(k(p)).map(({index:a,...u})=>u),h={role:"assistant",content:l||null};y.length>0&&(h.tool_calls=y),_(t,200,{id:o,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:c,choices:[{index:0,message:h,finish_reason:y.length>0?"tool_calls":"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}function Z(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>n.type==="text").map(n=>String(n.text??"")).join(""):""}var w=class extends Error{constructor(n){super(`unsupported anthropic content block type "${n}" \u2014 the proxy translates text, tool_use and tool_result blocks`)}};function tt(e){if(Array.isArray(e))return e.map(n=>{let t=n;return{type:"function",name:t.name,description:t.description,parameters:t.input_schema}})}function et(e){if(typeof e=="string")return e;if(e==null)return"";if(!Array.isArray(e))throw new w(typeof e);let n="";for(let t of e){let r=String(t.type??"");if(r!=="text")throw new w(`tool_result > ${r}`);n+=String(t.text??"")}return n}function nt(e){let{role:n,content:t}=e;if(typeof t=="string")return[{role:n,content:t}];if(t==null)return[];if(!Array.isArray(t))throw new w(typeof t);let r=[],s="",c=()=>{s&&(r.push({role:n,content:s}),s="")};for(let o of t){let i=String(o.type??"");if(i==="text")s+=String(o.text??"");else if(i==="tool_use")c(),r.push({type:"function_call",call_id:o.id,name:o.name,arguments:JSON.stringify(o.input??{})});else if(i==="tool_result")c(),r.push({type:"function_call_output",call_id:o.tool_use_id,output:et(o.content)});else{if(i==="thinking"||i==="redacted_thinking")continue;throw new w(i)}}return c(),r}function $(e){return T(e).map((n,t)=>{let r;try{r=JSON.parse(n.arguments||"{}")}catch{throw new Error(`upstream function_call "${n.name??""}" arguments are not valid JSON`)}return{type:"tool_use",id:n.call_id??n.id??`toolu_${t}`,name:n.name??"",input:r}})}async function rt(e,n,t,r){let s=e.messages;if(!Array.isArray(s)){f(t,400,"messages requires a messages array");return}let c=String(e.model??"urun"),o=`msg_${Math.random().toString(36).slice(2,14)}`,i=[];try{e.system&&i.push({role:"system",content:Z(e.system)});for(let u of s)i.push(...nt(u))}catch(u){if(u instanceof w){f(t,400,u.message);return}throw u}let d=await n.createResponse({model:e.model,input:i,stream:!0,tools:tt(e.tools),temperature:e.temperature,max_output_tokens:e.max_tokens}),l=(u,g)=>{t.write(`event: ${u}
19
- data: ${JSON.stringify({type:u,...g})}
18
+ `),t.end();return}let c="",g=[];for await(let r of s.track(y,l))if(g.push(r),r.type==="response.output_text.delta"&&typeof r.delta=="string"&&(c+=r.delta),r.type==="error"){h(t,502,JSON.stringify(r),"upstream_error");return}let _=z($(g)).map(({index:r,...a})=>a),w={role:"assistant",content:c||null};_.length>0&&(w.tool_calls=_),k(t,200,{id:u,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:p,choices:[{index:0,message:w,finish_reason:_.length>0?"tool_calls":"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}function yt(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>n.type==="text").map(n=>String(n.text??"")).join(""):""}var A=class extends Error{constructor(n){super(`unsupported anthropic content block type "${n}" \u2014 the proxy translates text, tool_use and tool_result blocks`)}};function gt(e){if(Array.isArray(e))return e.map(n=>{let t=n;return{type:"function",name:t.name,description:t.description,parameters:t.input_schema}})}function ht(e){if(typeof e=="string")return e;if(e==null)return"";if(!Array.isArray(e))throw new A(typeof e);let n="";for(let t of e){let s=String(t.type??"");if(s!=="text")throw new A(`tool_result > ${s}`);n+=String(t.text??"")}return n}function _t(e){let{role:n,content:t}=e;if(typeof t=="string")return[{role:n,content:t}];if(t==null)return[];if(!Array.isArray(t))throw new A(typeof t);let s=[],o="",p=()=>{o&&(s.push({role:n,content:o}),o="")};for(let u of t){let i=String(u.type??"");if(i==="text")o+=String(u.text??"");else if(i==="tool_use")p(),s.push({type:"function_call",call_id:u.id,name:u.name,arguments:JSON.stringify(u.input??{})});else if(i==="tool_result")p(),s.push({type:"function_call_output",call_id:u.tool_use_id,output:ht(u.content)});else{if(i==="thinking"||i==="redacted_thinking")continue;throw new A(i)}}return p(),s}function Y(e){return K(e).map((n,t)=>{let s;try{s=JSON.parse(n.arguments||"{}")}catch{throw new Error(`upstream function_call "${n.name??""}" arguments are not valid JSON`)}return{type:"tool_use",id:n.call_id??n.id??`toolu_${t}`,name:n.name??"",input:s}})}async function wt(e,n,t,s){let o=e.messages;if(!Array.isArray(o)){h(t,400,"messages requires a messages array");return}let p=String(e.model??"urun"),u=`msg_${Math.random().toString(36).slice(2,14)}`,i=[];try{e.system&&i.push({role:"system",content:yt(e.system)});for(let a of o)i.push(..._t(a))}catch(a){if(a instanceof A){h(t,400,a.message);return}throw a}let l=L(e);s.model(l);let y;try{y=await n.createResponse({model:e.model,input:i,stream:!0,tools:gt(e.tools),temperature:e.temperature,max_output_tokens:e.max_tokens})}catch(a){if(a instanceof x){q(t,"anthropic",a);return}throw a}let c=(a,m)=>{t.write(`event: ${a}
19
+ data: ${JSON.stringify({type:a,...m})}
20
20
 
21
- `)};if(e.stream===!0){let u=r.track(d);E(t),l("message_start",{message:{id:o,type:"message",role:"assistant",content:[],model:c,stop_reason:null,usage:{input_tokens:0,output_tokens:0}}}),l("content_block_start",{index:0,content_block:{type:"text",text:""}});let g=0,B=[];for await(let m of u)if(B.push(m),m.type==="response.output_text.delta"&&typeof m.delta=="string")g+=1,l("content_block_delta",{index:0,delta:{type:"text_delta",text:m.delta}});else if(m.type==="error"){l("error",{error:{type:"api_error",message:JSON.stringify(m)}}),t.end();return}let A;try{A=$(k(B))}catch(m){l("error",{error:{type:"api_error",message:String(m instanceof Error?m.message:m)}}),t.end();return}l("content_block_stop",{index:0}),A.forEach((m,j)=>{let S=1+j;l("content_block_start",{index:S,content_block:{...m,input:{}}}),l("content_block_delta",{index:S,delta:{type:"input_json_delta",partial_json:JSON.stringify(m.input??{})}}),l("content_block_stop",{index:S})}),l("message_delta",{delta:{stop_reason:A.length>0?"tool_use":"end_turn"},usage:{output_tokens:g}}),l("message_stop",{}),t.end();return}let p="",y=[];for await(let u of r.track(d))if(y.push(u),u.type==="response.output_text.delta"&&typeof u.delta=="string"&&(p+=u.delta),u.type==="error"){f(t,502,JSON.stringify(u),"upstream_error");return}let h;try{h=$(k(y))}catch(u){f(t,502,String(u instanceof Error?u.message:u),"upstream_error");return}let a=[];(p||h.length===0)&&a.push({type:"text",text:p}),a.push(...h),_(t,200,{id:o,type:"message",role:"assistant",content:a,model:c,stop_reason:h.length>0?"tool_use":"end_turn",usage:{input_tokens:0,output_tokens:0}})}function C(e){let{clients:n,apiKey:t}=e,r=new I,s=new b;return(0,P.createServer)((c,o)=>{(async()=>{let i=new URL(c.url??"/","http://localhost");if(c.method==="GET"&&i.pathname==="/healthz"){_(o,200,{ok:!0});return}if(c.method==="GET"&&i.pathname==="/stats"){_(o,200,s.snapshot());return}if(t&&(c.headers.authorization??"")!==`Bearer ${t}`){f(o,401,"invalid local proxy api key","authentication_error");return}if(c.method==="GET"&&i.pathname==="/v1/models"){_(o,200,await n.listModels());return}if(c.method!=="POST"){f(o,404,`no route for ${c.method} ${i.pathname}`);return}let d;try{d=await H(c)}catch(p){if(p instanceof R){f(o,413,p.message,"request_too_large");return}f(o,400,"request body is not valid JSON");return}let l=Buffer.byteLength(JSON.stringify(d));if(i.pathname==="/v1/responses"){s.request("responses",l,l),await V(d,n,r,o,s);return}if(i.pathname==="/v1/chat/completions"){s.request("chat_completions",l,l),await W(d,n,o,s);return}if(i.pathname==="/v1/messages"){s.request("messages",l,l),await rt(d,n,o,s);return}f(o,404,`no route for POST ${i.pathname}`)})().catch(i=>{o.headersSent?o.end():f(o,500,String(i),"proxy_error")})})}0&&(module.exports={createOpenAIProxy});
21
+ `)};if(e.stream===!0){let a=s.track(y,l);D(t),c("message_start",{message:{id:u,type:"message",role:"assistant",content:[],model:p,stop_reason:null,usage:{input_tokens:0,output_tokens:0}}}),c("content_block_start",{index:0,content_block:{type:"text",text:""}});let m=0,R=[];for await(let f of a)if(R.push(f),f.type==="response.output_text.delta"&&typeof f.delta=="string")m+=1,c("content_block_delta",{index:0,delta:{type:"text_delta",text:f.delta}});else if(f.type==="error"){c("error",{error:{type:"api_error",message:JSON.stringify(f)}}),t.end();return}let v;try{v=Y($(R))}catch(f){c("error",{error:{type:"api_error",message:String(f instanceof Error?f.message:f)}}),t.end();return}c("content_block_stop",{index:0}),v.forEach((f,S)=>{let b=1+S;c("content_block_start",{index:b,content_block:{...f,input:{}}}),c("content_block_delta",{index:b,delta:{type:"input_json_delta",partial_json:JSON.stringify(f.input??{})}}),c("content_block_stop",{index:b})}),c("message_delta",{delta:{stop_reason:v.length>0?"tool_use":"end_turn"},usage:{output_tokens:m}}),c("message_stop",{}),t.end();return}let g="",_=[];for await(let a of s.track(y,l))if(_.push(a),a.type==="response.output_text.delta"&&typeof a.delta=="string"&&(g+=a.delta),a.type==="error"){h(t,502,JSON.stringify(a),"upstream_error");return}let w;try{w=Y($(_))}catch(a){h(t,502,String(a instanceof Error?a.message:a),"upstream_error");return}let r=[];(g||w.length===0)&&r.push({type:"text",text:g}),r.push(...w),k(t,200,{id:u,type:"message",role:"assistant",content:r,model:p,stop_reason:w.length>0?"tool_use":"end_turn",usage:{input_tokens:0,output_tokens:0}})}function W(e){let{clients:n,apiKey:t,identity:s}=e,o=new J,p=new j;return(0,H.createServer)((u,i)=>{(async()=>{let l=new URL(u.url??"/","http://localhost");if(u.method==="GET"&&l.pathname==="/healthz"){k(i,200,{ok:!0});return}if(u.method==="GET"&&l.pathname==="/stats"){k(i,200,s?{identity:s,...p.snapshot()}:p.snapshot());return}if(t&&(u.headers.authorization??"")!==`Bearer ${t}`){h(i,401,"invalid local proxy api key","authentication_error");return}if(u.method==="GET"&&l.pathname==="/v1/models"){k(i,200,await n.listModels());return}if(u.method!=="POST"){h(i,404,`no route for ${u.method} ${l.pathname}`);return}let y;try{y=await at(u)}catch(g){if(g instanceof N){h(i,413,g.message,"request_too_large");return}h(i,400,"request body is not valid JSON");return}let c=Buffer.byteLength(JSON.stringify(y));if(l.pathname==="/v1/responses"){p.request("responses",c,c),await ft(y,n,o,i,p);return}if(l.pathname==="/v1/chat/completions"){p.request("chat_completions",c,c),await mt(y,n,i,p);return}if(l.pathname==="/v1/messages"){p.request("messages",c,c),await wt(y,n,i,p);return}h(i,404,`no route for POST ${l.pathname}`)})().catch(l=>{i.headersSent?i.end():h(i,500,String(l),"proxy_error")})})}0&&(module.exports={createOpenAIProxy});
@@ -1,5 +1,27 @@
1
1
  import { Server } from 'node:http';
2
2
 
3
+ /**
4
+ * WHAT a proxy serves — the `identity` block on `GET /stats`. Reuse of a
5
+ * running proxy is allowed iff every field matches the launching invocation
6
+ * EXACTLY: a partial match (same app, different fn; same everything, older
7
+ * proxy_version) silently routes the agent at the wrong backend, which is
8
+ * worse than any error.
9
+ */
10
+ interface ProxyIdentity {
11
+ app: string;
12
+ org: string;
13
+ fn: string;
14
+ /**
15
+ * The control-plane URL the proxy's backhaul session opens against
16
+ * (URUN_BASE_URL verbatim — same org/app/fn on staging vs prod are
17
+ * DIFFERENT backends; review finding, #285). Compared exactly: a cosmetic
18
+ * difference (trailing slash) merely refuses reuse and spawns an ephemeral
19
+ * proxy — the safe direction.
20
+ */
21
+ base_url: string;
22
+ proxy_version: string;
23
+ }
24
+
3
25
  /**
4
26
  * The local OpenAI-compatible proxy — `npx @urun-sh/openai proxy`.
5
27
  *
@@ -37,8 +59,17 @@ interface OpenAIProxyOptions {
37
59
  clients: ProxyClients;
38
60
  /** Optional bearer the local agent must present (never forwarded upstream). */
39
61
  apiKey?: string;
62
+ /**
63
+ * WHAT this proxy serves (app/org/fn/base_url + proxy_version), surfaced as
64
+ * the `identity` block on `GET /stats` so a second `urun compat` invocation
65
+ * can reuse this proxy iff the identity matches its own exactly. Only the
66
+ * standalone `urun compat proxy` command sets it — a launch-mode proxy is
67
+ * child-owned (it dies with its child) and an embedder that omits it is
68
+ * simply never reused.
69
+ */
70
+ identity?: ProxyIdentity;
40
71
  }
41
72
  /** Build (not listen) the proxy server — the caller owns listen/close. */
42
73
  declare function createOpenAIProxy(options: OpenAIProxyOptions): Server;
43
74
 
44
- export { type OpenAIProxyOptions, type ProxyClients, createOpenAIProxy };
75
+ export { type OpenAIProxyOptions, type ProxyClients, type ProxyIdentity, createOpenAIProxy };
@@ -1,5 +1,14 @@
1
1
  import { Server } from 'node:http';
2
2
 
3
+ interface ProxyIdentity {
4
+ app: string;
5
+ org: string;
6
+ fn: string;
7
+
8
+ base_url: string;
9
+ proxy_version: string;
10
+ }
11
+
3
12
  interface ProxyClients {
4
13
 
5
14
  createResponse(params: {
@@ -17,8 +26,10 @@ interface OpenAIProxyOptions {
17
26
  clients: ProxyClients;
18
27
 
19
28
  apiKey?: string;
29
+
30
+ identity?: ProxyIdentity;
20
31
  }
21
32
 
22
33
  declare function createOpenAIProxy(options: OpenAIProxyOptions): Server;
23
34
 
24
- export { type OpenAIProxyOptions, type ProxyClients, createOpenAIProxy };
35
+ export { type OpenAIProxyOptions, type ProxyClients, type ProxyIdentity, createOpenAIProxy };
@@ -1 +1 @@
1
- import{a as e}from"../chunk-YDXG2QGW.js";export{e as createOpenAIProxy};
1
+ import{a as e}from"../chunk-KJ25VEMG.js";import"../chunk-PS4BLX7J.js";export{e as createOpenAIProxy};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@urun-sh/openai",
3
- "version": "0.2.50",
3
+ "version": "0.2.52",
4
4
  "description": "OpenAI-compatible Realtime + Responses SDK over uRun session primitives (not websockets).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -27,6 +27,16 @@
27
27
  "default": "./dist/proxy/index.cjs"
28
28
  }
29
29
  },
30
+ "./pi-extension": {
31
+ "import": {
32
+ "types": "./dist/pi-extension/index.d.ts",
33
+ "default": "./dist/pi-extension/index.js"
34
+ },
35
+ "require": {
36
+ "types": "./dist/pi-extension/index.d.cts",
37
+ "default": "./dist/pi-extension/index.cjs"
38
+ }
39
+ },
30
40
  "./package.json": "./package.json"
31
41
  },
32
42
  "files": [
@@ -34,13 +44,13 @@
34
44
  ],
35
45
  "scripts": {
36
46
  "build": "tsup && node ../../scripts/sanitize-dist.mjs .",
37
- "prepack": "pnpm build",
47
+ "prepack": "pnpm build && node scripts/assert-pack-contents.mjs",
38
48
  "test": "vitest run",
39
49
  "dev": "tsup --watch",
40
50
  "build:bin": "bun build --compile --external @roamhq/wrtc --external werift --external opusscript src/proxy/cli.ts --outfile dist/bin/urun-openai"
41
51
  },
42
52
  "peerDependencies": {
43
- "@urun-sh/core": "^0.2.50"
53
+ "@urun-sh/core": "^0.2.52"
44
54
  },
45
55
  "dependencies": {
46
56
  "openai": "4.104.0"
@@ -51,6 +61,7 @@
51
61
  "opusscript": "^0.1.1"
52
62
  },
53
63
  "devDependencies": {
64
+ "reflect-metadata": "^0.2.2",
54
65
  "tsup": "^8.5.0",
55
66
  "vitest": "^3.0.0",
56
67
  "werift": "^0.23.0",
@@ -1 +0,0 @@
1
- function u(e){if(e instanceof Error)return{type:"error",error:{type:"urun_error",code:e.name||null,message:e.message}};if(e&&typeof e=="object"&&e.t==="error"){let t=e,r=t.body??{};return{type:"error",error:{type:"urun_error",code:t.code??null,message:r.message??"unknown error"}}}return{type:"error",error:{type:"urun_error",code:null,message:String(e)}}}function p(e,t,r,n){let o=e.response??{},s={request_id:r,consumer_id:n,stream:!0,kind:"chat",messages:t};return typeof o.instructions=="string"&&(s.instructions=o.instructions),Array.isArray(o.modalities)&&(s.modalities=o.modalities),typeof o.temperature=="number"&&(s.temperature=o.temperature),typeof o.max_output_tokens=="number"&&(s.max_output_tokens=o.max_output_tokens),o.tools!==void 0&&(s.tools=o.tools),s}function m(e,t,r){let n={request_id:t,consumer_id:r,stream:!!e.stream,kind:"responses",input:e.input};return e.model&&(n.model=e.model),e.tools!==void 0&&(n.tools=e.tools),typeof e.temperature=="number"&&(n.temperature=e.temperature),typeof e.max_output_tokens=="number"&&(n.max_output_tokens=e.max_output_tokens),n}var l="llm-resp";async function*a(e,t){let r=`${l}:${t}`,n=`resp_${t}`;yield{type:"response.created",response:{id:n,status:"in_progress"}};for await(let o of e.stream(r).messages()){let s=o;if(s.t==="delta")yield{type:"response.output_text.delta",item_id:n,delta:s.delta};else if(s.t==="response"){yield{type:"response.completed",response:{id:n,status:"completed",...s.body}};return}else if(s.t==="error"){yield u(s);return}}}var g="llm",i=class{constructor(t){this.session=t}session;get consumerId(){return this.session.consumerId}write(t){this.session.doc(g).set({requests:{[t.request_id]:{payload:t,consumer_id:t.consumer_id,stream:t.stream}}})}sendResponses(t,r){let n=m(t,r,this.consumerId);return this.write(n),a(this.session,r)}sendResponseCreate(t,r,n){let o=p(t,r,n,this.consumerId);return this.write(o),a(this.session,n)}};var c=0;function y(){return c+=1,`req_${Date.now().toString(36)}_${c.toString(36)}`}var d=class{transport;constructor(t){this.transport=new i(t)}responses={create:async t=>{let r=y(),n=this.transport.sendResponses(t,r);return Object.assign((async function*(){yield*n})(),{requestId:r})}}};async function h(e){let r=await(e.fetchImpl??fetch)(`${e.catalogUrl}/model_catalog?select=model_id,variant`,{headers:{apikey:e.anonKey,Authorization:`Bearer ${e.anonKey}`}});if(!r.ok)throw new Error(`model_catalog fetch failed: ${r.status}`);return{object:"list",data:(await r.json()).map(o=>({id:`${o.model_id}:${o.variant}`,object:"model",created:0,owned_by:"urun"}))}}export{u as a,i as b,d as c,h as d};
@@ -1,21 +0,0 @@
1
- import{createServer as P}from"http";var O=class e{startedAt=Date.now();requests={};ttftMs=[];tokRates=[];tokensOut=0;charsOut=0;localInBytes=0;naiveInBytes=0;request(n,t,r){this.requests[n]=(this.requests[n]??0)+1,this.localInBytes+=t,this.naiveInBytes+=r}track(n){let t=this,r=performance.now(),s=null,c=0;return(async function*(){for await(let i of n)i.type==="response.output_text.delta"&&typeof i.delta=="string"&&(s===null&&(s=performance.now(),t.ttftMs.push(s-r),t.ttftMs.length>512&&t.ttftMs.shift()),c+=1,t.tokensOut+=1,t.charsOut+=i.delta.length),yield i;let o=(performance.now()-(s??r))/1e3;c>0&&o>0&&(t.tokRates.push(c/o),t.tokRates.length>512&&t.tokRates.shift())})()}static p50(n){if(!n.length)return null;let t=[...n].sort((r,s)=>r-s);return t[Math.floor(t.length/2)]}snapshot(){let n=Object.values(this.requests).reduce((t,r)=>t+r,0);return{uptime_s:Math.round((Date.now()-this.startedAt)/1e3),requests:this.requests,tokens_out:this.tokensOut,chars_out:this.charsOut,ttft_ms:{p50:e.p50(this.ttftMs),last:this.ttftMs.at(-1)??null},tok_per_s:{p50:e.p50(this.tokRates),last:this.tokRates.at(-1)??null},traffic:{local_request_bytes:this.localInBytes,naive_baseline:{request_bytes:this.naiveInBytes,connections:n},persistent_connections:1,history_bytes_saved:Math.max(0,this.naiveInBytes-this.localInBytes),history_bytes_saved_pct:this.naiveInBytes>0?Math.round((1-this.localInBytes/this.naiveInBytes)*1e3)/10:null}}}};function I(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function _(e,n,t){e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(t))}function f(e,n,t,r="invalid_request_error"){_(e,n,{error:{message:t,type:r}})}var B=64*1024*1024,R=class extends Error{};async function C(e){let n=[],t=0;for await(let s of e){if(t+=s.length,t>B)throw new R(`request body exceeds ${B} bytes`);n.push(s)}let r=Buffer.concat(n).toString("utf8");return r?JSON.parse(r):{}}function v(e,n,t,r){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:n,choices:[{index:0,delta:t,finish_reason:r}]}}var j=256;function q(e){if(typeof e=="string")return[{role:"user",content:e}];if(Array.isArray(e))return e;throw new Error("responses input must be a string or an array of messages/items")}var b=class{conversations=new Map;thread(n,t){let r=q(t);if(n==null)return r;let s=this.conversations.get(String(n));if(!s)throw new Error(`unknown previous_response_id ${String(n)} (proxy restarts drop stored responses)`);return[...s,...r]}remember(n,t,r){this.conversations.set(n,[...t,{role:"assistant",content:r}]);for(let s of this.conversations.keys()){if(this.conversations.size<=j)break;this.conversations.delete(s)}}};function $(e){let n=e?.output;return Array.isArray(n)?n.filter(t=>t.type==="function_call"):[]}function k(e){return e.find(n=>n.type==="response.completed")?.response??null}function D(e){if(Array.isArray(e))return e.map(n=>{let t=n.function;return!t||typeof t!="object"?n:{type:"function",name:t.name,description:t.description,parameters:t.parameters,strict:t.strict}})}var x=class extends Error{};function z(e,n){return Array.isArray(n)?n.map(t=>{let r=t;if(r.type==="text")return{type:e==="assistant"?"output_text":"input_text",text:r.text};if(r.type==="image_url"){let s=r.image_url??{};return{type:"input_image",image_url:s.url,detail:s.detail}}throw new x(`unsupported chat content part type "${String(r.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function F(e){let n=[];for(let t of e){if(t.role==="tool"){n.push({type:"function_call_output",call_id:t.tool_call_id,output:typeof t.content=="string"?t.content:JSON.stringify(t.content??"")});continue}if(t.role==="assistant"&&Array.isArray(t.tool_calls)){typeof t.content=="string"&&t.content&&n.push({role:"assistant",content:t.content});for(let r of t.tool_calls){let s=r.function??{};n.push({type:"function_call",call_id:r.id,name:s.name,arguments:s.arguments})}continue}n.push({...t,content:z(t.role,t.content)})}return n}function M(e){return $(e).map((n,t)=>({index:t,id:n.call_id??n.id??`call_${t}`,type:"function",function:{name:n.name??"",arguments:n.arguments??"{}"}}))}function N(e,n){let t=n?.output_text;return typeof t=="string"?t:e.filter(r=>r.type==="response.output_text.delta"&&typeof r.delta=="string").map(r=>r.delta).join("")}async function G(e,n,t,r,s){let c=e.stream===!0,o;try{o=t.thread(e.previous_response_id,e.input)}catch(a){f(r,400,String(a instanceof Error?a.message:a));return}e.previous_response_id!=null&&(s.naiveInBytes+=Buffer.byteLength(JSON.stringify(o))-Buffer.byteLength(JSON.stringify(e.input)));let i=`resp_${Math.random().toString(36).slice(2,14)}`,d=e.store!==!1,l=await n.createResponse({model:e.model,input:o,stream:c,tools:e.tools,temperature:e.temperature,max_output_tokens:e.max_output_tokens}),p=[];if(c){I(r);for await(let a of s.track(l)){p.push(a);let u=a.response&&typeof a.response=="object"?{...a,response:{...a.response,id:i}}:a;r.write(`event: ${String(a.type??"message")}
2
- data: ${JSON.stringify(u)}
3
-
4
- `)}d&&t.remember(i,o,N(p,k(p))),r.write(`data: [DONE]
5
-
6
- `),r.end();return}let g=null;for await(let a of s.track(l)){if(p.push(a),a.type==="error"){f(r,502,JSON.stringify(a),"upstream_error");return}a.type==="response.completed"&&(g=a.response)}if(g==null){f(r,502,"upstream produced no response.completed event","upstream_error");return}let h=N(p,g);d&&t.remember(i,o,h),_(r,200,{...g,id:i})}async function L(e,n,t,r){let s=e.messages;if(!Array.isArray(s)){f(t,400,"chat/completions requires a messages array");return}let c=String(e.model??"urun"),o=`chatcmpl-${Math.random().toString(36).slice(2,14)}`,i;try{i=F(s)}catch(a){if(a instanceof x){f(t,400,a.message);return}throw a}let d=await n.createResponse({model:e.model,input:i,stream:!0,tools:D(e.tools),temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens});if(e.stream===!0){I(t);let a=[];t.write(`data: ${JSON.stringify(v(o,c,{role:"assistant"},null))}
7
-
8
- `);for await(let y of r.track(d))if(a.push(y),y.type==="response.output_text.delta"&&typeof y.delta=="string")t.write(`data: ${JSON.stringify(v(o,c,{content:y.delta},null))}
9
-
10
- `);else if(y.type==="error"){t.write(`data: ${JSON.stringify({error:y})}
11
-
12
- `),t.end();return}let u=M(k(a));u.length>0&&t.write(`data: ${JSON.stringify(v(o,c,{tool_calls:u},null))}
13
-
14
- `),t.write(`data: ${JSON.stringify(v(o,c,{},u.length>0?"tool_calls":"stop"))}
15
-
16
- `),t.write(`data: [DONE]
17
-
18
- `),t.end();return}let l="",p=[];for await(let a of r.track(d))if(p.push(a),a.type==="response.output_text.delta"&&typeof a.delta=="string"&&(l+=a.delta),a.type==="error"){f(t,502,JSON.stringify(a),"upstream_error");return}let g=M(k(p)).map(({index:a,...u})=>u),h={role:"assistant",content:l||null};g.length>0&&(h.tool_calls=g),_(t,200,{id:o,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:c,choices:[{index:0,message:h,finish_reason:g.length>0?"tool_calls":"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}function H(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>n.type==="text").map(n=>String(n.text??"")).join(""):""}var w=class extends Error{constructor(n){super(`unsupported anthropic content block type "${n}" \u2014 the proxy translates text, tool_use and tool_result blocks`)}};function K(e){if(Array.isArray(e))return e.map(n=>{let t=n;return{type:"function",name:t.name,description:t.description,parameters:t.input_schema}})}function X(e){if(typeof e=="string")return e;if(e==null)return"";if(!Array.isArray(e))throw new w(typeof e);let n="";for(let t of e){let r=String(t.type??"");if(r!=="text")throw new w(`tool_result > ${r}`);n+=String(t.text??"")}return n}function Y(e){let{role:n,content:t}=e;if(typeof t=="string")return[{role:n,content:t}];if(t==null)return[];if(!Array.isArray(t))throw new w(typeof t);let r=[],s="",c=()=>{s&&(r.push({role:n,content:s}),s="")};for(let o of t){let i=String(o.type??"");if(i==="text")s+=String(o.text??"");else if(i==="tool_use")c(),r.push({type:"function_call",call_id:o.id,name:o.name,arguments:JSON.stringify(o.input??{})});else if(i==="tool_result")c(),r.push({type:"function_call_output",call_id:o.tool_use_id,output:X(o.content)});else{if(i==="thinking"||i==="redacted_thinking")continue;throw new w(i)}}return c(),r}function J(e){return $(e).map((n,t)=>{let r;try{r=JSON.parse(n.arguments||"{}")}catch{throw new Error(`upstream function_call "${n.name??""}" arguments are not valid JSON`)}return{type:"tool_use",id:n.call_id??n.id??`toolu_${t}`,name:n.name??"",input:r}})}async function Q(e,n,t,r){let s=e.messages;if(!Array.isArray(s)){f(t,400,"messages requires a messages array");return}let c=String(e.model??"urun"),o=`msg_${Math.random().toString(36).slice(2,14)}`,i=[];try{e.system&&i.push({role:"system",content:H(e.system)});for(let u of s)i.push(...Y(u))}catch(u){if(u instanceof w){f(t,400,u.message);return}throw u}let d=await n.createResponse({model:e.model,input:i,stream:!0,tools:K(e.tools),temperature:e.temperature,max_output_tokens:e.max_tokens}),l=(u,y)=>{t.write(`event: ${u}
19
- data: ${JSON.stringify({type:u,...y})}
20
-
21
- `)};if(e.stream===!0){let u=r.track(d);I(t),l("message_start",{message:{id:o,type:"message",role:"assistant",content:[],model:c,stop_reason:null,usage:{input_tokens:0,output_tokens:0}}}),l("content_block_start",{index:0,content_block:{type:"text",text:""}});let y=0,E=[];for await(let m of u)if(E.push(m),m.type==="response.output_text.delta"&&typeof m.delta=="string")y+=1,l("content_block_delta",{index:0,delta:{type:"text_delta",text:m.delta}});else if(m.type==="error"){l("error",{error:{type:"api_error",message:JSON.stringify(m)}}),t.end();return}let A;try{A=J(k(E))}catch(m){l("error",{error:{type:"api_error",message:String(m instanceof Error?m.message:m)}}),t.end();return}l("content_block_stop",{index:0}),A.forEach((m,T)=>{let S=1+T;l("content_block_start",{index:S,content_block:{...m,input:{}}}),l("content_block_delta",{index:S,delta:{type:"input_json_delta",partial_json:JSON.stringify(m.input??{})}}),l("content_block_stop",{index:S})}),l("message_delta",{delta:{stop_reason:A.length>0?"tool_use":"end_turn"},usage:{output_tokens:y}}),l("message_stop",{}),t.end();return}let p="",g=[];for await(let u of r.track(d))if(g.push(u),u.type==="response.output_text.delta"&&typeof u.delta=="string"&&(p+=u.delta),u.type==="error"){f(t,502,JSON.stringify(u),"upstream_error");return}let h;try{h=J(k(g))}catch(u){f(t,502,String(u instanceof Error?u.message:u),"upstream_error");return}let a=[];(p||h.length===0)&&a.push({type:"text",text:p}),a.push(...h),_(t,200,{id:o,type:"message",role:"assistant",content:a,model:c,stop_reason:h.length>0?"tool_use":"end_turn",usage:{input_tokens:0,output_tokens:0}})}function V(e){let{clients:n,apiKey:t}=e,r=new b,s=new O;return P((c,o)=>{(async()=>{let i=new URL(c.url??"/","http://localhost");if(c.method==="GET"&&i.pathname==="/healthz"){_(o,200,{ok:!0});return}if(c.method==="GET"&&i.pathname==="/stats"){_(o,200,s.snapshot());return}if(t&&(c.headers.authorization??"")!==`Bearer ${t}`){f(o,401,"invalid local proxy api key","authentication_error");return}if(c.method==="GET"&&i.pathname==="/v1/models"){_(o,200,await n.listModels());return}if(c.method!=="POST"){f(o,404,`no route for ${c.method} ${i.pathname}`);return}let d;try{d=await C(c)}catch(p){if(p instanceof R){f(o,413,p.message,"request_too_large");return}f(o,400,"request body is not valid JSON");return}let l=Buffer.byteLength(JSON.stringify(d));if(i.pathname==="/v1/responses"){s.request("responses",l,l),await G(d,n,r,o,s);return}if(i.pathname==="/v1/chat/completions"){s.request("chat_completions",l,l),await L(d,n,o,s);return}if(i.pathname==="/v1/messages"){s.request("messages",l,l),await Q(d,n,o,s);return}f(o,404,`no route for POST ${i.pathname}`)})().catch(i=>{o.headersSent?o.end():f(o,500,String(i),"proxy_error")})})}export{V as a};