@urun-sh/openai 0.2.46 → 0.2.48

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.
@@ -0,0 +1 @@
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};
@@ -0,0 +1,21 @@
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};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- function v(n,e,t,r){let o=n.response??{},s={request_id:t,consumer_id:r,stream:!0,kind:"chat",messages:e};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 g(n,e,t){let r={request_id:e,consumer_id:t,stream:!!n.stream,kind:"responses",input:n.input};return n.model&&(r.model=n.model),n.tools!==void 0&&(r.tools=n.tools),typeof n.temperature=="number"&&(r.temperature=n.temperature),typeof n.max_output_tokens=="number"&&(r.max_output_tokens=n.max_output_tokens),r}function p(n){if(n instanceof Error)return{type:"error",error:{type:"urun_error",code:n.name||null,message:n.message}};if(n&&typeof n=="object"&&n.t==="error"){let e=n,t=e.body??{};return{type:"error",error:{type:"urun_error",code:e.code??null,message:t.message??"unknown error"}}}return{type:"error",error:{type:"urun_error",code:null,message:String(n)}}}var I="llm-resp";async function*k(n,e){let t=`${I}:${e}`,r=`resp_${e}`;yield{type:"response.created",response:{id:r,status:"in_progress"}};for await(let o of n.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 p(s);return}}}var T="llm",d=class{constructor(e){this.session=e}session;get consumerId(){return this.session.consumerId}write(e){this.session.doc(T).set({requests:{[e.request_id]:{payload:e,consumer_id:e.consumer_id,stream:e.stream}}})}sendResponses(e,t){let r=g(e,t,this.consumerId);return this.write(r),k(this.session,t)}sendResponseCreate(e,t,r){let o=v(e,t,r,this.consumerId);return this.write(o),k(this.session,r)}};var m=class{constructor(e,t){this.backend=e;this.opts=t}backend;opts;source=null;sink=null;outHandlers=new Set;async startOutbound(){return this.source=this.backend.createSource(),this.source.track}appendInputAudio(e){if(!this.source)throw new Error("startOutbound() not called");let t=Buffer.from(e,"base64"),r=Math.floor(t.byteLength/2),o=new Int16Array(r);for(let s=0;s<r;s++)o[s]=t.readInt16LE(s*2);this.source.onData(o)}async startInbound(e){if(e==null)throw new Error('startInbound: no downstream audio track \u2014 the runtime audio producer has not been consumed yet (session.stream("rt-audio-out").track is null)');this.sink=this.backend.createSink(e),this.sink.onframe=t=>{let r=Buffer.from(t.samples.buffer,t.samples.byteOffset,t.samples.byteLength).toString("base64");for(let o of this.outHandlers)o(r)}}onOutputAudio(e){return this.outHandlers.add(e),()=>this.outHandlers.delete(e)}},L=24e3,l=480,P=111;async function O(){let n=await import("opusscript"),e=n.default??n;return new e(L,1,2048)}async function B(){let n=await import("werift"),e=await O();return{createSource:()=>{let t=new n.MediaStreamTrack({kind:"audio"}),r=Math.random()*4294967295>>>0,o=Math.random()*65535&65535,s=Math.random()*4294967295>>>0,i=new Int16Array(0);return{track:t,onData:u=>{let a=new Int16Array(i.length+u.length);a.set(i,0),a.set(u,i.length);let c=0;for(;a.length-c>=l;){let f=a.subarray(c,c+l);c+=l;let E=Buffer.from(f.buffer,f.byteOffset,f.byteLength),A=e.encode(E,l);o=o+1&65535,s=s+l>>>0;let R=new n.RtpHeader({version:2,payloadType:P,sequenceNumber:o,timestamp:s,ssrc:r,marker:!1}),x=new n.RtpPacket(R,A);t.writeRtp(x)}i=a.slice(c)}}},createSink:t=>{let r={onframe:null};return t.onReceiveRtp.subscribe(s=>{let i;try{i=e.decode(s.payload)}catch{return}let u=new Int16Array(i.length/2);for(let a=0;a<u.length;a++)u[a]=i.readInt16LE(a*2);r.onframe?.({samples:u})}),r}}}async function M(){let n=await import("@roamhq/wrtc");return{createSource:()=>{let e=new n.nonstandard.RTCAudioSource;return{track:e.createTrack(),onData:r=>e.onData({samples:r,sampleRate:24e3})}},createSink:e=>{let t={onframe:null},r=new n.nonstandard.RTCAudioSink(e);return r.ondata=o=>{t.onframe?.(o)},t}}}var h=0;function C(){return h+=1,`rt_${Date.now().toString(36)}_${h.toString(36)}`}var y=class{constructor(e,t={}){this.session=e;this.opts=t;this.transport=new d(e)}session;opts;transport;handlers=new Set;conversation=[];active=null;audio=null;currentRequestId=null;async enableAudio(){if(!this.opts.audioBackend)throw new Error("audioBackend required for audio");this.audio=new m(this.opts.audioBackend,{sampleRate:24e3});let e=await this.audio.startOutbound();await this.session.stream("rt-audio-in").attach(e),this.audio.onOutputAudio(r=>this.emit({type:"response.audio.delta",delta:r}));let t=await this.awaitDownstreamAudioTrack();await this.audio.startInbound(t)}awaitDownstreamAudioTrack(e=1e4){let t=this.session.stream("rt-audio-out");return t.track!=null?Promise.resolve(t.track):new Promise((r,o)=>{let s,i=setTimeout(()=>{s?.(),o(new Error(`enableAudio: no downstream audio track within ${e}ms (runtime produced no voice OUT / SFU audio consumer never attached)`))},e),u=a=>{a!=null&&(clearTimeout(i),s?.(),r(a))};s=t.on?.("track",u),t.track!=null&&u(t.track)})}on(e,t){return this.handlers.add(t),()=>this.handlers.delete(t)}emit(e){for(let t of this.handlers)t(e)}send(e){switch(e.type){case"conversation.item.create":{let t=(e.item?.content??[]).map(r=>r.text??"").join("");this.conversation.push({role:e.item?.role??"user",content:t});return}case"response.create":{let t=C();this.currentRequestId=t;let r=this.transport.sendResponseCreate({type:"response.create",response:e.response},this.conversation,t);this.active=(async()=>{try{for await(let o of r)this.emit(o)}catch(o){this.emit(p(o))}})();return}case"input_audio_buffer.append":this.audio?.appendInputAudio(e.audio);return;case"input_audio_buffer.commit":case"input_audio_buffer.clear":return;case"response.cancel":return;default:return}}async drain(){this.active&&await this.active}};var S=0;function U(){return S+=1,`req_${Date.now().toString(36)}_${S.toString(36)}`}var w=class{transport;constructor(e){this.transport=new d(e)}responses={create:async e=>{let t=U(),r=this.transport.sendResponses(e,t);return Object.assign((async function*(){yield*r})(),{requestId:t})}}};async function D(n){let t=await(n.fetchImpl??fetch)(`${n.catalogUrl}/model_catalog?select=model_id,variant`,{headers:{apikey:n.anonKey,Authorization:`Bearer ${n.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 _=["session.update","conversation.item.create","response.create","response.cancel","input_audio_buffer.append","input_audio_buffer.commit","input_audio_buffer.clear"],b=["response.created","response.output_text.delta","response.output_item.added","response.function_call_arguments.delta","response.image_generation_call.partial_image","response.completed","error"];function q(n){return _.includes(n)}function $(n){return b.includes(n)}export{_ as SUPPORTED_REALTIME_CLIENT_EVENTS,b as SUPPORTED_RESPONSES_EVENTS,y as UrunRealtime,w as UrunResponses,q as isSupportedClientEvent,$ as isSupportedResponsesEvent,D as listModels,M as nodeAudioBackend,p as toErrorEvent,B as weriftAudioBackend};
1
+ import{a as f,b as k,c as b,d as R}from"./chunk-GUQC3NSG.js";var p=class{constructor(t,e){this.backend=t;this.opts=e}backend;opts;source=null;sink=null;outHandlers=new Set;async startOutbound(){return this.source=this.backend.createSource(),this.source.track}appendInputAudio(t){if(!this.source)throw new Error("startOutbound() not called");let e=Buffer.from(t,"base64"),n=Math.floor(e.byteLength/2),r=new Int16Array(n);for(let a=0;a<n;a++)r[a]=e.readInt16LE(a*2);this.source.onData(r)}async startInbound(t){if(t==null)throw new Error('startInbound: no downstream audio track \u2014 the runtime audio producer has not been consumed yet (session.stream("rt-audio-out").track is null)');this.sink=this.backend.createSink(t),this.sink.onframe=e=>{let n=Buffer.from(e.samples.buffer,e.samples.byteOffset,e.samples.byteLength).toString("base64");for(let r of this.outHandlers)r(n)}}onOutputAudio(t){return this.outHandlers.add(t),()=>this.outHandlers.delete(t)}},g=24e3,c=480,_=111;async function T(){let o=await import("opusscript"),t=o.default??o;return new t(g,1,2048)}async function x(){let o=await import("werift"),t=await T();return{createSource:()=>{let e=new o.MediaStreamTrack({kind:"audio"}),n=Math.random()*4294967295>>>0,r=Math.random()*65535&65535,a=Math.random()*4294967295>>>0,i=new Int16Array(0);return{track:e,onData:u=>{let s=new Int16Array(i.length+u.length);s.set(i,0),s.set(u,i.length);let d=0;for(;s.length-d>=c;){let l=s.subarray(d,d+c);d+=c;let S=Buffer.from(l.buffer,l.byteOffset,l.byteLength),y=t.encode(S,c);r=r+1&65535,a=a+c>>>0;let A=new o.RtpHeader({version:2,payloadType:_,sequenceNumber:r,timestamp:a,ssrc:n,marker:!1}),E=new o.RtpPacket(A,y);e.writeRtp(E)}i=s.slice(d)}}},createSink:e=>{let n={onframe:null};return e.onReceiveRtp.subscribe(a=>{let i;try{i=t.decode(a.payload)}catch{return}let u=new Int16Array(i.length/2);for(let s=0;s<u.length;s++)u[s]=i.readInt16LE(s*2);n.onframe?.({samples:u})}),n}}}async function I(){let o=await import("@roamhq/wrtc");return{createSource:()=>{let t=new o.nonstandard.RTCAudioSource;return{track:t.createTrack(),onData:n=>t.onData({samples:n,sampleRate:24e3})}},createSink:t=>{let e={onframe:null},n=new o.nonstandard.RTCAudioSink(t);return n.ondata=r=>{e.onframe?.(r)},e}}}var w=0;function P(){return w+=1,`rt_${Date.now().toString(36)}_${w.toString(36)}`}var m=class{constructor(t,e={}){this.session=t;this.opts=e;this.transport=new k(t)}session;opts;transport;handlers=new Set;conversation=[];active=null;audio=null;currentRequestId=null;async enableAudio(){if(!this.opts.audioBackend)throw new Error("audioBackend required for audio");this.audio=new p(this.opts.audioBackend,{sampleRate:24e3});let t=await this.audio.startOutbound();await this.session.stream("rt-audio-in").attach(t),this.audio.onOutputAudio(n=>this.emit({type:"response.audio.delta",delta:n}));let e=await this.awaitDownstreamAudioTrack();await this.audio.startInbound(e)}awaitDownstreamAudioTrack(t=1e4){let e=this.session.stream("rt-audio-out");return e.track!=null?Promise.resolve(e.track):new Promise((n,r)=>{let a,i=setTimeout(()=>{a?.(),r(new Error(`enableAudio: no downstream audio track within ${t}ms (runtime produced no voice OUT / SFU audio consumer never attached)`))},t),u=s=>{s!=null&&(clearTimeout(i),a?.(),n(s))};a=e.on?.("track",u),e.track!=null&&u(e.track)})}on(t,e){return this.handlers.add(e),()=>this.handlers.delete(e)}emit(t){for(let e of this.handlers)e(t)}send(t){switch(t.type){case"conversation.item.create":{let e=(t.item?.content??[]).map(n=>n.text??"").join("");this.conversation.push({role:t.item?.role??"user",content:e});return}case"response.create":{let e=P();this.currentRequestId=e;let n=this.transport.sendResponseCreate({type:"response.create",response:t.response},this.conversation,e);this.active=(async()=>{try{for await(let r of n)this.emit(r)}catch(r){this.emit(f(r))}})();return}case"input_audio_buffer.append":this.audio?.appendInputAudio(t.audio);return;case"input_audio_buffer.commit":case"input_audio_buffer.clear":return;case"response.cancel":return;default:return}}async drain(){this.active&&await this.active}};var v=["session.update","conversation.item.create","response.create","response.cancel","input_audio_buffer.append","input_audio_buffer.commit","input_audio_buffer.clear"],h=["response.created","response.output_text.delta","response.output_item.added","response.function_call_arguments.delta","response.image_generation_call.partial_image","response.completed","error"];function B(o){return v.includes(o)}function O(o){return h.includes(o)}export{v as SUPPORTED_REALTIME_CLIENT_EVENTS,h as SUPPORTED_RESPONSES_EVENTS,m as UrunRealtime,b as UrunResponses,B as isSupportedClientEvent,O as isSupportedResponsesEvent,R as listModels,I as nodeAudioBackend,f as toErrorEvent,x as weriftAudioBackend};
@@ -0,0 +1,26 @@
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})},j=(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)):{},j(n||!e||!e.__esModule?x(t,"default",{value:e,enumerable:!0}):t,e)),_e=e=>j(x({},"__esModule",{value:!0}),e);var Me={};ge(Me,{buildClients:()=>ae,resolveSessionFromEnv:()=>ie});module.exports=_e(Me);var se=require("child_process"),m=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 G(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",A=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=G(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 K=0;function ke(){return K+=1,`req_${Date.now().toString(36)}_${K.toString(36)}`}var S=class{transport;constructor(n){this.transport=new A(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 L(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 g(e,n,t,r="invalid_request_error"){w(e,n,{error:{message:t,type:r}})}var Y=64*1024*1024,E=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 E(`request body exceeds ${Y} bytes`);n.push(o)}let r=Buffer.concat(n).toString("utf8");return r?JSON.parse(r):{}}function b(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 Ae(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 O=class extends Error{};function Se(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 O(`unsupported chat content part type "${String(r.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function be(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:Se(t.role,t.content)})}return n}function z(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 W(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 Ee(e,n,t,r,o){let s=e.stream===!0,i;try{i=t.thread(e.previous_response_id,e.input)}catch(u){g(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)}`,f=e.store!==!1,c=await n.createResponse({model:e.model,input:i,stream:s,tools:e.tools,temperature:e.temperature,max_output_tokens:e.max_output_tokens}),l=[];if(s){L(r);for await(let u of o.track(c)){l.push(u);let p=u.response&&typeof u.response=="object"?{...u,response:{...u.response,id:a}}:u;r.write(`event: ${String(u.type??"message")}
3
+ data: ${JSON.stringify(p)}
4
+
5
+ `)}f&&t.remember(a,i,W(l,v(l))),r.write(`data: [DONE]
6
+
7
+ `),r.end();return}let d=null;for await(let u of o.track(c)){if(l.push(u),u.type==="error"){g(r,502,JSON.stringify(u),"upstream_error");return}u.type==="response.completed"&&(d=u.response)}if(d==null){g(r,502,"upstream produced no response.completed event","upstream_error");return}let y=W(l,d);f&&t.remember(a,i,y),w(r,200,{...d,id:a})}async function Oe(e,n,t,r){let o=e.messages;if(!Array.isArray(o)){g(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=be(o)}catch(u){if(u instanceof O){g(t,400,u.message);return}throw u}let f=await n.createResponse({model:e.model,input:a,stream:!0,tools:Ae(e.tools),temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens});if(e.stream===!0){L(t);let u=[];t.write(`data: ${JSON.stringify(b(i,s,{role:"assistant"},null))}
8
+
9
+ `);for await(let h of r.track(f))if(u.push(h),h.type==="response.output_text.delta"&&typeof h.delta=="string")t.write(`data: ${JSON.stringify(b(i,s,{content:h.delta},null))}
10
+
11
+ `);else if(h.type==="error"){t.write(`data: ${JSON.stringify({error:h})}
12
+
13
+ `),t.end();return}let p=z(v(u));p.length>0&&t.write(`data: ${JSON.stringify(b(i,s,{tool_calls:p},null))}
14
+
15
+ `),t.write(`data: ${JSON.stringify(b(i,s,{},p.length>0?"tool_calls":"stop"))}
16
+
17
+ `),t.write(`data: [DONE]
18
+
19
+ `),t.end();return}let c="",l=[];for await(let u of r.track(f))if(l.push(u),u.type==="response.output_text.delta"&&typeof u.delta=="string"&&(c+=u.delta),u.type==="error"){g(t,502,JSON.stringify(u),"upstream_error");return}let d=z(v(l)).map(({index:u,...p})=>p),y={role:"assistant",content:c||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 Ue(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 Ie(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)){g(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:Ue(e.system)});for(let p of o)a.push(...Pe(p))}catch(p){if(p instanceof k){g(t,400,p.message);return}throw p}let f=await n.createResponse({model:e.model,input:a,stream:!0,tools:Ie(e.tools),temperature:e.temperature,max_output_tokens:e.max_tokens}),c=(p,h)=>{t.write(`event: ${p}
20
+ data: ${JSON.stringify({type:p,...h})}
21
+
22
+ `)};if(e.stream===!0){let p=r.track(f);L(t),c("message_start",{message:{id:i,type:"message",role:"assistant",content:[],model:s,stop_reason:null,usage:{input_tokens:0,output_tokens:0}}}),c("content_block_start",{index:0,content_block:{type:"text",text:""}});let h=0,J=[];for await(let _ of p)if(J.push(_),_.type==="response.output_text.delta"&&typeof _.delta=="string")h+=1,c("content_block_delta",{index:0,delta:{type:"text_delta",text:_.delta}});else if(_.type==="error"){c("error",{error:{type:"api_error",message:JSON.stringify(_)}}),t.end();return}let I;try{I=H(v(J))}catch(_){c("error",{error:{type:"api_error",message:String(_ instanceof Error?_.message:_)}}),t.end();return}c("content_block_stop",{index:0}),I.forEach((_,ce)=>{let N=1+ce;c("content_block_start",{index:N,content_block:{..._,input:{}}}),c("content_block_delta",{index:N,delta:{type:"input_json_delta",partial_json:JSON.stringify(_.input??{})}}),c("content_block_stop",{index:N})}),c("message_delta",{delta:{stop_reason:I.length>0?"tool_use":"end_turn"},usage:{output_tokens:h}}),c("message_stop",{}),t.end();return}let l="",d=[];for await(let p of r.track(f))if(d.push(p),p.type==="response.output_text.delta"&&typeof p.delta=="string"&&(l+=p.delta),p.type==="error"){g(t,502,JSON.stringify(p),"upstream_error");return}let y;try{y=H(v(d))}catch(p){g(t,502,String(p instanceof Error?p.message:p),"upstream_error");return}let u=[];(l||y.length===0)&&u.push({type:"text",text:l}),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}`){g(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"){g(i,404,`no route for ${s.method} ${a.pathname}`);return}let f;try{f=await ve(s)}catch(l){if(l instanceof E){g(i,413,l.message,"request_too_large");return}g(i,400,"request body is not valid JSON");return}let c=Buffer.byteLength(JSON.stringify(f));if(a.pathname==="/v1/responses"){o.request("responses",c,c),await Ee(f,n,r,i,o);return}if(a.pathname==="/v1/chat/completions"){o.request("chat_completions",c,c),await Oe(f,n,i,o);return}if(a.pathname==="/v1/messages"){o.request("messages",c,c),await $e(f,n,i,o);return}g(i,404,`no route for POST ${a.pathname}`)})().catch(a=>{i.headersSent?i.end():g(i,500,String(a),"proxy_error")})})}var U={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 M(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,...M(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 ne(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 B(e){let n=(m.default.env[e]??"").trim();if(!n)throw new Error(`${e} is not set. The proxy needs URUN_BASE_URL, URUN_ORG_ID, URUN_APP and URUN_JWT (plus optional URUN_FUNCTION, default "serve") to open the backhaul session.`);return n}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 e=B("URUN_BASE_URL"),n=B("URUN_APP"),t=(m.default.env.URUN_FUNCTION??"serve").trim()||"serve",r=(m.default.env.URUN_API_KEY??"").trim(),o=(m.default.env.URUN_JWT??"").trim();if(!r&&!o)throw new Error("set URUN_API_KEY (the org API key \u2014 the CLI vends short-lived, function-scoped client tokens from it via the gateway) or URUN_JWT (an explicit pre-vended token). URUN_BASE_URL and URUN_APP are also required.");if(r){let a=(m.default.env.URUN_GATEWAY_URL??"").trim(),f=a?ne(a):void 0,c=(m.default.env.URUN_ORG_ID??"").trim(),l=(0,R.App)(n,{baseUrl:e,orgId:c,getAccessToken:async()=>(await(0,R.createClientToken)(r,{baseUrl:f,expiresIn:300,allowedFunctions:[`${n}/${t}`]})).token});return re(l,n,t)}let s=B("URUN_ORG_ID"),i=(0,R.App)(n,{baseUrl:e,orgId:s,jwt:o});return re(i,n,t)}function ae(e){let n=new S(e);return{createResponse:t=>n.responses.create(t),listModels:async()=>{let t=(m.default.env.URUN_CATALOG_URL??"").trim(),r=(m.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(M(e)))m.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)}),m.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=m.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=>{m.default.once("SIGINT",i),m.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(U).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=U[r];if(!d)throw new Error(`unknown command/agent ${r}; commands: proxy | env; agents: ${Object.keys(U).join(" | ")} \u2014 or \`-- <cmd>\``);s=d.bin,i=[...d.args??[],...e],a=d.env}let f=await oe(o),c=(0,se.spawn)(s,i,{stdio:"inherit",env:Z(m.default.env,o,a)}),l=await new Promise(d=>{c.once("exit",y=>d(y??1)),c.once("error",y=>{m.default.stderr.write(`failed to launch ${s}: ${String(y)}
25
+ `),d(127)})});return await f.close(),l}}Le().then(e=>m.default.exit(e),e=>{m.default.stderr.write(`${String(e instanceof Error?e.message:e)}
26
+ `),m.default.exit(1)});0&&(module.exports={buildClients,resolveSessionFromEnv});
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import{c as _,d as g}from"../chunk-GUQC3NSG.js";import{a as E}from"../chunk-YDXG2QGW.js";import{spawn as I}from"child_process";import r from"process";import{App as P,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 v(n,e="openai"){if(e==="anthropic")return{ANTHROPIC_BASE_URL:`http://127.0.0.1:${n}`,ANTHROPIC_API_KEY:"urun-local"};let t=`http://127.0.0.1:${n}/v1`;return{OPENAI_BASE_URL:t,OPENAI_API_BASE:t,OPENAI_API_KEY:"urun-local"}}function h(n,e,t){let o={...n,...v(e,t)};return delete o.URUN_API_KEY,delete o.URUN_JWT,o}function R(n){let e=Number(n);if(!Number.isInteger(e)||e<=0)throw new Error(`--port needs a positive integer, got ${n}`);return e}function y(n){if(n[0]!=="--port")return null;let e=R(n[1]);return n.splice(0,2),e}function w(n){let e=n.indexOf("--port");if(e===-1)return 4141;let t=R(n[e+1]);return n.splice(e,2),t}function N(n){let e=new URL(n),t=e.hostname==="localhost"||e.hostname==="127.0.0.1"||e.hostname==="[::1]";if(e.protocol!=="https:"&&!t)throw new Error(`URUN_GATEWAY_URL must be https (got ${n}) \u2014 the org API key rides the mint call's Authorization header`);return n}function f(n){let e=(r.env[n]??"").trim();if(!e)throw new Error(`${n} is not set. The proxy needs URUN_BASE_URL, URUN_ORG_ID, URUN_APP and URUN_JWT (plus optional URUN_FUNCTION, default "serve") to open the backhaul session.`);return e}function A(n,e,t){let o=n[t];if(typeof o!="function")throw new Error(`app "${e}" has no function "${t}" (set URUN_FUNCTION)`);let s=o();if(typeof s.end!="function")throw new Error(`app "${e}" function "${t}" returned a session without end()`);return s}function T(){let n=f("URUN_BASE_URL"),e=f("URUN_APP"),t=(r.env.URUN_FUNCTION??"serve").trim()||"serve",o=(r.env.URUN_API_KEY??"").trim(),s=(r.env.URUN_JWT??"").trim();if(!o&&!s)throw new Error("set URUN_API_KEY (the org API key \u2014 the CLI vends short-lived, function-scoped client tokens from it via the gateway) or URUN_JWT (an explicit pre-vended token). URUN_BASE_URL and URUN_APP are also required.");if(o){let u=(r.env.URUN_GATEWAY_URL??"").trim(),l=u?N(u):void 0,p=(r.env.URUN_ORG_ID??"").trim(),U=P(e,{baseUrl:n,orgId:p,getAccessToken:async()=>(await O(o,{baseUrl:l,expiresIn:300,allowedFunctions:[`${e}/${t}`]})).token});return A(U,e,t)}let i=f("URUN_ORG_ID"),c=P(e,{baseUrl:n,orgId:i,jwt:s});return A(c,e,t)}function k(n){let e=new _(n);return{createResponse:t=>e.responses.create(t),listModels:async()=>{let t=(r.env.URUN_CATALOG_URL??"").trim(),o=(r.env.URUN_CATALOG_ANON_KEY??"").trim();return!t||!o?{object:"list",data:[{id:"urun",object:"model",owned_by:"urun"}]}:g({catalogUrl:t,anonKey:o})}}}function x(n){for(let[e,t]of Object.entries(v(n)))r.stdout.write(`export ${e}=${t}
3
+ `)}async function b(n){let e=T(),t=E({clients:k(e)});return await new Promise((o,s)=>{t.once("error",s),t.listen(n,"127.0.0.1",o)}),r.stdout.write(`urun openai proxy listening on http://127.0.0.1:${n}/v1
4
+ `),x(n),{close:async()=>{let o=new Promise(s=>t.close(()=>s()));t.closeAllConnections(),await o,await e.end()}}}async function L(){let n=r.argv.slice(2),e=y(n),t=n.shift()??"proxy";if(t==="env")return x(e??w(n)),0;if(t==="proxy"){let s=e??w(n),i=await b(s);return await new Promise(c=>{r.once("SIGINT",c),r.once("SIGTERM",c)}),await i.close(),0}let o=t==="run"?n.shift():t;{if(!o)throw new Error(`launch needs an agent (${Object.keys(d).join("|")}) or \`-- <cmd>\``);let s=e??4141,i,c,u="openai";if(o==="--"){if(i=n.shift()??"",c=n,!i)throw new Error("`-- <cmd>` needs a command to launch")}else{let a=d[o];if(!a)throw new Error(`unknown command/agent ${o}; commands: proxy | env; agents: ${Object.keys(d).join(" | ")} \u2014 or \`-- <cmd>\``);i=a.bin,c=[...a.args??[],...n],u=a.env}let l=await b(s),p=I(i,c,{stdio:"inherit",env:h(r.env,s,u)}),U=await new Promise(a=>{p.once("exit",m=>a(m??1)),p.once("error",m=>{r.stderr.write(`failed to launch ${i}: ${String(m)}
5
+ `),a(127)})});return await l.close(),U}}L().then(n=>r.exit(n),n=>{r.stderr.write(`${String(n instanceof Error?n.message:n)}
6
+ `),r.exit(1)});export{k as buildClients,T as resolveSessionFromEnv};
@@ -0,0 +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)}
3
+
4
+ `)}d&&t.remember(i,o,J(p,k(p))),r.write(`data: [DONE]
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))}
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))}
9
+
10
+ `);else if(g.type==="error"){t.write(`data: ${JSON.stringify({error:g})}
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))}
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 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})}
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});
@@ -0,0 +1,44 @@
1
+ import { Server } from 'node:http';
2
+
3
+ /**
4
+ * The local OpenAI-compatible proxy — `npx @urun-sh/openai proxy`.
5
+ *
6
+ * A loopback HTTP server speaking the OpenAI REST surface (`/v1/models`,
7
+ * `/v1/responses`, `/v1/chat/completions`, SSE streaming included), so any
8
+ * OpenAI-env-var tool — coding agents first — integrates with uRun with ZERO
9
+ * code changes: point `OPENAI_BASE_URL` at it and keep making plain, local,
10
+ * "inefficient" HTTP requests. The proxy backhauls each request over the uRun
11
+ * session transport (the `@urun-sh/openai` Responses client → session doc
12
+ * lanes + streams — no public OpenAI-style HTTP leaves the machine), which is
13
+ * also where the delta-sync chat-state doc lane (urun-python
14
+ * `urun/serve/chat_state.py`) plugs in as the transport evolves.
15
+ *
16
+ * Local-trust model: binds 127.0.0.1 by default; `apiKey` (when set) must
17
+ * match the agent's `Authorization: Bearer` — otherwise any local bearer is
18
+ * accepted (the key the agent sends is NEVER forwarded upstream; uRun auth is
19
+ * the session's own).
20
+ */
21
+
22
+ /** The upstream calls the proxy makes — injectable (tests; alt transports). */
23
+ interface ProxyClients {
24
+ /** `UrunResponses(session).responses.create` — an async iterable of Responses stream events. */
25
+ createResponse(params: {
26
+ model?: string;
27
+ input: unknown;
28
+ stream?: boolean;
29
+ tools?: unknown;
30
+ temperature?: number;
31
+ max_output_tokens?: number;
32
+ }): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
33
+ /** `listModels(...)` result (an OpenAI model list object). */
34
+ listModels(): Promise<unknown>;
35
+ }
36
+ interface OpenAIProxyOptions {
37
+ clients: ProxyClients;
38
+ /** Optional bearer the local agent must present (never forwarded upstream). */
39
+ apiKey?: string;
40
+ }
41
+ /** Build (not listen) the proxy server — the caller owns listen/close. */
42
+ declare function createOpenAIProxy(options: OpenAIProxyOptions): Server;
43
+
44
+ export { type OpenAIProxyOptions, type ProxyClients, createOpenAIProxy };
@@ -0,0 +1,24 @@
1
+ import { Server } from 'node:http';
2
+
3
+ interface ProxyClients {
4
+
5
+ createResponse(params: {
6
+ model?: string;
7
+ input: unknown;
8
+ stream?: boolean;
9
+ tools?: unknown;
10
+ temperature?: number;
11
+ max_output_tokens?: number;
12
+ }): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
13
+
14
+ listModels(): Promise<unknown>;
15
+ }
16
+ interface OpenAIProxyOptions {
17
+ clients: ProxyClients;
18
+
19
+ apiKey?: string;
20
+ }
21
+
22
+ declare function createOpenAIProxy(options: OpenAIProxyOptions): Server;
23
+
24
+ export { type OpenAIProxyOptions, type ProxyClients, createOpenAIProxy };
@@ -0,0 +1 @@
1
+ import{a as e}from"../chunk-YDXG2QGW.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.46",
3
+ "version": "0.2.48",
4
4
  "description": "OpenAI-compatible Realtime + Responses SDK over uRun session primitives (not websockets).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -17,6 +17,16 @@
