@urun-sh/openai 0.2.53 → 0.2.54
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 → ResponsesClient-DF39QXq1.d.cts} +28 -2
- package/dist/{ResponsesClient-CQ3l8Wft.d.ts → ResponsesClient-DF39QXq1.d.ts} +14 -1
- package/dist/chunk-DYBS3NLC.js +1 -0
- package/dist/chunk-EEKOQKWE.js +27 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/pi-extension/index.cjs +3 -2
- package/dist/pi-extension/index.d.cts +55 -20
- package/dist/pi-extension/index.d.ts +24 -4
- package/dist/pi-extension/index.js +3 -2
- package/dist/pi-extension/standalone.cjs +49 -48
- package/dist/proxy/cli.cjs +31 -22
- package/dist/proxy/cli.js +15 -12
- package/dist/proxy/index.cjs +18 -12
- package/dist/proxy/index.d.cts +1 -0
- package/dist/proxy/index.d.ts +1 -0
- package/dist/proxy/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-FSS2A7IU.js +0 -1
- package/dist/chunk-KJ25VEMG.js +0 -21
|
@@ -25,11 +25,36 @@ interface UrunSessionLike {
|
|
|
25
25
|
stream(name: string): UrunStreamLike;
|
|
26
26
|
close?(): Promise<void> | void;
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* One OpenAI chat-completions-chunk-style tool_call delta fragment as the
|
|
30
|
+
* serve runtime streams it (`{"t":"delta","tool_calls":[...]}`): keyed by
|
|
31
|
+
* `index`; `id`/`function.name` typically arrive only on the first fragment
|
|
32
|
+
* of an index, later fragments carry only the `function.arguments`
|
|
33
|
+
* continuation.
|
|
34
|
+
*/
|
|
35
|
+
interface LaneToolCallDelta {
|
|
36
|
+
index: number;
|
|
37
|
+
id?: string;
|
|
38
|
+
type?: 'function';
|
|
39
|
+
function?: {
|
|
40
|
+
name?: string;
|
|
41
|
+
arguments?: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Lane message shape emitted by the serve runtime (core session.ts:83).
|
|
46
|
+
* A `delta` message carries AT LEAST ONE of `delta` (visible text),
|
|
47
|
+
* `reasoning` (thinking text) or `tool_calls` (structured tool-call
|
|
48
|
+
* fragments); both directions are additive — an old server simply never
|
|
49
|
+
* sends the new fields, and unknown extra fields must be ignored, never a
|
|
50
|
+
* decode error.
|
|
51
|
+
*/
|
|
29
52
|
type LaneMessage = {
|
|
30
53
|
t: 'delta';
|
|
31
54
|
request_id?: string;
|
|
32
|
-
delta
|
|
55
|
+
delta?: string;
|
|
56
|
+
reasoning?: string;
|
|
57
|
+
tool_calls?: LaneToolCallDelta[];
|
|
33
58
|
} | {
|
|
34
59
|
t: 'response';
|
|
35
60
|
request_id?: string;
|
|
@@ -53,6 +78,7 @@ declare class UrunResponses {
|
|
|
53
78
|
input: unknown;
|
|
54
79
|
stream?: boolean;
|
|
55
80
|
tools?: unknown;
|
|
81
|
+
tool_choice?: unknown;
|
|
56
82
|
temperature?: number;
|
|
57
83
|
max_output_tokens?: number;
|
|
58
84
|
}) => Promise<ResponsesStream>;
|
|
@@ -20,10 +20,22 @@ interface UrunSessionLike {
|
|
|
20
20
|
close?(): Promise<void> | void;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
interface LaneToolCallDelta {
|
|
24
|
+
index: number;
|
|
25
|
+
id?: string;
|
|
26
|
+
type?: 'function';
|
|
27
|
+
function?: {
|
|
28
|
+
name?: string;
|
|
29
|
+
arguments?: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
type LaneMessage = {
|
|
24
34
|
t: 'delta';
|
|
25
35
|
request_id?: string;
|
|
26
|
-
delta
|
|
36
|
+
delta?: string;
|
|
37
|
+
reasoning?: string;
|
|
38
|
+
tool_calls?: LaneToolCallDelta[];
|
|
27
39
|
} | {
|
|
28
40
|
t: 'response';
|
|
29
41
|
request_id?: string;
|
|
@@ -47,6 +59,7 @@ declare class UrunResponses {
|
|
|
47
59
|
input: unknown;
|
|
48
60
|
stream?: boolean;
|
|
49
61
|
tools?: unknown;
|
|
62
|
+
tool_choice?: unknown;
|
|
50
63
|
temperature?: number;
|
|
51
64
|
max_output_tokens?: number;
|
|
52
65
|
}) => Promise<ResponsesStream>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function g(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,o=n.body??{};return{type:"error",error:{type:"urun_error",code:n.code??null,message:o.message??"unknown error"}}}return{type:"error",error:{type:"urun_error",code:null,message:String(e)}}}function y(e,n,o,t){let r=e.response??{},i={request_id:o,consumer_id:t,stream:!0,kind:"chat",messages:n};return typeof r.instructions=="string"&&(i.instructions=r.instructions),Array.isArray(r.modalities)&&(i.modalities=r.modalities),typeof r.temperature=="number"&&(i.temperature=r.temperature),typeof r.max_output_tokens=="number"&&(i.max_output_tokens=r.max_output_tokens),r.tools!==void 0&&(i.tools=r.tools),i}function _(e,n,o){let t={request_id:n,consumer_id:o,stream:!!e.stream,kind:"responses",input:e.input};return e.model&&(t.model=e.model),e.tools!==void 0&&(t.tools=e.tools),e.tool_choice!==void 0&&(t.tool_choice=e.tool_choice),typeof e.temperature=="number"&&(t.temperature=e.temperature),typeof e.max_output_tokens=="number"&&(t.max_output_tokens=e.max_output_tokens),t}var w="llm-resp";async function*d(e,n){let o=`${w}:${n}`,t=`resp_${n}`;yield{type:"response.created",response:{id:t,status:"in_progress"}};let r=new Map;for await(let i of e.stream(o).messages()){let s=i;if(s.t==="delta"){if(typeof s.delta=="string"&&(yield{type:"response.output_text.delta",item_id:t,delta:s.delta}),typeof s.reasoning=="string"&&(yield{type:"response.reasoning_text.delta",item_id:t,delta:s.reasoning}),Array.isArray(s.tool_calls))for(let u of s.tool_calls){let p=typeof u.index=="number"?u.index:0,a=r.get(p)??{};u.id&&(a.id=u.id),u.function?.name&&(a.name=u.function.name),r.set(p,a),yield{type:"response.function_call_arguments.delta",item_id:`fc_${n}_${p}`,tool_index:p,call_id:a.id,name:a.name,delta:u.function?.arguments??""}}}else if(s.t==="response"){yield{type:"response.completed",response:{id:t,status:"completed",...s.body}};return}else if(s.t==="error"){yield g(s);return}}}var b="llm",l=class{constructor(n){this.session=n}session;get consumerId(){return this.session.consumerId}write(n){this.session.doc(b).set({requests:{[n.request_id]:{payload:n,consumer_id:n.consumer_id,stream:n.stream}}})}sendResponses(n,o){let t=_(n,o,this.consumerId);return this.write(t),d(this.session,o)}sendResponseCreate(n,o,t){let r=y(n,o,t,this.consumerId);return this.write(r),d(this.session,t)}};var f=0;function v(){return f+=1,`req_${Date.now().toString(36)}_${f.toString(36)}`}var k=class{transport;constructor(n){this.transport=new l(n)}responses={create:async n=>{let o=v(),t=this.transport.sendResponses(n,o);return Object.assign((async function*(){yield*t})(),{requestId:o})}}};export{g as a,l as b,k as c};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import{b as V}from"./chunk-PS4BLX7J.js";import{createServer as yt}from"http";var ut=class e{startedAt=Date.now();requests={};models={};ttftMs=[];tokRates=[];tokensOut=0;charsOut=0;localInBytes=0;naiveInBytes=0;request(n,t,o){this.requests[n]=(this.requests[n]??0)+1,this.localInBytes+=t,this.naiveInBytes+=o}modelEntry(n){let t=this.models[n];if(t)return t;let o=Object.keys(this.models).length>=ht?"(other)":n;return this.models[o]??={requests:0,tokens_out:0}}model(n){this.modelEntry(n).requests+=1}track(n,t){let o=this,a=performance.now(),c=null,u=0;return(async function*(){for await(let d of n)d.type==="response.output_text.delta"&&typeof d.delta=="string"&&(c===null&&(c=performance.now(),o.ttftMs.push(c-a),o.ttftMs.length>512&&o.ttftMs.shift()),u+=1,o.tokensOut+=1,o.charsOut+=d.delta.length,t!==void 0&&(o.modelEntry(t).tokens_out+=1)),yield d;let i=(performance.now()-(c??a))/1e3;u>0&&i>0&&(o.tokRates.push(u/i),o.tokRates.length>512&&o.tokRates.shift())})()}static p50(n){if(!n.length)return null;let t=[...n].sort((o,a)=>o-a);return t[Math.floor(t.length/2)]}snapshot(){let n=Object.values(this.requests).reduce((t,o)=>t+o,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 ct(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function J(e,n,t){e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(t))}function w(e,n,t,o="invalid_request_error"){J(e,n,{error:{message:t,type:o}})}function pt(e,n,t){if(n==="anthropic"){J(e,404,{type:"error",error:{type:"not_found_error",message:t.message}});return}J(e,404,{error:{message:t.message,type:"invalid_request_error",code:"model_not_found"}})}var ht=256,kt=128;function dt(e){return typeof e.model!="string"||!e.model.trim()?"(default)":e.model.trim().slice(0,kt)}var mt=64*1024*1024,nt=class extends Error{};async function wt(e){let n=[],t=0;for await(let a of e){if(t+=a.length,t>mt)throw new nt(`request body exceeds ${mt} bytes`);n.push(a)}let o=Buffer.concat(n).toString("utf8");return o?JSON.parse(o):{}}function F(e,n,t,o){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:n,choices:[{index:0,delta:t,finish_reason:o}]}}var xt=256;function Rt(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 lt=class{conversations=new Map;thread(n,t){let o=Rt(t);if(n==null)return o;let a=this.conversations.get(String(n));if(!a)throw new Error(`unknown previous_response_id ${String(n)} (proxy restarts drop stored responses)`);return[...a,...o]}remember(n,t,o){this.conversations.set(n,[...t,{role:"assistant",content:o}]);for(let a of this.conversations.keys()){if(this.conversations.size<=xt)break;this.conversations.delete(a)}}};function Q(e){let n=e?.output;return Array.isArray(n)?n.filter(t=>t.type==="function_call"):[]}function W(e){return e.find(n=>n.type==="response.completed")?.response??null}function _t(e){let n=e?.output;if(!Array.isArray(n))return"";let t="";for(let o of n)if(!(o.type!=="reasoning"||!Array.isArray(o.content)))for(let a of o.content)a.type==="reasoning_text"&&(t+=String(a.text??""));return t}function Z(e){return e.type!=="response.function_call_arguments.delta"||typeof e.tool_index!="number"?null:{tool_index:e.tool_index,call_id:typeof e.call_id=="string"?e.call_id:void 0,name:typeof e.name=="string"?e.name:void 0,delta:typeof e.delta=="string"?e.delta:""}}var z=class{calls=new Map;add(n){let t=this.calls.get(n.tool_index),o=!t;return t||(t={args:""},this.calls.set(n.tool_index,t)),n.call_id&&(t.id=n.call_id),n.name&&(t.name=n.name),t.args+=n.delta,{call:t,isNew:o}}get size(){return this.calls.size}items(){return[...this.calls.entries()].map(([n,t])=>({type:"function_call",call_id:t.id??`call_${n}`,name:t.name??"",arguments:t.args}))}},vt=["<tool_call>","<function="];function At(e){return vt.find(n=>e.includes(n))}function D(e,n){return`serving row emitted a prose tool call (literal ${JSON.stringify(n)} in the assistant text) for a request that carried tools, and no structured tool_calls arrived \u2014 the tool-call parser is not configured on the model row "${e}" (see catalog parser_defaults)`}function K(e,n,t){if(!(!e||n>0))return At(t)}function St(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 ot=class extends Error{};function It(e,n){return Array.isArray(n)?n.map(t=>{let o=t;if(o.type==="text")return{type:e==="assistant"?"output_text":"input_text",text:o.text};if(o.type==="image_url"){let a=o.image_url??{};return{type:"input_image",image_url:a.url,detail:a.detail}}throw new ot(`unsupported chat content part type "${String(o.type)}" \u2014 the proxy translates text and image_url parts`)}):n}function Ot(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 o of t.tool_calls){let a=o.function??{};n.push({type:"function_call",call_id:o.id,name:a.name,arguments:a.arguments})}continue}n.push({...t,content:It(t.role,t.content)})}return n}function it(e){return Q(e).map((n,t)=>({index:t,id:n.call_id??n.id??`call_${t}`,type:"function",function:{name:n.name??"",arguments:n.arguments??"{}"}}))}function gt(e,n){let t=n?.output_text;return typeof t=="string"?t:e.filter(o=>o.type==="response.output_text.delta"&&typeof o.delta=="string").map(o=>o.delta).join("")}async function Et(e,n,t,o,a){let c=e.stream===!0,u;try{u=t.thread(e.previous_response_id,e.input)}catch(s){w(o,400,String(s instanceof Error?s.message:s));return}e.previous_response_id!=null&&(a.naiveInBytes+=Buffer.byteLength(JSON.stringify(u))-Buffer.byteLength(JSON.stringify(e.input)));let i=`resp_${Math.random().toString(36).slice(2,14)}`,d=e.store!==!1,_=dt(e);a.model(_);let v=Array.isArray(e.tools)&&e.tools.length>0,A;try{A=await n.createResponse({model:e.model,input:u,stream:c,tools:e.tools,tool_choice:e.tool_choice,temperature:e.temperature,max_output_tokens:e.max_output_tokens})}catch(s){if(s instanceof V){pt(o,"openai",s);return}throw s}let f=[];if(c){ct(o);let s=p=>{o.write(`event: ${String(p.type??"message")}
|
|
2
|
+
data: ${JSON.stringify(p)}
|
|
3
|
+
|
|
4
|
+
`)},C=p=>p.response&&typeof p.response=="object"?{...p,response:{...p.response,id:i}}:p,R=`item_${i.slice(5)}`,b=`rs_${i.slice(5)}`,E=!1,$=!1,r=0,g=()=>{E||(E=!0,s({type:"response.created",response:{id:i,object:"response",status:"in_progress"}}))},T=!1,S=0,M="",N=()=>{T&&(T=!1,s({type:"response.reasoning_text.done",item_id:b,output_index:S,content_index:0,text:M}),s({type:"response.output_item.done",output_index:S,item:{id:b,type:"reasoning",summary:[],content:[{type:"reasoning_text",text:M}],status:"completed"}}))},m=!1,x=0,O="",j=p=>{m&&(m=!1,s({type:"response.output_text.done",item_id:R,output_index:x,content_index:0,text:O}),s({type:"response.content_part.done",item_id:R,output_index:x,content_index:0,part:{type:"output_text",text:O}}),s({type:"response.output_item.done",output_index:x,item:{id:R,type:"message",role:"assistant",status:p,content:[{type:"output_text",text:O}]}}))},B=new z,y=null,L=-1,H=p=>{if(!y)return;let h=y;y=null,s({type:"response.function_call_arguments.done",item_id:h.fcId,output_index:h.outputIndex,arguments:h.args}),s({type:"response.output_item.done",output_index:h.outputIndex,item:{id:h.fcId,type:"function_call",call_id:h.callId??h.fcId,name:h.name??"",arguments:h.args,status:p}})},U=!1;for await(let p of a.track(A,_)){f.push(p);let h=String(p.type??"");if(h==="response.created"||h==="response.in_progress"){E=!0,s(C(p));continue}if(h==="response.output_item.added"){$=!0,s(C(p));continue}if(h==="response.reasoning_text.delta"&&!$){g(),T||(T=!0,S=r++,s({type:"response.output_item.added",output_index:S,item:{id:b,type:"reasoning",summary:[],content:[],status:"in_progress"}})),M+=String(p.delta??""),s({type:"response.reasoning_text.delta",item_id:b,output_index:S,content_index:0,delta:p.delta});continue}if(h==="response.output_text.delta"&&!$){g(),N(),m||(m=!0,x=r++,s({type:"response.output_item.added",output_index:x,item:{id:R,type:"message",role:"assistant",status:"in_progress",content:[]}}),s({type:"response.content_part.added",item_id:R,output_index:x,content_index:0,part:{type:"output_text",text:""}})),O+=String(p.delta??""),s({type:h,item_id:R,output_index:x,content_index:0,delta:p.delta});continue}let l=$?null:Z(p);if(l){if(g(),N(),j("completed"),B.add(l),l.tool_index!==L){H("completed"),L=l.tool_index;let k=r++;y={fcId:`fc_${i.slice(5)}_${l.tool_index}`,outputIndex:k,callId:l.call_id,name:l.name,args:""},s({type:"response.output_item.added",output_index:k,item:{id:y.fcId,type:"function_call",call_id:y.callId??y.fcId,name:y.name??"",arguments:"",status:"in_progress"}})}y&&(l.call_id&&(y.callId=l.call_id),l.name&&(y.name=l.name),y.args+=l.delta,s({type:"response.function_call_arguments.delta",item_id:y.fcId,output_index:y.outputIndex,delta:l.delta}));continue}if(h==="response.completed"&&!$){let k=Q(p.response),X=K(v,B.size+k.length,O);if(X){U=!0,s({type:"error",error:{type:"urun_error",code:"tool_call_parser_missing",message:D(_,X)}});break}N(),j("completed"),H("completed"),B.size===0&&k.forEach(Y=>{let G=r++,et=Y.id??Y.call_id??`fc_${G}`,st=Y.arguments??"",ft={id:et,type:"function_call",call_id:Y.call_id??et,name:Y.name??""};s({type:"response.output_item.added",output_index:G,item:{...ft,arguments:"",status:"in_progress"}}),s({type:"response.function_call_arguments.delta",item_id:et,output_index:G,delta:st}),s({type:"response.function_call_arguments.done",item_id:et,output_index:G,arguments:st}),s({type:"response.output_item.done",output_index:G,item:{...ft,arguments:st,status:"completed"}})}),s(C(p));continue}s(C(p))}N(),j("incomplete"),H("incomplete"),d&&!U&&t.remember(i,u,gt(f,W(f))),o.write(`data: [DONE]
|
|
5
|
+
|
|
6
|
+
`),o.end();return}let I=null;for await(let s of a.track(A,_)){if(f.push(s),s.type==="error"){w(o,502,JSON.stringify(s),"upstream_error");return}s.type==="response.completed"&&(I=s.response)}if(I==null){w(o,502,"upstream produced no response.completed event","upstream_error");return}let q=gt(f,I),P=K(v,Q(I).length,q);if(P){w(o,502,D(_,P),"upstream_error");return}d&&t.remember(i,u,q),J(o,200,{...I,id:i})}async function bt(e,n,t,o){let a=e.messages;if(!Array.isArray(a)){w(t,400,"chat/completions requires a messages array");return}let c=String(e.model??"urun"),u=`chatcmpl-${Math.random().toString(36).slice(2,14)}`,i;try{i=Ot(a)}catch(r){if(r instanceof ot){w(t,400,r.message);return}throw r}let d=dt(e);o.model(d);let _=Array.isArray(e.tools)&&e.tools.length>0,v;try{v=await n.createResponse({model:e.model,input:i,stream:!0,tools:St(e.tools),tool_choice:e.tool_choice,temperature:e.temperature,max_output_tokens:e.max_completion_tokens??e.max_tokens})}catch(r){if(r instanceof V){pt(t,"openai",r);return}throw r}if(e.stream===!0){ct(t);let r=[],g=new z,T="";t.write(`data: ${JSON.stringify(F(u,c,{role:"assistant"},null))}
|
|
7
|
+
|
|
8
|
+
`);for await(let m of o.track(v,d)){r.push(m);let x=Z(m);if(m.type==="response.output_text.delta"&&typeof m.delta=="string")T+=m.delta,t.write(`data: ${JSON.stringify(F(u,c,{content:m.delta},null))}
|
|
9
|
+
|
|
10
|
+
`);else if(m.type==="response.reasoning_text.delta"&&typeof m.delta=="string")t.write(`data: ${JSON.stringify(F(u,c,{reasoning_content:m.delta},null))}
|
|
11
|
+
|
|
12
|
+
`);else if(x){let{call:O,isNew:j}=g.add(x),B=j?{index:x.tool_index,id:O.id??`call_${x.tool_index}`,type:"function",function:{name:O.name??"",arguments:x.delta}}:{index:x.tool_index,function:{arguments:x.delta}};t.write(`data: ${JSON.stringify(F(u,c,{tool_calls:[B]},null))}
|
|
13
|
+
|
|
14
|
+
`)}else if(m.type==="error"){t.write(`data: ${JSON.stringify({error:m})}
|
|
15
|
+
|
|
16
|
+
`),t.end();return}}let S=it(W(r)),M=K(_,g.size+S.length,T);if(M){t.write(`data: ${JSON.stringify({error:{type:"urun_error",code:"tool_call_parser_missing",message:D(d,M)}})}
|
|
17
|
+
|
|
18
|
+
`),t.end();return}g.size===0&&S.length>0&&t.write(`data: ${JSON.stringify(F(u,c,{tool_calls:S},null))}
|
|
19
|
+
|
|
20
|
+
`);let N=g.size>0||S.length>0;t.write(`data: ${JSON.stringify(F(u,c,{},N?"tool_calls":"stop"))}
|
|
21
|
+
|
|
22
|
+
`),t.write(`data: [DONE]
|
|
23
|
+
|
|
24
|
+
`),t.end();return}let A="",f="",I=[],q=new z;for await(let r of o.track(v,d)){I.push(r),r.type==="response.output_text.delta"&&typeof r.delta=="string"&&(A+=r.delta),r.type==="response.reasoning_text.delta"&&typeof r.delta=="string"&&(f+=r.delta);let g=Z(r);if(g&&q.add(g),r.type==="error"){w(t,502,JSON.stringify(r),"upstream_error");return}}let P=W(I),s=it(P),C=s.length>0?s:it({output:q.items()}),R=K(_,C.length,A);if(R){w(t,502,D(d,R),"upstream_error");return}let b=C.map(({index:r,...g})=>g),E={role:"assistant",content:A||null},$=f||_t(P);$&&(E.reasoning_content=$),b.length>0&&(E.tool_calls=b),J(t,200,{id:u,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:c,choices:[{index:0,message:E,finish_reason:b.length>0?"tool_calls":"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}function $t(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(n=>n.type==="text").map(n=>String(n.text??"")).join(""):""}var tt=class extends Error{};function rt(e){return new tt(`unsupported anthropic content block type "${e}" \u2014 the proxy translates text, tool_use and tool_result blocks`)}function Mt(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 Ct(e){if(e==null)return;let n=e.type;if(n==="auto")return"auto";if(n==="none")return"none";if(n==="any")return"required";if(n==="tool")return{type:"function",name:e.name};throw new tt(`unsupported anthropic tool_choice type ${JSON.stringify(String(n))} \u2014 the proxy maps auto, none, any and tool`)}function Tt(e){if(typeof e=="string")return e;if(e==null)return"";if(!Array.isArray(e))throw rt(typeof e);let n="";for(let t of e){let o=String(t.type??"");if(o!=="text")throw rt(`tool_result > ${o}`);n+=String(t.text??"")}return n}function Nt(e){let{role:n,content:t}=e;if(typeof t=="string")return[{role:n,content:t}];if(t==null)return[];if(!Array.isArray(t))throw rt(typeof t);let o=[],a="",c=()=>{a&&(o.push({role:n,content:a}),a="")};for(let u of t){let i=String(u.type??"");if(i==="text")a+=String(u.text??"");else if(i==="tool_use")c(),o.push({type:"function_call",call_id:u.id,name:u.name,arguments:JSON.stringify(u.input??{})});else if(i==="tool_result")c(),o.push({type:"function_call_output",call_id:u.tool_use_id,output:Tt(u.content)});else{if(i==="thinking"||i==="redacted_thinking")continue;throw rt(i)}}return c(),o}function at(e){return Q(e).map((n,t)=>{let o;try{o=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:o}})}async function Bt(e,n,t,o){let a=e.messages;if(!Array.isArray(a)){w(t,400,"messages requires a messages array");return}let c=String(e.model??"urun"),u=`msg_${Math.random().toString(36).slice(2,14)}`,i=[],d;try{e.system&&i.push({role:"system",content:$t(e.system)});for(let r of a)i.push(...Nt(r));d=Ct(e.tool_choice)}catch(r){if(r instanceof tt){w(t,400,r.message);return}throw r}let _=dt(e);o.model(_);let v=Array.isArray(e.tools)&&e.tools.length>0,A;try{A=await n.createResponse({model:e.model,input:i,stream:!0,tools:Mt(e.tools),tool_choice:d,temperature:e.temperature,max_output_tokens:e.max_tokens})}catch(r){if(r instanceof V){pt(t,"anthropic",r);return}throw r}let f=(r,g)=>{t.write(`event: ${r}
|
|
25
|
+
data: ${JSON.stringify({type:r,...g})}
|
|
26
|
+
|
|
27
|
+
`)};if(e.stream===!0){let r=o.track(A,_);ct(t),f("message_start",{message:{id:u,type:"message",role:"assistant",content:[],model:c,stop_reason:null,usage:{input_tokens:0,output_tokens:0}}});let g=0,T="",S=0,M="none",N=()=>M,m=-1,x=-1,O=new z,j=[],B=()=>{M!=="none"&&(M="none",f("content_block_stop",{index:m}))},y=(l,k)=>{B(),M=l,m=S++,f("content_block_start",{index:m,content_block:k})};for await(let l of r){j.push(l);let k=Z(l);if(l.type==="response.reasoning_text.delta"&&typeof l.delta=="string")N()!=="thinking"&&y("thinking",{type:"thinking",thinking:""}),f("content_block_delta",{index:m,delta:{type:"thinking_delta",thinking:l.delta}});else if(l.type==="response.output_text.delta"&&typeof l.delta=="string")N()!=="text"&&y("text",{type:"text",text:""}),g+=1,T+=l.delta,f("content_block_delta",{index:m,delta:{type:"text_delta",text:l.delta}});else if(k){let{call:X}=O.add(k);(N()!=="tool"||k.tool_index!==x)&&(x=k.tool_index,y("tool",{type:"tool_use",id:X.id??`call_${k.tool_index}`,name:X.name??"",input:{}})),k.delta&&f("content_block_delta",{index:m,delta:{type:"input_json_delta",partial_json:k.delta}})}else if(l.type==="error"){f("error",{error:{type:"api_error",message:JSON.stringify(l)}}),t.end();return}}let L=W(j),H=Q(L),U=K(v,O.size+H.length,T);if(U){f("error",{error:{type:"api_error",message:D(_,U)}}),t.end();return}B();let p=[];if(O.size===0)try{p=at(L)}catch(l){f("error",{error:{type:"api_error",message:String(l instanceof Error?l.message:l)}}),t.end();return}S===0&&p.length===0&&(y("text",{type:"text",text:""}),B()),p.forEach(l=>{let k=S++;f("content_block_start",{index:k,content_block:{...l,input:{}}}),f("content_block_delta",{index:k,delta:{type:"input_json_delta",partial_json:JSON.stringify(l.input??{})}}),f("content_block_stop",{index:k})});let h=O.size>0||p.length>0;f("message_delta",{delta:{stop_reason:h?"tool_use":"end_turn"},usage:{output_tokens:g}}),f("message_stop",{}),t.end();return}let I="",q="",P=[],s=new z;for await(let r of o.track(A,_)){P.push(r),r.type==="response.output_text.delta"&&typeof r.delta=="string"&&(I+=r.delta),r.type==="response.reasoning_text.delta"&&typeof r.delta=="string"&&(q+=r.delta);let g=Z(r);if(g&&s.add(g),r.type==="error"){w(t,502,JSON.stringify(r),"upstream_error");return}}let C=W(P),R;try{R=at(C),R.length===0&&s.size>0&&(R=at({output:s.items()}))}catch(r){w(t,502,String(r instanceof Error?r.message:r),"upstream_error");return}let b=K(v,R.length,I);if(b){w(t,502,D(_,b),"upstream_error");return}let E=[],$=q||_t(C);$&&E.push({type:"thinking",thinking:$}),(I||R.length===0)&&E.push({type:"text",text:I}),E.push(...R),J(t,200,{id:u,type:"message",role:"assistant",content:E,model:c,stop_reason:R.length>0?"tool_use":"end_turn",usage:{input_tokens:0,output_tokens:0}})}function zt(e){let{clients:n,apiKey:t,identity:o}=e,a=new lt,c=new ut;return yt((u,i)=>{(async()=>{let d=new URL(u.url??"/","http://localhost");if(u.method==="GET"&&d.pathname==="/healthz"){J(i,200,{ok:!0});return}if(u.method==="GET"&&d.pathname==="/stats"){J(i,200,o?{identity:o,...c.snapshot()}:c.snapshot());return}if(t&&(u.headers.authorization??"")!==`Bearer ${t}`){w(i,401,"invalid local proxy api key","authentication_error");return}if(u.method==="GET"&&d.pathname==="/v1/models"){J(i,200,await n.listModels());return}if(u.method!=="POST"){w(i,404,`no route for ${u.method} ${d.pathname}`);return}let _;try{_=await wt(u)}catch(A){if(A instanceof nt){w(i,413,A.message,"request_too_large");return}w(i,400,"request body is not valid JSON");return}let v=Buffer.byteLength(JSON.stringify(_));if(d.pathname==="/v1/responses"){c.request("responses",v,v),await Et(_,n,a,i,c);return}if(d.pathname==="/v1/chat/completions"){c.request("chat_completions",v,v),await bt(_,n,i,c);return}if(d.pathname==="/v1/messages"){c.request("messages",v,v),await Bt(_,n,i,c);return}w(i,404,`no route for POST ${d.pathname}`)})().catch(d=>{i.headersSent?i.end():w(i,500,String(d),"proxy_error")})})}export{zt as a};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var D=Object.create;var f=Object.defineProperty;var
|
|
1
|
+
"use strict";var D=Object.create;var f=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,H=Object.prototype.hasOwnProperty;var N=(n,e)=>{for(var t in e)f(n,t,{get:e[t],enumerable:!0})},S=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of j(e))!H.call(n,o)&&o!==t&&f(n,o,{get:()=>e[o],enumerable:!(r=$(e,o))||r.enumerable});return n};var v=(n,e,t)=>(t=n!=null?D(q(n)):{},S(e||!n||!n.__esModule?f(t,"default",{value:n,enumerable:!0}):t,n)),W=n=>S(f({},"__esModule",{value:!0}),n);var Q={};N(Q,{SUPPORTED_REALTIME_CLIENT_EVENTS:()=>h,SUPPORTED_RESPONSES_EVENTS:()=>b,UrunRealtime:()=>y,UrunResponses:()=>w,isSupportedClientEvent:()=>P,isSupportedResponsesEvent:()=>O,listModels:()=>L,nodeAudioBackend:()=>x,toErrorEvent:()=>p,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),n.tool_choice!==void 0&&(r.tool_choice=n.tool_choice),typeof n.temperature=="number"&&(r.temperature=n.temperature),typeof n.max_output_tokens=="number"&&(r.max_output_tokens=n.max_output_tokens),r}function p(n){if(n instanceof Error)return{type:"error",error:{type:"urun_error",code:n.name||null,message:n.message}};if(n&&typeof n=="object"&&n.t==="error"){let e=n,t=e.body??{};return{type:"error",error:{type:"urun_error",code:e.code??null,message:t.message??"unknown error"}}}return{type:"error",error:{type:"urun_error",code:null,message:String(n)}}}var F="llm-resp";async function*_(n,e){let t=`${F}:${e}`,r=`resp_${e}`;yield{type:"response.created",response:{id:r,status:"in_progress"}};let o=new Map;for await(let s of n.stream(t).messages()){let a=s;if(a.t==="delta"){if(typeof a.delta=="string"&&(yield{type:"response.output_text.delta",item_id:r,delta:a.delta}),typeof a.reasoning=="string"&&(yield{type:"response.reasoning_text.delta",item_id:r,delta:a.reasoning}),Array.isArray(a.tool_calls))for(let u of a.tool_calls){let i=typeof u.index=="number"?u.index:0,c=o.get(i)??{};u.id&&(c.id=u.id),u.function?.name&&(c.name=u.function.name),o.set(i,c),yield{type:"response.function_call_arguments.delta",item_id:`fc_${e}_${i}`,tool_index:i,call_id:c.id,name:c.name,delta:u.function?.arguments??""}}}else if(a.t==="response"){yield{type:"response.completed",response:{id:r,status:"completed",...a.body}};return}else if(a.t==="error"){yield p(a);return}}}var K="llm",l=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),_(this.session,t)}sendResponseCreate(e,t,r){let o=E(e,t,r,this.consumerId);return this.write(o),_(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,a=new Int16Array(0);return{track:t,onData:u=>{let i=new Int16Array(a.length+u.length);i.set(a,0),i.set(u,a.length);let c=0;for(;i.length-c>=m;){let g=i.subarray(c,c+m);c+=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)}a=i.slice(c)}}},createSink:t=>{let r={onframe:null};return t.onReceiveRtp.subscribe(s=>{let a;try{a=e.decode(s.payload)}catch{return}let u=new Int16Array(a.length/2);for(let i=0;i<u.length;i++)u[i]=a.readInt16LE(i*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 l(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,a=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=i=>{i!=null&&(clearTimeout(a),s?.(),r(i))};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(p(o))}})();return}case"input_audio_buffer.append":this.audio?.appendInputAudio(e.audio);return;case"input_audio_buffer.commit":case"input_audio_buffer.clear":return;case"response.cancel":return;default:return}}async drain(){this.active&&await this.active}};var T=0;function G(){return T+=1,`req_${Date.now().toString(36)}_${T.toString(36)}`}var w=class{transport;constructor(e){this.transport=new l(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 h=["session.update","conversation.item.create","response.create","response.cancel","input_audio_buffer.append","input_audio_buffer.commit","input_audio_buffer.clear"],b=["response.created","response.output_text.delta","response.output_item.added","response.function_call_arguments.delta","response.image_generation_call.partial_image","response.completed","error"];function P(n){return h.includes(n)}function O(n){return b.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,5 +1,5 @@
|
|
|
1
|
-
import { a as UrunSessionLike, L as LaneMessage } from './ResponsesClient-
|
|
2
|
-
export { U as UrunResponses } from './ResponsesClient-
|
|
1
|
+
import { a as UrunSessionLike, L as LaneMessage } from './ResponsesClient-DF39QXq1.cjs';
|
|
2
|
+
export { U as UrunResponses } from './ResponsesClient-DF39QXq1.cjs';
|
|
3
3
|
export { RealtimeClientEvent, RealtimeServerEvent } from 'openai/resources/beta/realtime/realtime';
|
|
4
4
|
export { ResponseStreamEvent } from 'openai/resources/responses/responses';
|
|
5
5
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as UrunSessionLike, L as LaneMessage } from './ResponsesClient-
|
|
2
|
-
export { U as UrunResponses } from './ResponsesClient-
|
|
1
|
+
import { a as UrunSessionLike, L as LaneMessage } from './ResponsesClient-DF39QXq1.js';
|
|
2
|
+
export { U as UrunResponses } from './ResponsesClient-DF39QXq1.js';
|
|
3
3
|
export { RealtimeClientEvent, RealtimeServerEvent } from 'openai/resources/beta/realtime/realtime';
|
|
4
4
|
export { ResponseStreamEvent } from 'openai/resources/responses/responses';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as _}from"./chunk-OLE2YJO3.js";import{a as f,b as v,c as g}from"./chunk-
|
|
1
|
+
import{b as _}from"./chunk-OLE2YJO3.js";import{a as f,b as v,c as g}from"./chunk-DYBS3NLC.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};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var xe=Object.create;var M=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var Ae=Object.getPrototypeOf,Se=Object.prototype.hasOwnProperty;var Ee=(t,e)=>{for(var n in e)M(t,n,{get:e[n],enumerable:!0})},ee=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of be(e))!Se.call(t,r)&&r!==n&&M(t,r,{get:()=>e[r],enumerable:!(o=ke(e,r))||o.enumerable});return t};var te=(t,e,n)=>(n=t!=null?xe(Ae(t)):{},ee(e||!t||!t.__esModule?M(n,"default",{value:t,enumerable:!0}):n,t)),Re=t=>ee(M({},"__esModule",{value:!0}),t);var tt={};Ee(tt,{SessionPool:()=>O,URUN_API:()=>Y,coalesceSameRole:()=>he,createFileDiagnosticSink:()=>me,createUrunExtension:()=>_e,default:()=>et,makeSessionFactory:()=>fe,makeStreamSimple:()=>we,piDiagnosticLogPath:()=>ge,resolveSessionEnv:()=>de,toResponsesInput:()=>ye});module.exports=Re(tt);var Te=()=>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,_=Te();var ce=require("@earendil-works/pi-ai"),R=require("fs"),ue=te(require("os"),1),j=require("path");function ne(t,e,n,o){let r=t.response??{},l={request_id:n,consumer_id:o,stream:!0,kind:"chat",messages:e};return typeof r.instructions=="string"&&(l.instructions=r.instructions),Array.isArray(r.modalities)&&(l.modalities=r.modalities),typeof r.temperature=="number"&&(l.temperature=r.temperature),typeof r.max_output_tokens=="number"&&(l.max_output_tokens=r.max_output_tokens),r.tools!==void 0&&(l.tools=r.tools),l}function oe(t,e,n){let o={request_id:e,consumer_id:n,stream:!!t.stream,kind:"responses",input:t.input};return t.model&&(o.model=t.model),t.tools!==void 0&&(o.tools=t.tools),t.tool_choice!==void 0&&(o.tool_choice=t.tool_choice),typeof t.temperature=="number"&&(o.temperature=t.temperature),typeof t.max_output_tokens=="number"&&(o.max_output_tokens=t.max_output_tokens),o}function re(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 Ue="llm-resp";async function*G(t,e){let n=`${Ue}:${e}`,o=`resp_${e}`;yield{type:"response.created",response:{id:o,status:"in_progress"}};let r=new Map;for await(let l of t.stream(n).messages()){let i=l;if(i.t==="delta"){if(typeof i.delta=="string"&&(yield{type:"response.output_text.delta",item_id:o,delta:i.delta}),typeof i.reasoning=="string"&&(yield{type:"response.reasoning_text.delta",item_id:o,delta:i.reasoning}),Array.isArray(i.tool_calls))for(let p of i.tool_calls){let m=typeof p.index=="number"?p.index:0,a=r.get(m)??{};p.id&&(a.id=p.id),p.function?.name&&(a.name=p.function.name),r.set(m,a),yield{type:"response.function_call_arguments.delta",item_id:`fc_${e}_${m}`,tool_index:m,call_id:a.id,name:a.name,delta:p.function?.arguments??""}}}else if(i.t==="response"){yield{type:"response.completed",response:{id:o,status:"completed",...i.body}};return}else if(i.t==="error"){yield re(i);return}}}var Ie="llm",N=class{constructor(e){this.session=e}session;get consumerId(){return this.session.consumerId}write(e){this.session.doc(Ie).set({requests:{[e.request_id]:{payload:e,consumer_id:e.consumer_id,stream:e.stream}}})}sendResponses(e,n){let o=oe(e,n,this.consumerId);return this.write(o),G(this.session,n)}sendResponseCreate(e,n,o){let r=ne(e,n,o,this.consumerId);return this.write(r),G(this.session,o)}};var se=0;function Pe(){return se+=1,`req_${Date.now().toString(36)}_${se.toString(36)}`}var D=class{transport;constructor(e){this.transport=new N(e)}responses={create:async e=>{let n=Pe(),o=this.transport.sendResponses(e,n);return Object.assign((async function*(){yield*o})(),{requestId:n})}}};var B="https://api.urun.sh/v1";async function ie(t){let e=t.fetchImpl??fetch,n=`${t.apiUrl.replace(/\/+$/,"")}/apps`,o=await e(n,{headers:{Authorization:`Bearer ${t.apiKey}`,Accept:"application/json"}});if(!o.ok)throw new Error(`org apps listing failed: GET ${n} \u2192 ${o.status}`);let r=await o.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 ae(t){let e=await ie(t),n=e.filter(o=>o.function_name===t.fnName&&o.deployment_status==="active").map(o=>o.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 Y="urun-serve",Ce="serve",Le=131072,$e=16384,le=3,Me=42e4,Ne=6e4,De=15e3;function Oe(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()||B,fnName:(t.URUN_FUNCTION??"").trim()||Ce}}function de(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 o=(t.URUN_JWT??"").trim();if(o)return{baseUrl:e,orgId:n,auth:{lane:"jwt",jwt:o}};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 l=(t.URUN_GATEWAY_URL??"").trim()||void 0;return{baseUrl:e,orgId:n,auth:{lane:"api-key",apiKey:r,gatewayUrl:l}}}function me(t){let e=null;return n=>{e===null&&((0,R.mkdirSync)((0,j.dirname)(t),{recursive:!0}),e=(0,R.openSync)(t,"a"));let o=n.detail?` ${JSON.stringify(n.detail)}`:"";(0,R.writeSync)(e,`${new Date().toISOString()} [${n.level}] [urun] ${n.message}${o}
|
|
2
|
+
`)}}function ge(t=ue.default.homedir()){return(0,j.join)(t,".urun","logs","pi-extension.log")}function fe(t){let e=me(ge());return async(n,o,r)=>{let{baseUrl:l,orgId:i,auth:p}=de(n),{App:m,createClientToken:a}=await t(),v=(p.lane==="jwt"?m(o,{baseUrl:l,orgId:i,jwt:p.jwt,diagnosticSink:e}):m(o,{baseUrl:l,orgId:i,diagnosticSink:e,getAccessToken:async()=>(await a(p.apiKey,{baseUrl:p.gatewayUrl,expiresIn:300,allowedFunctions:[`${o}/${r}`]})).token}))[r];if(typeof v!="function")throw new Error(`urun pi extension: app "${o}" has no function "${r}"`);let h=v(),T=h.connect;return typeof T=="function"&&await T.call(h),h}}var je=fe(async()=>{let{createRequire:t}=await import("module"),e=t(_);if(typeof globalThis.RTCPeerConnection>"u")try{e.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.')}return e("@urun-sh/core")});function Fe(t){try{Promise.resolve(t.close?.()).catch(()=>{})}catch{}}var O=class{constructor(e,n,o){this.open=e;this.env=n;this.fnName=o}open;env;fnName;pool=new Map;acquire(e){let n=this.pool.get(e);if(!n){let o=Promise.resolve(this.open(this.env,e,this.fnName)).then(r=>({session:r,responses:new D(r)}));n=o,this.pool.set(e,o),o.catch(()=>{this.pool.get(e)===o&&this.pool.delete(e)})}return n}evict(e){let n=this.pool.get(e);n&&(this.pool.delete(e),n.then(o=>Fe(o.session),()=>{}))}closeAll(){for(let e of[...this.pool.keys()])this.evict(e)}};function ye(t){let e=[];t.systemPrompt&&e.push({role:"system",content:t.systemPrompt});for(let n of t.messages){if(n.role==="toolResult"){e.push({type:"function_call_output",call_id:n.toolCallId,output:qe(n.content)});continue}if(n.role==="assistant"&&Array.isArray(n.content)){let r="",l=()=>{r&&(e.push({role:"assistant",content:r}),r="")};for(let i of n.content)if(i.type==="text")r+=String(i.text??"");else if(i.type==="toolCall")l(),e.push({type:"function_call",call_id:String(i.id??""),name:String(i.name??""),arguments:JSON.stringify(i.arguments??{})});else{if(i.type==="thinking")continue;throw new Error(`urun pi extension: unsupported assistant content part "${String(i.type)}"`)}l();continue}let o=n.role==="assistant"?"assistant":"user";e.push({role:o,content:Ke(n.content)})}return he(e)}function he(t){let e=[];for(let n of t){let o=e[e.length-1];o&&"role"in o&&"role"in n&&o.role===n.role?o.content=[o.content,n.content].filter(r=>r.length>0).join(`
|
|
2
3
|
|
|
3
|
-
`):
|
|
4
|
+
`):e.push({...n})}return e}function Ke(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>e&&typeof e=="object"&&"text"in e?String(e.text):"").join(""):""}function qe(t){if(typeof t=="string")return t;if(!Array.isArray(t))return"";let e="";for(let n of t){let o=String(n.type??"");if(o!=="text")throw new Error(`urun pi extension: unsupported toolResult content part "${o}" \u2014 the serve lane carries text tool results only`);e+=String(n.text??"")}return e}function We(t){if(!(!Array.isArray(t)||t.length===0))return t.map(e=>({type:"function",name:e.name,description:e.description,parameters:e.parameters}))}function pe(t,e){if(!e.trim())return{};try{return JSON.parse(e)}catch{throw new Error(`uRun serve error: tool call "${t}" arguments are not valid JSON: ${e}`)}}function Je(t){let e=t?.output;return Array.isArray(e)?e.filter(n=>n.type==="function_call"):[]}function Ge(t){let e=t?.output;if(!Array.isArray(e))return"";let n="";for(let o of e)if(!(o.type!=="reasoning"||!Array.isArray(o.content)))for(let r of o.content)r.type==="reasoning_text"&&(n+=String(r.text??""));return n}var Be=["<tool_call>","<function="];function Ye(t,e){let n=Be.find(o=>e.includes(o));if(n)return new Error(`serving row emitted a prose tool call (literal ${JSON.stringify(n)} in the assistant text) for a request that carried tools, and no structured tool_calls arrived \u2014 the tool-call parser is not configured on the model row "${t}" (see catalog parser_defaults)`)}function He(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 Xe(t){return new Promise(e=>setTimeout(e,t))}function ze(t,e,n,o){return new Promise((r,l)=>{let i=!1,p=s=>{i||(i=!0,clearTimeout(m),o?.removeEventListener("abort",a),s())},m=setTimeout(()=>p(()=>l(n())),e),a=()=>p(()=>l(new Error("aborted")));if(o?.aborted){a();return}o?.addEventListener("abort",a,{once:!0}),Promise.resolve(t).then(s=>p(()=>r(s)),s=>p(()=>l(s)))})}async function*Qe(t,e){let n=t[Symbol.asyncIterator](),o,r=new Promise((l,i)=>{o=()=>i(new Error("aborted")),e.addEventListener("abort",o,{once:!0})});try{for(;;){if(e.aborted)throw new Error("aborted");let l=await Promise.race([n.next(),r]);if(l.done)return;yield l.value}}finally{o&&e.removeEventListener("abort",o),n.return?.(void 0)}}function Ve(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 we(t,e={},n){let o=e.connectDeadlineMs??Me,r=e.stallTimeoutMs??Ne,l=e.phaseHeartbeatMs??De;return(i,p,m)=>{let a=(0,ce.createAssistantMessageEventStream)(),s={role:"assistant",content:[],api:i.api,provider:i.provider,model:i.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()},v=new AbortController,h=m?.signal,T=!1,P=()=>{T=!0,v.abort()};h&&(h.aborted?P():h.addEventListener("abort",P,{once:!0}));let F=!1,S,H=()=>{S&&clearTimeout(S),S=setTimeout(()=>{F=!0,v.abort()},r)},K=()=>{S&&clearTimeout(S),S=void 0},x=null,k=null,f=null,X="",C=!1,q=()=>{if(!k)return;let d=k;k=null,a.push({type:"thinking_end",contentIndex:s.content.indexOf(d),content:d.thinking,partial:s})},z=()=>{if(!x)return;let d=x;x=null,a.push({type:"text_end",contentIndex:s.content.indexOf(d),content:d.text,partial:s})},W=()=>{if(!f)return;let{call:d,args:y,contentIndex:b}=f;f=null,d.arguments=pe(d.name,y),a.push({type:"toolcall_end",contentIndex:b,toolCall:d,partial:s})},ve=d=>{let y={type:"toolCall",id:String(d.call_id??d.id??`call_${s.content.length}`),name:String(d.name??""),arguments:{}};s.content.push(y);let b=s.content.length-1;a.push({type:"toolcall_start",contentIndex:b,partial:s});let U=typeof d.arguments=="string"?d.arguments:"";U&&a.push({type:"toolcall_delta",contentIndex:b,delta:U,partial:s}),y.arguments=pe(y.name,U),a.push({type:"toolcall_end",contentIndex:b,toolCall:y,partial:s})};return(async()=>{a.push({type:"start",partial:s});let d=!1,y,b=()=>{y&&clearInterval(y),y=void 0},U=Date.now();y=setInterval(()=>{let A=Math.round((Date.now()-U)/1e3);Ve(n,`uRun: still opening the "${i.id}" session\u2026 (${A}s \u2014 serve apps scale to zero, first turn can cold-start ~6min)`)},l);try{let{responses:A}=await ze(t.acquire(i.id),o,()=>new Error(`uRun session for "${i.id}" did not connect within ${Math.round(o/1e3)}s \u2014 likely cold-starting (scaled to zero) or queued behind capacity. Retry shortly.`),v.signal);b();let J=ye(p),L,$;for(let u=1;u<=le;u++)try{let w=await A.responses.create({model:i.id,input:J,stream:!0,tools:We(p.tools),max_output_tokens:i.maxTokens});H();for await(let I of Qe(w,v.signal)){H();let g=I;if(g.type==="response.output_text.delta"){let c=typeof g.delta=="string"?g.delta:"";c&&(C=!0,q(),W(),x||(x={type:"text",text:""},s.content.push(x),a.push({type:"text_start",contentIndex:s.content.length-1,partial:s})),x.text+=c,X+=c,a.push({type:"text_delta",contentIndex:s.content.indexOf(x),delta:c,partial:s}))}else if(g.type==="response.reasoning_text.delta"){let c=typeof g.delta=="string"?g.delta:"";c&&(C=!0,k||(k={type:"thinking",thinking:""},s.content.push(k),a.push({type:"thinking_start",contentIndex:s.content.length-1,partial:s})),k.thinking+=c,a.push({type:"thinking_delta",contentIndex:s.content.indexOf(k),delta:c,partial:s}))}else if(g.type==="response.function_call_arguments.delta"&&typeof g.tool_index=="number"){let c=g;if(C=!0,q(),z(),!f||f.toolIndex!==c.tool_index){W();let Z={type:"toolCall",id:c.call_id??`call_${c.tool_index}`,name:c.name??"",arguments:{}};s.content.push(Z),f={call:Z,args:"",contentIndex:s.content.length-1,toolIndex:c.tool_index},a.push({type:"toolcall_start",contentIndex:f.contentIndex,partial:s})}c.call_id&&(f.call.id=c.call_id),c.name&&(f.call.name=c.name);let E=typeof c.delta=="string"?c.delta:"";E&&(f.args+=E,a.push({type:"toolcall_delta",contentIndex:f.contentIndex,delta:E,partial:s}))}else if(g.type==="response.completed"){L=g.response;break}else if(g.type==="error"){let c=g.error,E=new Error(`uRun serve error: ${c?.message??"unknown error"}`);throw E.code=c?.code??null,E}}$=void 0;break}catch(w){if($=w,v.signal.aborted)throw w;if(u<le&&He(w)&&!C){await Xe(u*500);continue}throw w}if($)throw $;if(K(),q(),z(),W(),!s.content.some(u=>u.type==="toolCall"))for(let u of Je(L))ve(u);if(!s.content.some(u=>u.type==="thinking")){let u=Ge(L);if(u){let w={type:"thinking",thinking:""};s.content.push(w);let I=s.content.length-1;a.push({type:"thinking_start",contentIndex:I,partial:s}),w.thinking=u,a.push({type:"thinking_delta",contentIndex:I,delta:u,partial:s}),a.push({type:"thinking_end",contentIndex:I,content:u,partial:s})}}let Q=s.content.filter(u=>u.type==="toolCall").length;if((p.tools?.length??0)>0&&Q===0){let u=Ye(i.id,X);if(u)throw u}let V=Q>0?"toolUse":L?.status==="incomplete"?"length":"stop";s.stopReason=V,a.push({type:"done",reason:V,message:s}),a.end(s)}catch(A){if(d=!0,K(),T||h?.aborted&&!F)s.stopReason="aborted",s.errorMessage="aborted by user",a.push({type:"error",reason:"aborted",error:s});else{let J=F?`uRun stream stalled \u2014 no output for ${Math.round(r/1e3)}s; the model may be hung. Retry, or Ctrl-C to abort.`:A instanceof Error?A.message:String(A);s.stopReason="error",s.errorMessage=J,a.push({type:"error",reason:"error",error:s})}a.end(s)}finally{K(),b(),h&&h.removeEventListener("abort",P),d&&t.evict(i.id)}})(),a}}function Ze(t){return{id:t,name:`uRun ${t}`,api:Y,reasoning:!0,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:Le,maxTokens:$e}}function _e(t={}){return async e=>{let n=t.env??process.env,{apiKey:o,apiUrl:r,fnName:l}=Oe(n),i=await ae({apiUrl:r,apiKey:o,fnName:l,fetchImpl:t.fetchImpl}),p=new O(t.openSession??je,n,l);e.on("session_shutdown",()=>p.closeAll());let m={name:"uRun",api:Y,baseUrl:"urun://session",apiKey:"$URUN_API_KEY",models:i.map(Ze),streamSimple:we(p,t.timing??{},e)};e.registerProvider("urun",m)}}var et=_e();0&&(module.exports={SessionPool,URUN_API,coalesceSameRole,createFileDiagnosticSink,createUrunExtension,makeSessionFactory,makeStreamSimple,piDiagnosticLogPath,resolveSessionEnv,toResponsesInput});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
2
|
import { Api, Model, Context, SimpleStreamOptions, AssistantMessageEventStream } from '@earendil-works/pi-ai';
|
|
3
|
-
import { a as UrunSessionLike, U as UrunResponses } from '../ResponsesClient-
|
|
3
|
+
import { a as UrunSessionLike, U as UrunResponses } from '../ResponsesClient-DF39QXq1.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Pi coding-agent extension: register the `urun` model provider, with one pi
|
|
@@ -40,13 +40,16 @@ import { a as UrunSessionLike, U as UrunResponses } from '../ResponsesClient-CQ3
|
|
|
40
40
|
* empty provider.
|
|
41
41
|
* 2. `streamSimple` (pi's custom-API hook, keyed by `api: "urun-serve"`):
|
|
42
42
|
* opens ONE uRun session per app slug, POOLED and reused across turns,
|
|
43
|
-
* translates pi's Context into Responses `input` items
|
|
44
|
-
*
|
|
45
|
-
* `
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
43
|
+
* translates pi's Context into Responses `input` items (tool loop
|
|
44
|
+
* included: assistant `toolCall` content → `function_call` items,
|
|
45
|
+
* `toolResult` turns → `function_call_output` items), forwards
|
|
46
|
+
* `context.tools` upstream, drives
|
|
47
|
+
* `UrunResponses.responses.create({stream: true})`, and maps the lane's
|
|
48
|
+
* decoded events onto pi-ai's REAL AssistantMessageEvent union:
|
|
49
|
+
* output_text → text_*, reasoning_text → thinking_*, function-call
|
|
50
|
+
* argument fragments → toolcall_* (stopReason "toolUse" ends a
|
|
51
|
+
* tool-calling turn, which is what makes pi's agent loop execute the
|
|
52
|
+
* tools and feed results back).
|
|
50
53
|
* 3. ABORT/CANCEL (loud contract): the Responses lane has NO request-cancel
|
|
51
54
|
* primitive (`SdkTransport.sendResponses` writes an envelope and the
|
|
52
55
|
* decode loop just reads the reply lane), so Ctrl-C / the stall watchdog
|
|
@@ -117,6 +120,13 @@ declare function resolveSessionEnv(env: NodeJS.ProcessEnv): {
|
|
|
117
120
|
interface SessionFactory {
|
|
118
121
|
(env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<UrunSessionLike> | UrunSessionLike;
|
|
119
122
|
}
|
|
123
|
+
/** The structured diagnostic shape core's transports emit (typed locally). */
|
|
124
|
+
interface CoreDiagnosticLike {
|
|
125
|
+
level: string;
|
|
126
|
+
kind: string;
|
|
127
|
+
message: string;
|
|
128
|
+
detail?: Record<string, unknown>;
|
|
129
|
+
}
|
|
120
130
|
/**
|
|
121
131
|
* The subset of `@urun-sh/core` a session factory needs — typed locally so
|
|
122
132
|
* core stays OUT of this module's static import graph (the npm lane resolves
|
|
@@ -128,6 +138,7 @@ interface CoreModuleLike {
|
|
|
128
138
|
orgId: string;
|
|
129
139
|
jwt?: string;
|
|
130
140
|
getAccessToken?: () => Promise<string>;
|
|
141
|
+
diagnosticSink?: (diagnostic: CoreDiagnosticLike) => void;
|
|
131
142
|
}) => Record<string, (args?: Record<string, unknown>) => UrunSessionLike>;
|
|
132
143
|
createClientToken: (apiKey: string, opts: {
|
|
133
144
|
baseUrl?: string;
|
|
@@ -149,6 +160,16 @@ interface CoreModuleLike {
|
|
|
149
160
|
* self-contained bundle INLINES core (and, through core's own dynamic
|
|
150
161
|
* werift import, the WebRTC backend) — that lane has no node_modules.
|
|
151
162
|
*/
|
|
163
|
+
/**
|
|
164
|
+
* A diagnostic sink appending formatted lines to `path` — SYNCHRONOUS writes
|
|
165
|
+
* (a crashing pi must still leave the lines on disk), lazy directory
|
|
166
|
+
* creation, one open descriptor per sink. An open/write failure THROWS: core's
|
|
167
|
+
* `_emitDiagnostic` catches it, complains once on the console, and keeps the
|
|
168
|
+
* structured event flowing — loud once, never TUI spam, never silent.
|
|
169
|
+
*/
|
|
170
|
+
declare function createFileDiagnosticSink(path: string): (diagnostic: CoreDiagnosticLike) => void;
|
|
171
|
+
/** Where the pi lane's quiet diagnostics land (the compat log convention). */
|
|
172
|
+
declare function piDiagnosticLogPath(home?: string): string;
|
|
152
173
|
declare function makeSessionFactory(loadCore: () => Promise<CoreModuleLike> | CoreModuleLike): SessionFactory;
|
|
153
174
|
/** One pooled backhaul: the session plus its Responses client (cli.ts shape). */
|
|
154
175
|
interface PoolEntry {
|
|
@@ -174,22 +195,36 @@ declare class SessionPool {
|
|
|
174
195
|
/** Release everything (pi session_shutdown). */
|
|
175
196
|
closeAll(): void;
|
|
176
197
|
}
|
|
177
|
-
/** A Responses input item
|
|
178
|
-
|
|
198
|
+
/** A Responses input item: role message or function-call round-trip item. */
|
|
199
|
+
type ResponsesInputItem = {
|
|
179
200
|
role: 'system' | 'user' | 'assistant';
|
|
180
201
|
content: string;
|
|
181
|
-
}
|
|
202
|
+
} | {
|
|
203
|
+
type: 'function_call';
|
|
204
|
+
call_id: string;
|
|
205
|
+
name: string;
|
|
206
|
+
arguments: string;
|
|
207
|
+
} | {
|
|
208
|
+
type: 'function_call_output';
|
|
209
|
+
call_id: string;
|
|
210
|
+
output: string;
|
|
211
|
+
};
|
|
182
212
|
/**
|
|
183
|
-
* Pi `Context` -> Responses `input` items
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
213
|
+
* Pi `Context` -> Responses `input` items, in ENCOUNTER ORDER (the tool
|
|
214
|
+
* loop's canonical Responses shapes — the same translation the compat proxy
|
|
215
|
+
* performs):
|
|
216
|
+
* - assistant `toolCall` content → `{type:'function_call', call_id, name,
|
|
217
|
+
* arguments}` (arguments re-serialized: pi stores the PARSED object);
|
|
218
|
+
* - `role:"toolResult"` turns → `{type:'function_call_output', call_id,
|
|
219
|
+
* output}` keyed by pi's `toolCallId`;
|
|
220
|
+
* - assistant `thinking` content is the producing model's internal state —
|
|
221
|
+
* not re-submittable — and is skipped by design (same rule as the proxy);
|
|
222
|
+
* - text runs become role messages where they sit; adjacent same-role
|
|
223
|
+
* messages are coalesced so chat templates that assume strict role
|
|
224
|
+
* alternation never see two turns of one role back-to-back.
|
|
190
225
|
*/
|
|
191
226
|
declare function toResponsesInput(context: Context): ResponsesInputItem[];
|
|
192
|
-
/** Fold consecutive same-role items into one, joining with a blank line. */
|
|
227
|
+
/** Fold consecutive same-role message items into one, joining with a blank line. */
|
|
193
228
|
declare function coalesceSameRole(items: ResponsesInputItem[]): ResponsesInputItem[];
|
|
194
229
|
/** Tunable timeouts (overridable so tests can drive them deterministically). */
|
|
195
230
|
interface StreamTiming {
|
|
@@ -219,4 +254,4 @@ declare function createUrunExtension(opts?: UrunExtensionOptions): (pi: Extensio
|
|
|
219
254
|
/** The pi extension factory (default export — what pi's loader invokes). */
|
|
220
255
|
declare const _default: (pi: ExtensionAPI) => Promise<void>;
|
|
221
256
|
|
|
222
|
-
export { type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, resolveSessionEnv, toResponsesInput };
|
|
257
|
+
export { type CoreDiagnosticLike, type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createFileDiagnosticSink, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, piDiagnosticLogPath, resolveSessionEnv, toResponsesInput };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
2
|
import { Api, Model, Context, SimpleStreamOptions, AssistantMessageEventStream } from '@earendil-works/pi-ai';
|
|
3
|
-
import { a as UrunSessionLike, U as UrunResponses } from '../ResponsesClient-
|
|
3
|
+
import { a as UrunSessionLike, U as UrunResponses } from '../ResponsesClient-DF39QXq1.js';
|
|
4
4
|
|
|
5
5
|
declare const URUN_API: Api;
|
|
6
6
|
|
|
@@ -21,12 +21,20 @@ interface SessionFactory {
|
|
|
21
21
|
(env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<UrunSessionLike> | UrunSessionLike;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
interface CoreDiagnosticLike {
|
|
25
|
+
level: string;
|
|
26
|
+
kind: string;
|
|
27
|
+
message: string;
|
|
28
|
+
detail?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
interface CoreModuleLike {
|
|
25
32
|
App: (id: string, opts: {
|
|
26
33
|
baseUrl: string;
|
|
27
34
|
orgId: string;
|
|
28
35
|
jwt?: string;
|
|
29
36
|
getAccessToken?: () => Promise<string>;
|
|
37
|
+
diagnosticSink?: (diagnostic: CoreDiagnosticLike) => void;
|
|
30
38
|
}) => Record<string, (args?: Record<string, unknown>) => UrunSessionLike>;
|
|
31
39
|
createClientToken: (apiKey: string, opts: {
|
|
32
40
|
baseUrl?: string;
|
|
@@ -37,6 +45,9 @@ interface CoreModuleLike {
|
|
|
37
45
|
}>;
|
|
38
46
|
}
|
|
39
47
|
|
|
48
|
+
declare function createFileDiagnosticSink(path: string): (diagnostic: CoreDiagnosticLike) => void;
|
|
49
|
+
|
|
50
|
+
declare function piDiagnosticLogPath(home?: string): string;
|
|
40
51
|
declare function makeSessionFactory(loadCore: () => Promise<CoreModuleLike> | CoreModuleLike): SessionFactory;
|
|
41
52
|
|
|
42
53
|
interface PoolEntry {
|
|
@@ -57,10 +68,19 @@ declare class SessionPool {
|
|
|
57
68
|
closeAll(): void;
|
|
58
69
|
}
|
|
59
70
|
|
|
60
|
-
|
|
71
|
+
type ResponsesInputItem = {
|
|
61
72
|
role: 'system' | 'user' | 'assistant';
|
|
62
73
|
content: string;
|
|
63
|
-
}
|
|
74
|
+
} | {
|
|
75
|
+
type: 'function_call';
|
|
76
|
+
call_id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
arguments: string;
|
|
79
|
+
} | {
|
|
80
|
+
type: 'function_call_output';
|
|
81
|
+
call_id: string;
|
|
82
|
+
output: string;
|
|
83
|
+
};
|
|
64
84
|
|
|
65
85
|
declare function toResponsesInput(context: Context): ResponsesInputItem[];
|
|
66
86
|
|
|
@@ -85,4 +105,4 @@ declare function createUrunExtension(opts?: UrunExtensionOptions): (pi: Extensio
|
|
|
85
105
|
|
|
86
106
|
declare const _default: (pi: ExtensionAPI) => Promise<void>;
|
|
87
107
|
|
|
88
|
-
export { type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, resolveSessionEnv, toResponsesInput };
|
|
108
|
+
export { type CoreDiagnosticLike, type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createFileDiagnosticSink, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, piDiagnosticLogPath, resolveSessionEnv, toResponsesInput };
|