@urun-sh/openai 0.2.49 → 0.2.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ResponsesClient-CQ3l8Wft.d.cts +62 -0
- package/dist/ResponsesClient-CQ3l8Wft.d.ts +56 -0
- package/dist/chunk-FSS2A7IU.js +1 -0
- package/dist/chunk-KJ25VEMG.js +21 -0
- package/dist/chunk-OLE2YJO3.js +1 -0
- package/dist/chunk-PS4BLX7J.js +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +6 -64
- package/dist/index.d.ts +6 -57
- package/dist/index.js +1 -1
- package/dist/pi-extension/index.cjs +3 -0
- package/dist/pi-extension/index.d.cts +189 -0
- package/dist/pi-extension/index.d.ts +70 -0
- package/dist/pi-extension/index.js +3 -0
- package/dist/proxy/cli.cjs +21 -15
- package/dist/proxy/cli.js +11 -5
- package/dist/proxy/index.cjs +11 -11
- package/dist/proxy/index.d.cts +32 -1
- package/dist/proxy/index.d.ts +12 -1
- package/dist/proxy/index.js +1 -1
- package/package.json +12 -2
- package/dist/chunk-GUQC3NSG.js +0 -1
- package/dist/chunk-YDXG2QGW.js +0 -21
package/dist/proxy/index.cjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
data: ${JSON.stringify(
|
|
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&&
|
|
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
|
-
`),
|
|
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
|
|
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(
|
|
10
|
+
`);else if(m.type==="error"){t.write(`data: ${JSON.stringify({error:m})}
|
|
11
11
|
|
|
12
|
-
`),t.end();return}let
|
|
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(
|
|
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
|
|
19
|
-
data: ${JSON.stringify({type:
|
|
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
|
|
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});
|
package/dist/proxy/index.d.cts
CHANGED
|
@@ -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 };
|
package/dist/proxy/index.d.ts
CHANGED
|
@@ -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 };
|
package/dist/proxy/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e}from"../chunk-
|
|
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.
|
|
3
|
+
"version": "0.2.51",
|
|
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": [
|
|
@@ -40,7 +50,7 @@
|
|
|
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.
|
|
53
|
+
"@urun-sh/core": "^0.2.51"
|
|
44
54
|
},
|
|
45
55
|
"dependencies": {
|
|
46
56
|
"openai": "4.104.0"
|
package/dist/chunk-GUQC3NSG.js
DELETED
|
@@ -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};
|
package/dist/chunk-YDXG2QGW.js
DELETED
|
@@ -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};
|