17
17
  "default": "./dist/index.cjs"
18
18
  }
19
19
  },
20
+ "./proxy": {
21
+ "import": {
22
+ "types": "./dist/proxy/index.d.ts",
23
+ "default": "./dist/proxy/index.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/proxy/index.d.cts",
27
+ "default": "./dist/proxy/index.cjs"
28
+ }
29
+ },
20
30
  "./package.json": "./package.json"
21
31
  },
22
32
  "files": [
@@ -26,10 +36,11 @@
26
36
  "build": "tsup && node ../../scripts/sanitize-dist.mjs .",
27
37
  "prepack": "pnpm build",
28
38
  "test": "vitest run",
29
- "dev": "tsup --watch"
39
+ "dev": "tsup --watch",
40
+ "build:bin": "bun build --compile --external @roamhq/wrtc --external werift --external opusscript src/proxy/cli.ts --outfile dist/bin/urun-openai"
30
41
  },
31
42
  "peerDependencies": {
32
- "@urun-sh/core": "^0.2.2"
43
+ "@urun-sh/core": "^0.2.48"
33
44
  },
34
45
  "dependencies": {
35
46
  "openai": "4.104.0"
@@ -51,5 +62,8 @@
51
62
  },
52
63
  "publishConfig": {
53
64
  "access": "public"
65
+ },
66
+ "bin": {
67
+ "urun-openai": "./dist/proxy/cli.cjs"
54
68
  }
55
- }
69
+ }