@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.
@@ -0,0 +1,62 @@
1
+ /** The narrow subset of @urun-sh/core's Session the SDK depends on. */
2
+ interface UrunDocLike {
3
+ set(patch: Record<string, unknown>): void;
4
+ get(path?: string, defaultValue?: unknown): unknown;
5
+ on(event: 'change', handler: (snapshot: Record<string, unknown>) => void): () => void;
6
+ }
7
+ interface UrunStreamLike {
8
+ messages(): AsyncIterable<unknown>;
9
+ attach(track: unknown): Promise<void>;
10
+ detach(): Promise<void>;
11
+ readonly track: unknown;
12
+ /**
13
+ * Subscribe to the named media track (de)appearing. The downstream audio track
14
+ * is consumed ASYNCHRONOUSLY after the WebRTC handshake, so `track` may be null
15
+ * at `enableAudio()` time; this fires with the real `MediaStreamTrack` the
16
+ * moment the consumer attaches (core `SessionStream.on('track')`). Optional so
17
+ * non-media test doubles need not implement it.
18
+ */
19
+ on?(event: 'track', handler: (track: unknown) => void): () => void;
20
+ }
21
+ interface UrunSessionLike {
22
+ /** Per-leg consumer identity (core: transport.consumerId). */
23
+ readonly consumerId: string;
24
+ doc(key: string): UrunDocLike;
25
+ stream(name: string): UrunStreamLike;
26
+ close?(): Promise<void> | void;
27
+ }
28
+ /** Lane message shape emitted by the serve runtime (core session.ts:83). */
29
+ type LaneMessage = {
30
+ t: 'delta';
31
+ request_id?: string;
32
+ delta: string;
33
+ } | {
34
+ t: 'response';
35
+ request_id?: string;
36
+ body: unknown;
37
+ } | {
38
+ t: 'error';
39
+ request_id?: string;
40
+ body: unknown;
41
+ code?: string;
42
+ };
43
+
44
+ interface ResponsesStream extends AsyncIterable<unknown> {
45
+ readonly requestId: string;
46
+ }
47
+ declare class UrunResponses {
48
+ private readonly transport;
49
+ constructor(session: UrunSessionLike);
50
+ readonly responses: {
51
+ create: (params: {
52
+ model?: string;
53
+ input: unknown;
54
+ stream?: boolean;
55
+ tools?: unknown;
56
+ temperature?: number;
57
+ max_output_tokens?: number;
58
+ }) => Promise<ResponsesStream>;
59
+ };
60
+ }
61
+
62
+ export { type LaneMessage as L, UrunResponses as U, type UrunSessionLike as a };
@@ -0,0 +1,56 @@
1
+
2
+ interface UrunDocLike {
3
+ set(patch: Record<string, unknown>): void;
4
+ get(path?: string, defaultValue?: unknown): unknown;
5
+ on(event: 'change', handler: (snapshot: Record<string, unknown>) => void): () => void;
6
+ }
7
+ interface UrunStreamLike {
8
+ messages(): AsyncIterable<unknown>;
9
+ attach(track: unknown): Promise<void>;
10
+ detach(): Promise<void>;
11
+ readonly track: unknown;
12
+
13
+ on?(event: 'track', handler: (track: unknown) => void): () => void;
14
+ }
15
+ interface UrunSessionLike {
16
+
17
+ readonly consumerId: string;
18
+ doc(key: string): UrunDocLike;
19
+ stream(name: string): UrunStreamLike;
20
+ close?(): Promise<void> | void;
21
+ }
22
+
23
+ type LaneMessage = {
24
+ t: 'delta';
25
+ request_id?: string;
26
+ delta: string;
27
+ } | {
28
+ t: 'response';
29
+ request_id?: string;
30
+ body: unknown;
31
+ } | {
32
+ t: 'error';
33
+ request_id?: string;
34
+ body: unknown;
35
+ code?: string;
36
+ };
37
+
38
+ interface ResponsesStream extends AsyncIterable<unknown> {
39
+ readonly requestId: string;
40
+ }
41
+ declare class UrunResponses {
42
+ private readonly transport;
43
+ constructor(session: UrunSessionLike);
44
+ readonly responses: {
45
+ create: (params: {
46
+ model?: string;
47
+ input: unknown;
48
+ stream?: boolean;
49
+ tools?: unknown;
50
+ temperature?: number;
51
+ max_output_tokens?: number;
52
+ }) => Promise<ResponsesStream>;
53
+ };
54
+ }
55
+
56
+ export { type LaneMessage as L, UrunResponses as U, type UrunSessionLike as a };
@@ -0,0 +1 @@
1
+ function m(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)}}}function c(e,n,t,r){let s=e.response??{},o={request_id:t,consumer_id:r,stream:!0,kind:"chat",messages:n};return typeof s.instructions=="string"&&(o.instructions=s.instructions),Array.isArray(s.modalities)&&(o.modalities=s.modalities),typeof s.temperature=="number"&&(o.temperature=s.temperature),typeof s.max_output_tokens=="number"&&(o.max_output_tokens=s.max_output_tokens),s.tools!==void 0&&(o.tools=s.tools),o}function d(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}var g="llm-resp";async function*a(e,n){let t=`${g}:${n}`,r=`resp_${n}`;yield{type:"response.created",response:{id:r,status:"in_progress"}};for await(let s of e.stream(t).messages()){let o=s;if(o.t==="delta")yield{type:"response.output_text.delta",item_id:r,delta:o.delta};else if(o.t==="response"){yield{type:"response.completed",response:{id:r,status:"completed",...o.body}};return}else if(o.t==="error"){yield m(o);return}}}var _="llm",p=class{constructor(n){this.session=n}session;get consumerId(){return this.session.consumerId}write(n){this.session.doc(_).set({requests:{[n.request_id]:{payload:n,consumer_id:n.consumer_id,stream:n.stream}}})}sendResponses(n,t){let r=d(n,t,this.consumerId);return this.write(r),a(this.session,t)}sendResponseCreate(n,t,r){let s=c(n,t,r,this.consumerId);return this.write(s),a(this.session,r)}};var l=0;function k(){return l+=1,`req_${Date.now().toString(36)}_${l.toString(36)}`}var y=class{transport;constructor(n){this.transport=new p(n)}responses={create:async n=>{let t=k(),r=this.transport.sendResponses(n,t);return Object.assign((async function*(){yield*r})(),{requestId:t})}}};export{m as a,p as b,y as c};
@@ -0,0 +1,21 @@
1
+ import{b as I}from"./chunk-PS4BLX7J.js";import{createServer as H}from"http";var T=class e{startedAt=Date.now();requests={};models={};ttftMs=[];tokRates=[];tokensOut=0;charsOut=0;localInBytes=0;naiveInBytes=0;request(n,t,r){this.requests[n]=(this.requests[n]??0)+1,this.localInBytes+=t,this.naiveInBytes+=r}modelEntry(n){let t=this.models[n];if(t)return t;let r=Object.keys(this.models).length>=Q?"(other)":n;return this.models[r]??={requests:0,tokens_out:0}}model(n){this.modelEntry(n).requests+=1}track(n,t){let r=this,i=performance.now(),c=null,u=0;return(async function*(){for await(let p of n)p.type==="response.output_text.delta"&&typeof p.delta=="string"&&(c===null&&(c=performance.now(),r.ttftMs.push(c-i),r.ttftMs.length>512&&r.ttftMs.shift()),u+=1,r.tokensOut+=1,r.charsOut+=p.delta.length,t!==void 0&&(r.modelEntry(t).tokens_out+=1)),yield p;let o=(performance.now()-(c??i))/1e3;u>0&&o>0&&(r.tokRates.push(u/o),r.tokRates.length>512&&r.tokRates.shift())})()}static p50(n){if(!n.length)return null;let t=[...n].sort((r,i)=>r-i);return t[Math.floor(t.length/2)]}snapshot(){let n=Object.values(this.requests).reduce((t,r)=>t+r,0);return{uptime_s:Math.round((Date.now()-this.startedAt)/1e3),requests:this.requests,models:this.models,tokens_out:this.tokensOut,chars_out:this.charsOut,ttft_ms:{p50:e.p50(this.ttftMs),last:this.ttftMs.at(-1)??null},tok_per_s:{p50:e.p50(this.tokRates),last:this.tokRates.at(-1)??null},traffic:{local_request_bytes:this.localInBytes,naive_baseline:{request_bytes:this.naiveInBytes,connections:n},persistent_connections:1,history_bytes_saved:Math.max(0,this.naiveInBytes-this.localInBytes),history_bytes_saved_pct:this.naiveInBytes>0?Math.round((1-this.localInBytes/this.naiveInBytes)*1e3)/10:null}}}};function C(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 _(e,n,t,r="invalid_request_error"){w(e,n,{error:{message:t,type:r}})}function j(e,n,t){if(n==="anthropic"){w(e,404,{type:"error",error:{type:"not_found_error",message:t.message}});return}w(e,404,{error:{message:t.message,type:"invalid_request_error",code:"model_not_found"}})}var Q=256,V=128;function D(e){return typeof e.model!="string"||!e.model.trim()?"(default)":e.model.trim().slice(0,V)}var z=64*1024*1024,B=class extends Error{};async function W(e){let n=[],t=0;for await(let i of e){if(t+=i.length,t>z)throw new B(`request body exceeds ${z} bytes`);n.push(i)}let r=Buffer.concat(n).toString("utf8");return r?JSON.parse(r):{}}function $(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 Z=256;function tt(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 q=class{conversations=new Map;thread(n,t){let r=tt(t);if(n==null)return r;let i=this.conversations.get(String(n));if(!i)throw new Error(`unknown previous_response_id ${String(n)} (proxy restarts drop stored responses)`);return[...i,...r]}remember(n,t,r){this.conversations.set(n,[...t,{role:"assistant",content:r}]);for(let i of this.conversations.keys()){if(this.conversations.size<=Z)break;this.conversations.delete(i)}}};function K(e){let n=e?.output;return Array.isArray(n)?n.filter(t=>t.type==="function_call"):[]}function M(e){return e.find(n=>n.type==="response.completed")?.response??null}function et(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 J=class extends Error{};function nt(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 i=r.image_url??{};return{type:"input_image",image_url:i.url,detail:i.detail}}throw new J(`unsupported chat content part type "${String(r.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function rt(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 i=r.function??{};n.push({type:"function_call",call_id:r.id,name:i.name,arguments:i.arguments})}continue}n.push({...t,content:nt(t.role,t.content)})}return n}function F(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 U(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 st(e,n,t,r,i){let c=e.stream===!0,u;try{u=t.thread(e.previous_response_id,e.input)}catch(s){_(r,400,String(s instanceof Error?s.message:s));return}e.previous_response_id!=null&&(i.naiveInBytes+=Buffer.byteLength(JSON.stringify(u))-Buffer.byteLength(JSON.stringify(e.input)));let o=`resp_${Math.random().toString(36).slice(2,14)}`,p=e.store!==!1,y=D(e);i.model(y);let l;try{l=await n.createResponse({model:e.model,input:u,stream:c,tools:e.tools,temperature:e.temperature,max_output_tokens:e.max_output_tokens})}catch(s){if(s instanceof I){j(r,"openai",s);return}throw s}let g=[];if(c){C(r);let s=d=>{r.write(`event: ${String(d.type??"message")}
2
+ data: ${JSON.stringify(d)}
3
+
4
+ `)},a=d=>d.response&&typeof d.response=="object"?{...d,response:{...d.response,id:o}}:d,m=`item_${o.slice(5)}`,R=!1,x=!1,f=!1,A="",S=d=>{f&&(f=!1,s({type:"response.output_text.done",item_id:m,output_index:0,content_index:0,text:A}),s({type:"response.content_part.done",item_id:m,output_index:0,content_index:0,part:{type:"output_text",text:A}}),s({type:"response.output_item.done",output_index:0,item:{id:m,type:"message",role:"assistant",status:d,content:[{type:"output_text",text:A}]}}))};for await(let d of i.track(l,y)){g.push(d);let O=String(d.type??"");if(O==="response.created"||O==="response.in_progress"){R=!0,s(a(d));continue}if(O==="response.output_item.added"){x=!0,s(a(d));continue}if(O==="response.output_text.delta"&&!x){R||(R=!0,s({type:"response.created",response:{id:o,object:"response",status:"in_progress"}})),f||(f=!0,s({type:"response.output_item.added",output_index:0,item:{id:m,type:"message",role:"assistant",status:"in_progress",content:[]}}),s({type:"response.content_part.added",item_id:m,output_index:0,content_index:0,part:{type:"output_text",text:""}})),A+=String(d.delta??""),s({type:O,item_id:m,output_index:0,content_index:0,delta:d.delta});continue}if(O==="response.completed"&&!x){let Y=f;S("completed"),K(d.response).forEach((E,G)=>{let b=(Y?1:0)+G,N=E.id??E.call_id??`fc_${b}`,P=E.arguments??"",L={id:N,type:"function_call",call_id:E.call_id??N,name:E.name??""};s({type:"response.output_item.added",output_index:b,item:{...L,arguments:"",status:"in_progress"}}),s({type:"response.function_call_arguments.delta",item_id:N,output_index:b,delta:P}),s({type:"response.function_call_arguments.done",item_id:N,output_index:b,arguments:P}),s({type:"response.output_item.done",output_index:b,item:{...L,arguments:P,status:"completed"}})}),s(a(d));continue}s(a(d))}S("incomplete"),p&&t.remember(o,u,U(g,M(g))),r.write(`data: [DONE]
5
+
6
+ `),r.end();return}let h=null;for await(let s of i.track(l,y)){if(g.push(s),s.type==="error"){_(r,502,JSON.stringify(s),"upstream_error");return}s.type==="response.completed"&&(h=s.response)}if(h==null){_(r,502,"upstream produced no response.completed event","upstream_error");return}let k=U(g,h);p&&t.remember(o,u,k),w(r,200,{...h,id:o})}async function ot(e,n,t,r){let i=e.messages;if(!Array.isArray(i)){_(t,400,"chat/completions requires a messages array");return}let c=String(e.model??"urun"),u=`chatcmpl-${Math.random().toString(36).slice(2,14)}`,o;try{o=rt(i)}catch(s){if(s instanceof J){_(t,400,s.message);return}throw s}let p=D(e);r.model(p);let y;try{y=await n.createResponse({model:e.model,input:o,stream:!0,tools:et(e.tools),temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens})}catch(s){if(s instanceof I){j(t,"openai",s);return}throw s}if(e.stream===!0){C(t);let s=[];t.write(`data: ${JSON.stringify($(u,c,{role:"assistant"},null))}
7
+
8
+ `);for await(let m of r.track(y,p))if(s.push(m),m.type==="response.output_text.delta"&&typeof m.delta=="string")t.write(`data: ${JSON.stringify($(u,c,{content:m.delta},null))}
9
+
10
+ `);else if(m.type==="error"){t.write(`data: ${JSON.stringify({error:m})}
11
+
12
+ `),t.end();return}let a=F(M(s));a.length>0&&t.write(`data: ${JSON.stringify($(u,c,{tool_calls:a},null))}
13
+
14
+ `),t.write(`data: ${JSON.stringify($(u,c,{},a.length>0?"tool_calls":"stop"))}
15
+
16
+ `),t.write(`data: [DONE]
17
+
18
+ `),t.end();return}let l="",g=[];for await(let s of r.track(y,p))if(g.push(s),s.type==="response.output_text.delta"&&typeof s.delta=="string"&&(l+=s.delta),s.type==="error"){_(t,502,JSON.stringify(s),"upstream_error");return}let h=F(M(g)).map(({index:s,...a})=>a),k={role:"assistant",content:l||null};h.length>0&&(k.tool_calls=h),w(t,200,{id:u,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:c,choices:[{index:0,message:k,finish_reason:h.length>0?"tool_calls":"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}function it(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>n.type==="text").map(n=>String(n.text??"")).join(""):""}var v=class extends Error{constructor(n){super(`unsupported anthropic content block type "${n}" \u2014 the proxy translates text, tool_use and tool_result blocks`)}};function at(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 ut(e){if(typeof e=="string")return e;if(e==null)return"";if(!Array.isArray(e))throw new v(typeof e);let n="";for(let t of e){let r=String(t.type??"");if(r!=="text")throw new v(`tool_result > ${r}`);n+=String(t.text??"")}return n}function ct(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 v(typeof t);let r=[],i="",c=()=>{i&&(r.push({role:n,content:i}),i="")};for(let u of t){let o=String(u.type??"");if(o==="text")i+=String(u.text??"");else if(o==="tool_use")c(),r.push({type:"function_call",call_id:u.id,name:u.name,arguments:JSON.stringify(u.input??{})});else if(o==="tool_result")c(),r.push({type:"function_call_output",call_id:u.tool_use_id,output:ut(u.content)});else{if(o==="thinking"||o==="redacted_thinking")continue;throw new v(o)}}return c(),r}function X(e){return K(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 pt(e,n,t,r){let i=e.messages;if(!Array.isArray(i)){_(t,400,"messages requires a messages array");return}let c=String(e.model??"urun"),u=`msg_${Math.random().toString(36).slice(2,14)}`,o=[];try{e.system&&o.push({role:"system",content:it(e.system)});for(let a of i)o.push(...ct(a))}catch(a){if(a instanceof v){_(t,400,a.message);return}throw a}let p=D(e);r.model(p);let y;try{y=await n.createResponse({model:e.model,input:o,stream:!0,tools:at(e.tools),temperature:e.temperature,max_output_tokens:e.max_tokens})}catch(a){if(a instanceof I){j(t,"anthropic",a);return}throw a}let l=(a,m)=>{t.write(`event: ${a}
19
+ data: ${JSON.stringify({type:a,...m})}
20
+
21
+ `)};if(e.stream===!0){let a=r.track(y,p);C(t),l("message_start",{message:{id:u,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 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,l("content_block_delta",{index:0,delta:{type:"text_delta",text:f.delta}});else if(f.type==="error"){l("error",{error:{type:"api_error",message:JSON.stringify(f)}}),t.end();return}let x;try{x=X(M(R))}catch(f){l("error",{error:{type:"api_error",message:String(f instanceof Error?f.message:f)}}),t.end();return}l("content_block_stop",{index:0}),x.forEach((f,A)=>{let S=1+A;l("content_block_start",{index:S,content_block:{...f,input:{}}}),l("content_block_delta",{index:S,delta:{type:"input_json_delta",partial_json:JSON.stringify(f.input??{})}}),l("content_block_stop",{index:S})}),l("message_delta",{delta:{stop_reason:x.length>0?"tool_use":"end_turn"},usage:{output_tokens:m}}),l("message_stop",{}),t.end();return}let g="",h=[];for await(let a of r.track(y,p))if(h.push(a),a.type==="response.output_text.delta"&&typeof a.delta=="string"&&(g+=a.delta),a.type==="error"){_(t,502,JSON.stringify(a),"upstream_error");return}let k;try{k=X(M(h))}catch(a){_(t,502,String(a instanceof Error?a.message:a),"upstream_error");return}let s=[];(g||k.length===0)&&s.push({type:"text",text:g}),s.push(...k),w(t,200,{id:u,type:"message",role:"assistant",content:s,model:c,stop_reason:k.length>0?"tool_use":"end_turn",usage:{input_tokens:0,output_tokens:0}})}function yt(e){let{clients:n,apiKey:t,identity:r}=e,i=new q,c=new T;return H((u,o)=>{(async()=>{let p=new URL(u.url??"/","http://localhost");if(u.method==="GET"&&p.pathname==="/healthz"){w(o,200,{ok:!0});return}if(u.method==="GET"&&p.pathname==="/stats"){w(o,200,r?{identity:r,...c.snapshot()}:c.snapshot());return}if(t&&(u.headers.authorization??"")!==`Bearer ${t}`){_(o,401,"invalid local proxy api key","authentication_error");return}if(u.method==="GET"&&p.pathname==="/v1/models"){w(o,200,await n.listModels());return}if(u.method!=="POST"){_(o,404,`no route for ${u.method} ${p.pathname}`);return}let y;try{y=await W(u)}catch(g){if(g instanceof B){_(o,413,g.message,"request_too_large");return}_(o,400,"request body is not valid JSON");return}let l=Buffer.byteLength(JSON.stringify(y));if(p.pathname==="/v1/responses"){c.request("responses",l,l),await st(y,n,i,o,c);return}if(p.pathname==="/v1/chat/completions"){c.request("chat_completions",l,l),await ot(y,n,o,c);return}if(p.pathname==="/v1/messages"){c.request("messages",l,l),await pt(y,n,o,c);return}_(o,404,`no route for POST ${p.pathname}`)})().catch(p=>{o.headersSent?o.end():_(o,500,String(p),"proxy_error")})})}export{yt as a};
@@ -0,0 +1 @@
1
+ async function a(t){let e=await(t.fetchImpl??fetch)(`${t.catalogUrl}/model_catalog?select=model_id,variant`,{headers:{apikey:t.anonKey,Authorization:`Bearer ${t.anonKey}`}});if(!e.ok)throw new Error(`model_catalog fetch failed: ${e.status}`);return await e.json()}async function i(t){return{object:"list",data:(await a(t)).map(e=>({id:`${e.model_id}:${e.variant}`,object:"model",created:0,owned_by:"urun"}))}}export{a,i as b};
@@ -0,0 +1 @@
1
+ var g="https://api.urun.sh/v1";function l(a){return a.toLowerCase().replace(/[^\p{L}\p{N}-]/gu,"-").replace(/^-+|-+$/g,"")}var r=class extends Error{};async function m(a){let e=a.fetchImpl??fetch,t=`${a.apiUrl.replace(/\/+$/,"")}/apps`,s=await e(t,{headers:{Authorization:`Bearer ${a.apiKey}`,Accept:"application/json"}});if(!s.ok)throw new Error(`org apps listing failed: GET ${t} \u2192 ${s.status}`);let i=await s.json();if(!Array.isArray(i.apps))throw new Error(`org apps listing returned no "apps" array (GET ${t})`);if(i.truncated===!0)throw new Error(`org apps listing was truncated (GET ${t} returned ${i.apps.length} of more) \u2014 model discovery would silently omit deployed apps`);return i.apps}var c=6e4,u=class{constructor(e){this.opts=e}opts;pool=new Map;appsCache=null;seed(e,t){this.pool.set(e,Promise.resolve(t))}async deployedApps(){if(!this.opts.listApps)return[];let e=this.opts.appsTtlMs??c;if(this.appsCache&&Date.now()-this.appsCache.at<e)return this.appsCache.apps;let t=await this.opts.listApps();return this.appsCache={at:Date.now(),apps:t},t}servable(e){return e.filter(t=>t.function_name===this.opts.fnName&&t.deployment_status==="active").map(t=>t.app_slug)}async availableIds(){let e=new Set([this.opts.defaultApp]);if(this.opts.listApps)for(let t of this.servable(await this.deployedApps()))e.add(t);for(let t of this.pool.keys())e.add(t);return[this.opts.defaultApp,...[...e].filter(t=>t!==this.opts.defaultApp).sort()]}async resolveApp(e){let t=(e??"").trim();if(!t||t==="urun")return this.opts.defaultApp;let s=l(t);if(s===this.opts.defaultApp)return this.opts.defaultApp;if(this.pool.has(s))return s;if(this.opts.listApps){let i=await this.deployedApps(),p=this.servable(i);if(p.includes(s))return s;let o=p.filter(n=>n.startsWith(`${s}-`));if(o.length===1)return o[0];if(o.length>1)throw new r(`model "${t}" is ambiguous across deployed apps ${o.join(", ")} \u2014 name the exact app slug (or catalog id:variant)`);let d=i.find(n=>n.app_slug===s||n.app_slug.startsWith(`${s}-`));if(d)throw new r(`model "${t}" maps to app "${d.app_slug}", which is not an active "${this.opts.fnName}" app \u2014 deploy it with \`urun serve ${t}\`; available models: ${(await this.availableIds()).join(", ")}`)}if(this.opts.listCatalog){let p=(await this.opts.listCatalog()).find(o=>t===o.model_id||t===`${o.model_id}:${o.variant}`||s===l(o.model_id)||s===l(`${o.model_id}-${o.variant}`));if(p)throw new r(`model "${t}" is in the uRun catalog but not deployed \u2014 deploy it with \`urun serve ${p.model_id}\`; available models: ${(await this.availableIds()).join(", ")}`)}return this.opts.defaultApp}async sessionFor(e){let t=await this.resolveApp(e),s=this.pool.get(t);return s||(s=Promise.resolve(this.opts.openSession(t)),this.pool.set(t,s),s.catch(()=>this.pool.delete(t))),{app:t,entry:await s}}async modelList(){return{object:"list",data:(await this.availableIds()).map(t=>({id:t,object:"model",created:0,owned_by:"urun"}))}}async closeAll(){let e=[...this.pool.values()];this.pool.clear();let t=[];if(await Promise.all(e.map(async s=>{try{await this.opts.closeSession(await s)}catch(i){t.push(String(i instanceof Error?i.message:i))}})),t.length>0)throw new Error(`failed to close ${t.length} pooled session(s): ${t.join("; ")}`)}};export{g as a,r as b,m as c,u as d};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var U=Object.create;var m=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var $=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var H=(n,e)=>{for(var t in e)m(n,t,{get:e[t],enumerable:!0})},_=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of q(e))!j.call(n,o)&&o!==t&&m(n,o,{get:()=>e[o],enumerable:!(r=D(e,o))||r.enumerable});return n};var v=(n,e,t)=>(t=n!=null?U($(n)):{},_(e||!n||!n.__esModule?m(t,"default",{value:n,enumerable:!0}):t,n)),N=n=>_(m({},"__esModule",{value:!0}),n);var G={};H(G,{SUPPORTED_REALTIME_CLIENT_EVENTS:()=>h,SUPPORTED_RESPONSES_EVENTS:()=>S,UrunRealtime:()=>k,UrunResponses:()=>y,isSupportedClientEvent:()=>L,isSupportedResponsesEvent:()=>P,listModels:()=>T,nodeAudioBackend:()=>R,toErrorEvent:()=>d,weriftAudioBackend:()=>A});module.exports=N(G);function b(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 E(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 d(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 W="llm-resp";async function*g(n,e){let t=`${W}:${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 d(s);return}}}var F="llm",c=class{constructor(e){this.session=e}session;get consumerId(){return this.session.consumerId}write(e){this.session.doc(F).set({requests:{[e.request_id]:{payload:e,consumer_id:e.consumer_id,stream:e.stream}}})}sendResponses(e,t){let r=E(e,t,this.consumerId);return this.write(r),g(this.session,t)}sendResponseCreate(e,t,r){let o=b(e,t,r,this.consumerId);return this.write(o),g(this.session,r)}};var f=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)}},K=24e3,l=480,V=111;async function Y(){let n=await import("opusscript"),e=n.default??n;return new e(K,1,2048)}async function A(){let n=await import("werift"),e=await Y();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 p=0;for(;a.length-p>=l;){let w=a.subarray(p,p+l);p+=l;let O=Buffer.from(w.buffer,w.byteOffset,w.byteLength),B=e.encode(O,l);o=o+1&65535,s=s+l>>>0;let M=new n.RtpHeader({version:2,payloadType:V,sequenceNumber:o,timestamp:s,ssrc:r,marker:!1}),C=new n.RtpPacket(M,B);t.writeRtp(C)}i=a.slice(p)}}},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 R(){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 x=0;function z(){return x+=1,`rt_${Date.now().toString(36)}_${x.toString(36)}`}var k=class{constructor(e,t={}){this.session=e;this.opts=t;this.transport=new c(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 f(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=z();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(d(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 I=0;function X(){return I+=1,`req_${Date.now().toString(36)}_${I.toString(36)}`}var y=class{transport;constructor(e){this.transport=new c(e)}responses={create:async e=>{let t=X(),r=this.transport.sendResponses(e,t);return Object.assign((async function*(){yield*r})(),{requestId:t})}}};async function T(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 h=["session.update","conversation.item.create","response.create","response.cancel","input_audio_buffer.append","input_audio_buffer.commit","input_audio_buffer.clear"],S=["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 L(n){return h.includes(n)}function P(n){return S.includes(n)}0&&(module.exports={SUPPORTED_REALTIME_CLIENT_EVENTS,SUPPORTED_RESPONSES_EVENTS,UrunRealtime,UrunResponses,isSupportedClientEvent,isSupportedResponsesEvent,listModels,nodeAudioBackend,toErrorEvent,weriftAudioBackend});
1
+ "use strict";var D=Object.create;var f=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,H=Object.prototype.hasOwnProperty;var N=(n,e)=>{for(var t in e)f(n,t,{get:e[t],enumerable:!0})},b=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of $(e))!H.call(n,o)&&o!==t&&f(n,o,{get:()=>e[o],enumerable:!(r=q(e,o))||r.enumerable});return n};var v=(n,e,t)=>(t=n!=null?D(j(n)):{},b(e||!n||!n.__esModule?f(t,"default",{value:n,enumerable:!0}):t,n)),W=n=>b(f({},"__esModule",{value:!0}),n);var Q={};N(Q,{SUPPORTED_REALTIME_CLIENT_EVENTS:()=>S,SUPPORTED_RESPONSES_EVENTS:()=>_,UrunRealtime:()=>y,UrunResponses:()=>w,isSupportedClientEvent:()=>P,isSupportedResponsesEvent:()=>O,listModels:()=>L,nodeAudioBackend:()=>x,toErrorEvent:()=>d,weriftAudioBackend:()=>R});module.exports=W(Q);function E(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 A(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 d(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 F="llm-resp";async function*h(n,e){let t=`${F}:${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 d(s);return}}}var K="llm",p=class{constructor(e){this.session=e}session;get consumerId(){return this.session.consumerId}write(e){this.session.doc(K).set({requests:{[e.request_id]:{payload:e,consumer_id:e.consumer_id,stream:e.stream}}})}sendResponses(e,t){let r=A(e,t,this.consumerId);return this.write(r),h(this.session,t)}sendResponseCreate(e,t,r){let o=E(e,t,r,this.consumerId);return this.write(o),h(this.session,r)}};var k=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)}},V=24e3,m=480,Y=111;async function z(){let n=await import("opusscript"),e=n.default??n;return new e(V,1,2048)}async function R(){let n=await import("werift"),e=await z();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 l=0;for(;a.length-l>=m;){let g=a.subarray(l,l+m);l+=m;let B=Buffer.from(g.buffer,g.byteOffset,g.byteLength),C=e.encode(B,m);o=o+1&65535,s=s+m>>>0;let M=new n.RtpHeader({version:2,payloadType:Y,sequenceNumber:o,timestamp:s,ssrc:r,marker:!1}),U=new n.RtpPacket(M,C);t.writeRtp(U)}i=a.slice(l)}}},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 x(){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 I=0;function X(){return I+=1,`rt_${Date.now().toString(36)}_${I.toString(36)}`}var y=class{constructor(e,t={}){this.session=e;this.opts=t;this.transport=new p(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 k(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=X();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(d(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 T=0;function G(){return T+=1,`req_${Date.now().toString(36)}_${T.toString(36)}`}var w=class{transport;constructor(e){this.transport=new p(e)}responses={create:async e=>{let t=G(),r=this.transport.sendResponses(e,t);return Object.assign((async function*(){yield*r})(),{requestId:t})}}};async function J(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 await t.json()}async function L(n){return{object:"list",data:(await J(n)).map(t=>({id:`${t.model_id}:${t.variant}`,object:"model",created:0,owned_by:"urun"}))}}var S=["session.update","conversation.item.create","response.create","response.cancel","input_audio_buffer.append","input_audio_buffer.commit","input_audio_buffer.clear"],_=["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 P(n){return S.includes(n)}function O(n){return _.includes(n)}0&&(module.exports={SUPPORTED_REALTIME_CLIENT_EVENTS,SUPPORTED_RESPONSES_EVENTS,UrunRealtime,UrunResponses,isSupportedClientEvent,isSupportedResponsesEvent,listModels,nodeAudioBackend,toErrorEvent,weriftAudioBackend});
package/dist/index.d.cts CHANGED
@@ -1,49 +1,8 @@
1
+ import { a as UrunSessionLike, L as LaneMessage } from './ResponsesClient-CQ3l8Wft.cjs';
2
+ export { U as UrunResponses } from './ResponsesClient-CQ3l8Wft.cjs';
1
3
  export { RealtimeClientEvent, RealtimeServerEvent } from 'openai/resources/beta/realtime/realtime';
2
4
  export { ResponseStreamEvent } from 'openai/resources/responses/responses';
3
5
 
4
- /** The narrow subset of @urun-sh/core's Session the SDK depends on. */
5
- interface UrunDocLike {
6
- set(patch: Record<string, unknown>): void;
7
- get(path?: string, defaultValue?: unknown): unknown;
8
- on(event: 'change', handler: (snapshot: Record<string, unknown>) => void): () => void;
9
- }
10
- interface UrunStreamLike {
11
- messages(): AsyncIterable<unknown>;
12
- attach(track: unknown): Promise<void>;
13
- detach(): Promise<void>;
14
- readonly track: unknown;
15
- /**
16
- * Subscribe to the named media track (de)appearing. The downstream audio track
17
- * is consumed ASYNCHRONOUSLY after the WebRTC handshake, so `track` may be null
18
- * at `enableAudio()` time; this fires with the real `MediaStreamTrack` the
19
- * moment the consumer attaches (core `SessionStream.on('track')`). Optional so
20
- * non-media test doubles need not implement it.
21
- */
22
- on?(event: 'track', handler: (track: unknown) => void): () => void;
23
- }
24
- interface UrunSessionLike {
25
- /** Per-leg consumer identity (core: transport.consumerId). */
26
- readonly consumerId: string;
27
- doc(key: string): UrunDocLike;
28
- stream(name: string): UrunStreamLike;
29
- close?(): Promise<void> | void;
30
- }
31
- /** Lane message shape emitted by the serve runtime (core session.ts:83). */
32
- type LaneMessage = {
33
- t: 'delta';
34
- request_id?: string;
35
- delta: string;
36
- } | {
37
- t: 'response';
38
- request_id?: string;
39
- body: unknown;
40
- } | {
41
- t: 'error';
42
- request_id?: string;
43
- body: unknown;
44
- code?: string;
45
- };
46
-
47
6
  /** Pluggable audio backend so tests don't need real WebRTC. In production, `nodeAudioBackend()` wraps @roamhq/wrtc. */
48
7
  interface AudioSource {
49
8
  track: unknown;
@@ -119,24 +78,6 @@ declare class UrunRealtime {
119
78
  drain(): Promise<void>;
120
79
  }
121
80
 
122
- interface ResponsesStream extends AsyncIterable<unknown> {
123
- readonly requestId: string;
124
- }
125
- declare class UrunResponses {
126
- private readonly transport;
127
- constructor(session: UrunSessionLike);
128
- readonly responses: {
129
- create: (params: {
130
- model?: string;
131
- input: unknown;
132
- stream?: boolean;
133
- tools?: unknown;
134
- temperature?: number;
135
- max_output_tokens?: number;
136
- }) => Promise<ResponsesStream>;
137
- };
138
- }
139
-
140
81
  interface ModelObject {
141
82
  id: string;
142
83
  object: 'model';
@@ -147,11 +88,12 @@ interface ModelList {
147
88
  object: 'list';
148
89
  data: ModelObject[];
149
90
  }
150
- declare function listModels(opts: {
91
+ interface CatalogOptions {
151
92
  catalogUrl: string;
152
93
  anonKey: string;
153
94
  fetchImpl?: typeof fetch;
154
- }): Promise<ModelList>;
95
+ }
96
+ declare function listModels(opts: CatalogOptions): Promise<ModelList>;
155
97
 
156
98
  interface OpenAIErrorEvent {
157
99
  type: 'error';
@@ -171,4 +113,4 @@ declare const SUPPORTED_RESPONSES_EVENTS: readonly ["response.created", "respons
171
113
  declare function isSupportedClientEvent(type: string): boolean;
172
114
  declare function isSupportedResponsesEvent(type: string): boolean;
173
115
 
174
- export { type AudioBackend, type AudioSink, type AudioSource, type LaneMessage, type ModelList, type ModelObject, type OpenAIErrorEvent, SUPPORTED_REALTIME_CLIENT_EVENTS, SUPPORTED_RESPONSES_EVENTS, UrunRealtime, UrunResponses, type UrunSessionLike, isSupportedClientEvent, isSupportedResponsesEvent, listModels, nodeAudioBackend, toErrorEvent, weriftAudioBackend };
116
+ export { type AudioBackend, type AudioSink, type AudioSource, LaneMessage, type ModelList, type ModelObject, type OpenAIErrorEvent, SUPPORTED_REALTIME_CLIENT_EVENTS, SUPPORTED_RESPONSES_EVENTS, UrunRealtime, UrunSessionLike, isSupportedClientEvent, isSupportedResponsesEvent, listModels, nodeAudioBackend, toErrorEvent, weriftAudioBackend };
package/dist/index.d.ts CHANGED
@@ -1,42 +1,8 @@
1
+ import { a as UrunSessionLike, L as LaneMessage } from './ResponsesClient-CQ3l8Wft.js';
2
+ export { U as UrunResponses } from './ResponsesClient-CQ3l8Wft.js';
1
3
  export { RealtimeClientEvent, RealtimeServerEvent } from 'openai/resources/beta/realtime/realtime';
2
4
  export { ResponseStreamEvent } from 'openai/resources/responses/responses';
3
5
 
4
- interface UrunDocLike {
5
- set(patch: Record<string, unknown>): void;
6
- get(path?: string, defaultValue?: unknown): unknown;
7
- on(event: 'change', handler: (snapshot: Record<string, unknown>) => void): () => void;
8
- }
9
- interface UrunStreamLike {
10
- messages(): AsyncIterable<unknown>;
11
- attach(track: unknown): Promise<void>;
12
- detach(): Promise<void>;
13
- readonly track: unknown;
14
-
15
- on?(event: 'track', handler: (track: unknown) => void): () => void;
16
- }
17
- interface UrunSessionLike {
18
-
19
- readonly consumerId: string;
20
- doc(key: string): UrunDocLike;
21
- stream(name: string): UrunStreamLike;
22
- close?(): Promise<void> | void;
23
- }
24
-
25
- type LaneMessage = {
26
- t: 'delta';
27
- request_id?: string;
28
- delta: string;
29
- } | {
30
- t: 'response';
31
- request_id?: string;
32
- body: unknown;
33
- } | {
34
- t: 'error';
35
- request_id?: string;
36
- body: unknown;
37
- code?: string;
38
- };
39
-
40
6
  interface AudioSource {
41
7
  track: unknown;
42
8
  onData(frame: Int16Array): void;
@@ -91,24 +57,6 @@ declare class UrunRealtime {
91
57
  drain(): Promise<void>;
92
58
  }
93
59
 
94
- interface ResponsesStream extends AsyncIterable<unknown> {
95
- readonly requestId: string;
96
- }
97
- declare class UrunResponses {
98
- private readonly transport;
99
- constructor(session: UrunSessionLike);
100
- readonly responses: {
101
- create: (params: {
102
- model?: string;
103
- input: unknown;
104
- stream?: boolean;
105
- tools?: unknown;
106
- temperature?: number;
107
- max_output_tokens?: number;
108
- }) => Promise<ResponsesStream>;
109
- };
110
- }
111
-
112
60
  interface ModelObject {
113
61
  id: string;
114
62
  object: 'model';
@@ -119,11 +67,12 @@ interface ModelList {
119
67
  object: 'list';
120
68
  data: ModelObject[];
121
69
  }
122
- declare function listModels(opts: {
70
+ interface CatalogOptions {
123
71
  catalogUrl: string;
124
72
  anonKey: string;
125
73
  fetchImpl?: typeof fetch;
126
- }): Promise<ModelList>;
74
+ }
75
+ declare function listModels(opts: CatalogOptions): Promise<ModelList>;
127
76
 
128
77
  interface OpenAIErrorEvent {
129
78
  type: 'error';
@@ -142,4 +91,4 @@ declare const SUPPORTED_RESPONSES_EVENTS: readonly ["response.created", "respons
142
91
  declare function isSupportedClientEvent(type: string): boolean;
143
92
  declare function isSupportedResponsesEvent(type: string): boolean;
144
93
 
145
- export { type AudioBackend, type AudioSink, type AudioSource, type LaneMessage, type ModelList, type ModelObject, type OpenAIErrorEvent, SUPPORTED_REALTIME_CLIENT_EVENTS, SUPPORTED_RESPONSES_EVENTS, UrunRealtime, UrunResponses, type UrunSessionLike, isSupportedClientEvent, isSupportedResponsesEvent, listModels, nodeAudioBackend, toErrorEvent, weriftAudioBackend };
94
+ export { type AudioBackend, type AudioSink, type AudioSource, LaneMessage, type ModelList, type ModelObject, type OpenAIErrorEvent, SUPPORTED_REALTIME_CLIENT_EVENTS, SUPPORTED_RESPONSES_EVENTS, UrunRealtime, UrunSessionLike, isSupportedClientEvent, isSupportedResponsesEvent, listModels, nodeAudioBackend, toErrorEvent, weriftAudioBackend };
package/dist/index.js CHANGED
@@ -1 +1 @@
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};
1
+ import{b as _}from"./chunk-OLE2YJO3.js";import{a as f,b as v,c as g}from"./chunk-FSS2A7IU.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)}},T=24e3,c=480,x=111;async function I(){let o=await import("opusscript"),t=o.default??o;return new t(T,1,2048)}async function P(){let o=await import("werift"),t=await I();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 A=Buffer.from(l.buffer,l.byteOffset,l.byteLength),E=t.encode(A,c);r=r+1&65535,a=a+c>>>0;let b=new o.RtpHeader({version:2,payloadType:x,sequenceNumber:r,timestamp:a,ssrc:n,marker:!1}),R=new o.RtpPacket(b,E);e.writeRtp(R)}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 B(){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 h=0;function O(){return h+=1,`rt_${Date.now().toString(36)}_${h.toString(36)}`}var w=class{constructor(t,e={}){this.session=t;this.opts=e;this.transport=new v(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=O();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 S=["session.update","conversation.item.create","response.create","response.cancel","input_audio_buffer.append","input_audio_buffer.commit","input_audio_buffer.clear"],y=["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 L(o){return S.includes(o)}function C(o){return y.includes(o)}export{S as SUPPORTED_REALTIME_CLIENT_EVENTS,y as SUPPORTED_RESPONSES_EVENTS,w as UrunRealtime,g as UrunResponses,L as isSupportedClientEvent,C as isSupportedResponsesEvent,_ as listModels,B as nodeAudioBackend,f as toErrorEvent,P as weriftAudioBackend};
@@ -0,0 +1,3 @@
1
+ "use strict";var se=Object.create;var E=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var ie=Object.getPrototypeOf,ae=Object.prototype.hasOwnProperty;var pe=(t,e)=>{for(var n in e)E(t,n,{get:e[n],enumerable:!0})},K=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of oe(e))!ae.call(t,r)&&r!==n&&E(t,r,{get:()=>e[r],enumerable:!(s=re(e,r))||s.enumerable});return t};var le=(t,e,n)=>(n=t!=null?se(ie(t)):{},K(e||!t||!t.__esModule?E(n,"default",{value:t,enumerable:!0}):n,t)),ue=t=>K(E({},"__esModule",{value:!0}),t);var Le={};pe(Le,{SessionPool:()=>U,URUN_API:()=>M,coalesceSameRole:()=>V,createUrunExtension:()=>ee,default:()=>Ie,makeStreamSimple:()=>Z,resolveSessionEnv:()=>z,toResponsesInput:()=>Q});module.exports=ue(Le);var ce=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,d=ce();var X=require("@earendil-works/pi-ai");function q(t,e,n,s){let r=t.response??{},o={request_id:n,consumer_id:s,stream:!0,kind:"chat",messages:e};return typeof r.instructions=="string"&&(o.instructions=r.instructions),Array.isArray(r.modalities)&&(o.modalities=r.modalities),typeof r.temperature=="number"&&(o.temperature=r.temperature),typeof r.max_output_tokens=="number"&&(o.max_output_tokens=r.max_output_tokens),r.tools!==void 0&&(o.tools=r.tools),o}function W(t,e,n){let s={request_id:e,consumer_id:n,stream:!!t.stream,kind:"responses",input:t.input};return t.model&&(s.model=t.model),t.tools!==void 0&&(s.tools=t.tools),typeof t.temperature=="number"&&(s.temperature=t.temperature),typeof t.max_output_tokens=="number"&&(s.max_output_tokens=t.max_output_tokens),s}function G(t){if(t instanceof Error)return{type:"error",error:{type:"urun_error",code:t.name||null,message:t.message}};if(t&&typeof t=="object"&&t.t==="error"){let e=t,n=e.body??{};return{type:"error",error:{type:"urun_error",code:e.code??null,message:n.message??"unknown error"}}}return{type:"error",error:{type:"urun_error",code:null,message:String(t)}}}var de="llm-resp";async function*L(t,e){let n=`${de}:${e}`,s=`resp_${e}`;yield{type:"response.created",response:{id:s,status:"in_progress"}};for await(let r of t.stream(n).messages()){let o=r;if(o.t==="delta")yield{type:"response.output_text.delta",item_id:s,delta:o.delta};else if(o.t==="response"){yield{type:"response.completed",response:{id:s,status:"completed",...o.body}};return}else if(o.t==="error"){yield G(o);return}}}var me="llm",R=class{constructor(e){this.session=e}session;get consumerId(){return this.session.consumerId}write(e){this.session.doc(me).set({requests:{[e.request_id]:{payload:e,consumer_id:e.consumer_id,stream:e.stream}}})}sendResponses(e,n){let s=W(e,n,this.consumerId);return this.write(s),L(this.session,n)}sendResponseCreate(e,n,s){let r=q(e,n,s,this.consumerId);return this.write(r),L(this.session,s)}};var J=0;function fe(){return J+=1,`req_${Date.now().toString(36)}_${J.toString(36)}`}var x=class{transport;constructor(e){this.transport=new R(e)}responses={create:async e=>{let n=fe(),s=this.transport.sendResponses(e,n);return Object.assign((async function*(){yield*s})(),{requestId:n})}}};var $="https://api.urun.sh/v1";async function B(t){let e=t.fetchImpl??fetch,n=`${t.apiUrl.replace(/\/+$/,"")}/apps`,s=await e(n,{headers:{Authorization:`Bearer ${t.apiKey}`,Accept:"application/json"}});if(!s.ok)throw new Error(`org apps listing failed: GET ${n} \u2192 ${s.status}`);let r=await s.json();if(!Array.isArray(r.apps))throw new Error(`org apps listing returned no "apps" array (GET ${n})`);if(r.truncated===!0)throw new Error(`org apps listing was truncated (GET ${n} returned ${r.apps.length} of more) \u2014 model discovery would silently omit deployed apps`);return r.apps}async function Y(t){let e=await B(t),n=e.filter(s=>s.function_name===t.fnName&&s.deployment_status==="active").map(s=>s.app_slug);if(n.length===0)throw new Error(`urun pi extension: the org has no active deployed app exposing "${t.fnName}" (GET ${t.apiUrl}/apps returned ${e.length} app(s), none servable) \u2014 deploy one with \`urun serve <model>\` first`);return n.sort()}var M="urun-serve",ge="serve",ye=131072,he=16384,H=3,we=42e4,ve=6e4,_e=15e3;function be(t){let e=(t.URUN_API_KEY??"").trim();if(!e)throw new Error("urun pi extension: URUN_API_KEY is required \u2014 model discovery lists the org's deployed serve apps via the org API (URUN_JWT alone cannot list apps)");return{apiKey:e,apiUrl:(t.URUN_API_URL??"").trim()||$,fnName:(t.URUN_FUNCTION??"").trim()||ge}}function z(t){let e=(t.URUN_BASE_URL??"").trim(),n=(t.URUN_ORG_ID??"").trim();if(!e)throw new Error("urun pi extension: URUN_BASE_URL is required to open a session");if(/\/v1\/*$/.test(new URL(e).pathname))throw new Error(`urun pi extension: URUN_BASE_URL must be the session-gateway base (e.g. https://api.urun.sh), got ${e} \u2014 a trailing /v1 is the org API form (URUN_API_URL); session allocation 404s against it. Drop the /v1.`);if(!n)throw new Error("urun pi extension: URUN_ORG_ID is required to open a session");let s=(t.URUN_JWT??"").trim();if(s)return{baseUrl:e,orgId:n,auth:{lane:"jwt",jwt:s}};let r=(t.URUN_API_KEY??"").trim();if(!r)throw new Error("urun pi extension: URUN_JWT or URUN_API_KEY is required to open a session");let o=(t.URUN_GATEWAY_URL??"").trim()||void 0;return{baseUrl:e,orgId:n,auth:{lane:"api-key",apiKey:r,gatewayUrl:o}}}var Ae=async(t,e,n)=>{let{baseUrl:s,orgId:r,auth:o}=z(t),{createRequire:a}=await import("module"),l=a(d);if(typeof globalThis.RTCPeerConnection>"u")try{l.resolve("werift")}catch{throw new Error('urun pi extension: token streams require a WebRTC data channel, and this Node runtime has no RTCPeerConnection and no "werift" backend installed (@urun-sh/core\'s optional Node WebRTC backend \u2014 it was probably stripped by a --no-optional install). Install werift (`npm i werift`) and retry.')}let{App:m,createClientToken:p}=l("@urun-sh/core"),y=(o.lane==="jwt"?m(e,{baseUrl:s,orgId:r,jwt:o.jwt}):m(e,{baseUrl:s,orgId:r,getAccessToken:async()=>(await p(o.apiKey,{baseUrl:o.gatewayUrl,expiresIn:300,allowedFunctions:[`${e}/${n}`]})).token}))[n];if(typeof y!="function")throw new Error(`urun pi extension: app "${e}" has no function "${n}"`);let u=y(),c=u.connect;return typeof c=="function"&&await c.call(u),u};function Ee(t){try{Promise.resolve(t.close?.()).catch(()=>{})}catch{}}var U=class{constructor(e,n,s){this.open=e;this.env=n;this.fnName=s}open;env;fnName;pool=new Map;acquire(e){let n=this.pool.get(e);if(!n){let s=Promise.resolve(this.open(this.env,e,this.fnName)).then(r=>({session:r,responses:new x(r)}));n=s,this.pool.set(e,s),s.catch(()=>{this.pool.get(e)===s&&this.pool.delete(e)})}return n}evict(e){let n=this.pool.get(e);n&&(this.pool.delete(e),n.then(s=>Ee(s.session),()=>{}))}closeAll(){for(let e of[...this.pool.keys()])this.evict(e)}};function Q(t){let e=[];t.systemPrompt&&e.push({role:"system",content:t.systemPrompt});for(let n of t.messages){let s=n.role==="assistant"?"assistant":"user";e.push({role:s,content:Re(n.content)})}return V(e)}function V(t){let e=[];for(let n of t){let s=e[e.length-1];s&&s.role===n.role?s.content=[s.content,n.content].filter(r=>r.length>0).join(`
2
+
3
+ `):e.push({...n})}return e}function Re(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>e&&typeof e=="object"&&"text"in e?String(e.text):"").join(""):""}function xe(t){let e=t instanceof Error?t.message:String(t),n=t?.code;return/\b529\b/.test(e)||/overloaded/i.test(e)||n===529||n==="529"}function Ue(t){return new Promise(e=>setTimeout(e,t))}function Se(t,e,n,s){return new Promise((r,o)=>{let a=!1,l=i=>{a||(a=!0,clearTimeout(m),s?.removeEventListener("abort",p),i())},m=setTimeout(()=>l(()=>o(n())),e),p=()=>l(()=>o(new Error("aborted")));if(s?.aborted){p();return}s?.addEventListener("abort",p,{once:!0}),Promise.resolve(t).then(i=>l(()=>r(i)),i=>l(()=>o(i)))})}async function*ke(t,e){let n=t[Symbol.asyncIterator](),s,r=new Promise((o,a)=>{s=()=>a(new Error("aborted")),e.addEventListener("abort",s,{once:!0})});try{for(;;){if(e.aborted)throw new Error("aborted");let o=await Promise.race([n.next(),r]);if(o.done)return;yield o.value}}finally{s&&e.removeEventListener("abort",s),n.return?.(void 0)}}function Te(t,e){let n=t?.sendMessage;if(typeof n=="function")try{n.call(t,{customType:"urun-status",content:e,display:!0},{triggerTurn:!1})}catch{}}function Z(t,e={},n){let s=e.connectDeadlineMs??we,r=e.stallTimeoutMs??ve,o=e.phaseHeartbeatMs??_e;return(a,l,m)=>{let p=(0,X.createAssistantMessageEventStream)(),i={role:"assistant",content:[{type:"text",text:""}],api:a.api,provider:a.provider,model:a.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"stop",timestamp:Date.now()},y=i.content[0],u=new AbortController,c=m?.signal,S=!1,k=()=>{S=!0,u.abort()};c&&(c.aborted?k():c.addEventListener("abort",k,{once:!0}));let T=!1,h,C=()=>{h&&clearTimeout(h),h=setTimeout(()=>{T=!0,u.abort()},r)},P=()=>{h&&clearTimeout(h),h=void 0};return(async()=>{p.push({type:"start",partial:i}),p.push({type:"text_start",contentIndex:0,partial:i});let N=!1,_,D=()=>{_&&clearInterval(_),_=void 0},te=Date.now();_=setInterval(()=>{let f=Math.round((Date.now()-te)/1e3);Te(n,`uRun: still opening the "${a.id}" session\u2026 (${f}s \u2014 serve apps scale to zero, first turn can cold-start ~6min)`)},o);try{let{responses:f}=await Se(t.acquire(a.id),s,()=>new Error(`uRun session for "${a.id}" did not connect within ${Math.round(s/1e3)}s \u2014 likely cold-starting (scaled to zero) or queued behind capacity. Retry shortly.`),u.signal);D();let I=Q(l),O,b;for(let A=1;A<=H;A++)try{let w=await f.responses.create({model:a.id,input:I,stream:!0,max_output_tokens:a.maxTokens});C();for await(let ne of ke(w,u.signal)){C();let g=ne;if(g.type==="response.output_text.delta"){let v=typeof g.delta=="string"?g.delta:"";v&&(y.text+=v,p.push({type:"text_delta",contentIndex:0,delta:v,partial:i}))}else if(g.type==="response.completed"){O=g.response;break}else if(g.type==="error"){let v=g.error,F=new Error(`uRun serve error: ${v?.message??"unknown error"}`);throw F.code=v?.code??null,F}}b=void 0;break}catch(w){if(b=w,u.signal.aborted)throw w;if(A<H&&xe(w)&&y.text.length===0){await Ue(A*500);continue}throw w}if(b)throw b;P(),p.push({type:"text_end",contentIndex:0,content:y.text,partial:i});let j=O?.status==="incomplete"?"length":"stop";i.stopReason=j,p.push({type:"done",reason:j,message:i}),p.end(i)}catch(f){if(N=!0,P(),S||c?.aborted&&!T)i.stopReason="aborted",i.errorMessage="aborted by user",p.push({type:"error",reason:"aborted",error:i});else{let I=T?`uRun stream stalled \u2014 no output for ${Math.round(r/1e3)}s; the model may be hung. Retry, or Ctrl-C to abort.`:f instanceof Error?f.message:String(f);i.stopReason="error",i.errorMessage=I,p.push({type:"error",reason:"error",error:i})}p.end(i)}finally{P(),D(),c&&c.removeEventListener("abort",k),N&&t.evict(a.id)}})(),p}}function Pe(t){return{id:t,name:`uRun ${t}`,api:M,reasoning:!1,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:ye,maxTokens:he}}function ee(t={}){return async e=>{let n=t.env??process.env,{apiKey:s,apiUrl:r,fnName:o}=be(n),a=await Y({apiUrl:r,apiKey:s,fnName:o,fetchImpl:t.fetchImpl}),l=new U(t.openSession??Ae,n,o);e.on("session_shutdown",()=>l.closeAll());let m={name:"uRun",api:M,baseUrl:"urun://session",apiKey:"$URUN_API_KEY",models:a.map(Pe),streamSimple:Z(l,t.timing??{},e)};e.registerProvider("urun",m)}}var Ie=ee();0&&(module.exports={SessionPool,URUN_API,coalesceSameRole,createUrunExtension,makeStreamSimple,resolveSessionEnv,toResponsesInput});