@urun-sh/openai 0.2.53 → 0.2.55
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-DrccxHTc.d.cts +108 -0
- package/dist/{ResponsesClient-CQ3l8Wft.d.ts → ResponsesClient-DrccxHTc.d.ts} +18 -2
- package/dist/chunk-47ZLHRBM.js +27 -0
- package/dist/{chunk-PS4BLX7J.js → chunk-5CEMLB6H.js} +1 -1
- package/dist/chunk-HQVV5UN5.js +1 -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 +74 -28
- package/dist/pi-extension/index.d.ts +30 -6
- package/dist/pi-extension/index.js +3 -2
- package/dist/pi-extension/standalone.cjs +48 -47
- package/dist/proxy/cli.cjs +33 -22
- package/dist/proxy/cli.js +17 -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/ResponsesClient-CQ3l8Wft.d.cts +0 -62
- package/dist/chunk-FSS2A7IU.js +0 -1
- package/dist/chunk-KJ25VEMG.js +0 -21
|
@@ -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-DrccxHTc.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Pi coding-agent extension: register the `urun` model provider, with one pi
|
|
@@ -40,22 +40,26 @@ 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
|
|
53
|
-
* stop consuming AND evict+
|
|
54
|
-
* WebRTC transport is what stops
|
|
55
|
-
* keeps its session for the next
|
|
56
|
-
* always reopens
|
|
57
|
-
*
|
|
58
|
-
*
|
|
56
|
+
* stop consuming AND evict+END the pooled session (core's own
|
|
57
|
+
* `Session.end()`) — tearing down the WebRTC transport is what stops
|
|
58
|
+
* server-side generation. A clean turn keeps its session for the next
|
|
59
|
+
* turn; a failed/aborted/stalled turn always reopens — and a turn whose
|
|
60
|
+
* session DIED re-homes once and replays (see REHOME_ATTEMPTS).
|
|
61
|
+
* 4. cleanup: pooled sessions are released (core's `Session.end()`) on
|
|
62
|
+
* pi's `session_shutdown` lifecycle event.
|
|
59
63
|
*
|
|
60
64
|
* RUNTIME DEPENDENCY STORY (owner requirement — stated honestly): token
|
|
61
65
|
* streams are named-DATA session streams, i.e. SCTP data channels over
|
|
@@ -115,7 +119,24 @@ declare function resolveSessionEnv(env: NodeJS.ProcessEnv): {
|
|
|
115
119
|
* `@urun-sh/core`.
|
|
116
120
|
*/
|
|
117
121
|
interface SessionFactory {
|
|
118
|
-
(env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<
|
|
122
|
+
(env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<OwnedSession> | OwnedSession;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A session this lane OWNS: core's transport surface plus core's own terminal
|
|
126
|
+
* release, `Session.end()` (the same requirement the compat proxy asserts in
|
|
127
|
+
* `sessionOf`). A session without it could never be released — it would leak
|
|
128
|
+
* the backend session and its capacity lease until the platform's abandonment
|
|
129
|
+
* backstop reclaimed it — so the factory refuses to hand one back.
|
|
130
|
+
*/
|
|
131
|
+
type OwnedSession = UrunSessionLike & {
|
|
132
|
+
end: () => Promise<unknown>;
|
|
133
|
+
};
|
|
134
|
+
/** The structured diagnostic shape core's transports emit (typed locally). */
|
|
135
|
+
interface CoreDiagnosticLike {
|
|
136
|
+
level: string;
|
|
137
|
+
kind: string;
|
|
138
|
+
message: string;
|
|
139
|
+
detail?: Record<string, unknown>;
|
|
119
140
|
}
|
|
120
141
|
/**
|
|
121
142
|
* The subset of `@urun-sh/core` a session factory needs — typed locally so
|
|
@@ -128,6 +149,7 @@ interface CoreModuleLike {
|
|
|
128
149
|
orgId: string;
|
|
129
150
|
jwt?: string;
|
|
130
151
|
getAccessToken?: () => Promise<string>;
|
|
152
|
+
diagnosticSink?: (diagnostic: CoreDiagnosticLike) => void;
|
|
131
153
|
}) => Record<string, (args?: Record<string, unknown>) => UrunSessionLike>;
|
|
132
154
|
createClientToken: (apiKey: string, opts: {
|
|
133
155
|
baseUrl?: string;
|
|
@@ -149,10 +171,20 @@ interface CoreModuleLike {
|
|
|
149
171
|
* self-contained bundle INLINES core (and, through core's own dynamic
|
|
150
172
|
* werift import, the WebRTC backend) — that lane has no node_modules.
|
|
151
173
|
*/
|
|
174
|
+
/**
|
|
175
|
+
* A diagnostic sink appending formatted lines to `path` — SYNCHRONOUS writes
|
|
176
|
+
* (a crashing pi must still leave the lines on disk), lazy directory
|
|
177
|
+
* creation, one open descriptor per sink. An open/write failure THROWS: core's
|
|
178
|
+
* `_emitDiagnostic` catches it, complains once on the console, and keeps the
|
|
179
|
+
* structured event flowing — loud once, never TUI spam, never silent.
|
|
180
|
+
*/
|
|
181
|
+
declare function createFileDiagnosticSink(path: string): (diagnostic: CoreDiagnosticLike) => void;
|
|
182
|
+
/** Where the pi lane's quiet diagnostics land (the compat log convention). */
|
|
183
|
+
declare function piDiagnosticLogPath(home?: string): string;
|
|
152
184
|
declare function makeSessionFactory(loadCore: () => Promise<CoreModuleLike> | CoreModuleLike): SessionFactory;
|
|
153
185
|
/** One pooled backhaul: the session plus its Responses client (cli.ts shape). */
|
|
154
186
|
interface PoolEntry {
|
|
155
|
-
session:
|
|
187
|
+
session: OwnedSession;
|
|
156
188
|
responses: UrunResponses;
|
|
157
189
|
}
|
|
158
190
|
/**
|
|
@@ -174,22 +206,36 @@ declare class SessionPool {
|
|
|
174
206
|
/** Release everything (pi session_shutdown). */
|
|
175
207
|
closeAll(): void;
|
|
176
208
|
}
|
|
177
|
-
/** A Responses input item
|
|
178
|
-
|
|
209
|
+
/** A Responses input item: role message or function-call round-trip item. */
|
|
210
|
+
type ResponsesInputItem = {
|
|
179
211
|
role: 'system' | 'user' | 'assistant';
|
|
180
212
|
content: string;
|
|
181
|
-
}
|
|
213
|
+
} | {
|
|
214
|
+
type: 'function_call';
|
|
215
|
+
call_id: string;
|
|
216
|
+
name: string;
|
|
217
|
+
arguments: string;
|
|
218
|
+
} | {
|
|
219
|
+
type: 'function_call_output';
|
|
220
|
+
call_id: string;
|
|
221
|
+
output: string;
|
|
222
|
+
};
|
|
182
223
|
/**
|
|
183
|
-
* Pi `Context` -> Responses `input` items
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
224
|
+
* Pi `Context` -> Responses `input` items, in ENCOUNTER ORDER (the tool
|
|
225
|
+
* loop's canonical Responses shapes — the same translation the compat proxy
|
|
226
|
+
* performs):
|
|
227
|
+
* - assistant `toolCall` content → `{type:'function_call', call_id, name,
|
|
228
|
+
* arguments}` (arguments re-serialized: pi stores the PARSED object);
|
|
229
|
+
* - `role:"toolResult"` turns → `{type:'function_call_output', call_id,
|
|
230
|
+
* output}` keyed by pi's `toolCallId`;
|
|
231
|
+
* - assistant `thinking` content is the producing model's internal state —
|
|
232
|
+
* not re-submittable — and is skipped by design (same rule as the proxy);
|
|
233
|
+
* - text runs become role messages where they sit; adjacent same-role
|
|
234
|
+
* messages are coalesced so chat templates that assume strict role
|
|
235
|
+
* alternation never see two turns of one role back-to-back.
|
|
190
236
|
*/
|
|
191
237
|
declare function toResponsesInput(context: Context): ResponsesInputItem[];
|
|
192
|
-
/** Fold consecutive same-role items into one, joining with a blank line. */
|
|
238
|
+
/** Fold consecutive same-role message items into one, joining with a blank line. */
|
|
193
239
|
declare function coalesceSameRole(items: ResponsesInputItem[]): ResponsesInputItem[];
|
|
194
240
|
/** Tunable timeouts (overridable so tests can drive them deterministically). */
|
|
195
241
|
interface StreamTiming {
|
|
@@ -219,4 +265,4 @@ declare function createUrunExtension(opts?: UrunExtensionOptions): (pi: Extensio
|
|
|
219
265
|
/** The pi extension factory (default export — what pi's loader invokes). */
|
|
220
266
|
declare const _default: (pi: ExtensionAPI) => Promise<void>;
|
|
221
267
|
|
|
222
|
-
export { type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, resolveSessionEnv, toResponsesInput };
|
|
268
|
+
export { type CoreDiagnosticLike, type CoreModuleLike, type OwnedSession, 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-DrccxHTc.js';
|
|
4
4
|
|
|
5
5
|
declare const URUN_API: Api;
|
|
6
6
|
|
|
@@ -18,7 +18,18 @@ declare function resolveSessionEnv(env: NodeJS.ProcessEnv): {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
interface SessionFactory {
|
|
21
|
-
(env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<
|
|
21
|
+
(env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<OwnedSession> | OwnedSession;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type OwnedSession = UrunSessionLike & {
|
|
25
|
+
end: () => Promise<unknown>;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
interface CoreDiagnosticLike {
|
|
29
|
+
level: string;
|
|
30
|
+
kind: string;
|
|
31
|
+
message: string;
|
|
32
|
+
detail?: Record<string, unknown>;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
interface CoreModuleLike {
|
|
@@ -27,6 +38,7 @@ interface CoreModuleLike {
|
|
|
27
38
|
orgId: string;
|
|
28
39
|
jwt?: string;
|
|
29
40
|
getAccessToken?: () => Promise<string>;
|
|
41
|
+
diagnosticSink?: (diagnostic: CoreDiagnosticLike) => void;
|
|
30
42
|
}) => Record<string, (args?: Record<string, unknown>) => UrunSessionLike>;
|
|
31
43
|
createClientToken: (apiKey: string, opts: {
|
|
32
44
|
baseUrl?: string;
|
|
@@ -37,10 +49,13 @@ interface CoreModuleLike {
|
|
|
37
49
|
}>;
|
|
38
50
|
}
|
|
39
51
|
|
|
52
|
+
declare function createFileDiagnosticSink(path: string): (diagnostic: CoreDiagnosticLike) => void;
|
|
53
|
+
|
|
54
|
+
declare function piDiagnosticLogPath(home?: string): string;
|
|
40
55
|
declare function makeSessionFactory(loadCore: () => Promise<CoreModuleLike> | CoreModuleLike): SessionFactory;
|
|
41
56
|
|
|
42
57
|
interface PoolEntry {
|
|
43
|
-
session:
|
|
58
|
+
session: OwnedSession;
|
|
44
59
|
responses: UrunResponses;
|
|
45
60
|
}
|
|
46
61
|
|
|
@@ -57,10 +72,19 @@ declare class SessionPool {
|
|
|
57
72
|
closeAll(): void;
|
|
58
73
|
}
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
type ResponsesInputItem = {
|
|
61
76
|
role: 'system' | 'user' | 'assistant';
|
|
62
77
|
content: string;
|
|
63
|
-
}
|
|
78
|
+
} | {
|
|
79
|
+
type: 'function_call';
|
|
80
|
+
call_id: string;
|
|
81
|
+
name: string;
|
|
82
|
+
arguments: string;
|
|
83
|
+
} | {
|
|
84
|
+
type: 'function_call_output';
|
|
85
|
+
call_id: string;
|
|
86
|
+
output: string;
|
|
87
|
+
};
|
|
64
88
|
|
|
65
89
|
declare function toResponsesInput(context: Context): ResponsesInputItem[];
|
|
66
90
|
|
|
@@ -85,4 +109,4 @@ declare function createUrunExtension(opts?: UrunExtensionOptions): (pi: Extensio
|
|
|
85
109
|
|
|
86
110
|
declare const _default: (pi: ExtensionAPI) => Promise<void>;
|
|
87
111
|
|
|
88
|
-
export { type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, resolveSessionEnv, toResponsesInput };
|
|
112
|
+
export { type CoreDiagnosticLike, type CoreModuleLike, type OwnedSession, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createFileDiagnosticSink, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, piDiagnosticLogPath, resolveSessionEnv, toResponsesInput };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import{c as
|
|
1
|
+
import{c as G}from"../chunk-HQVV5UN5.js";import{a as F,c as H}from"../chunk-5CEMLB6H.js";import{createAssistantMessageEventStream as oe}from"@earendil-works/pi-ai";import{mkdirSync as re,openSync as se,writeSync as ie}from"fs";import ae from"os";import{dirname as le,join as ce}from"path";async function Y(t){let e=await H(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 V="urun-serve",ue="serve",pe=131072,de=16384,B=3,fe=42e4,ge=6e4,X=2,me=15e3;function ye(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()||F,fnName:(t.URUN_FUNCTION??"").trim()||ue}}function he(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 i=(t.URUN_API_KEY??"").trim();if(!i)throw new Error("urun pi extension: URUN_JWT or URUN_API_KEY is required to open a session");let u=(t.URUN_GATEWAY_URL??"").trim()||void 0;return{baseUrl:e,orgId:n,auth:{lane:"api-key",apiKey:i,gatewayUrl:u}}}function we(t){let e=null;return n=>{e===null&&(re(le(t),{recursive:!0}),e=se(t,"a"));let o=n.detail?` ${JSON.stringify(n.detail)}`:"";ie(e,`${new Date().toISOString()} [${n.level}] [urun] ${n.message}${o}
|
|
2
|
+
`)}}function _e(t=ae.homedir()){return ce(t,".urun","logs","pi-extension.log")}function xe(t){let e=we(_e());return async(n,o,i)=>{let{baseUrl:u,orgId:s,auth:d}=he(n),{App:x,createClientToken:a}=await t(),w=(d.lane==="jwt"?x(o,{baseUrl:u,orgId:s,jwt:d.jwt,diagnosticSink:e}):x(o,{baseUrl:u,orgId:s,diagnosticSink:e,getAccessToken:async()=>(await a(d.apiKey,{baseUrl:d.gatewayUrl,expiresIn:300,allowedFunctions:[`${o}/${i}`]})).token}))[i];if(typeof w!="function")throw new Error(`urun pi extension: app "${o}" has no function "${i}"`);let m=w();if(typeof m.end!="function")throw new Error(`urun pi extension: app "${o}" function "${i}" returned a session without end()`);let E=m.connect;return typeof E=="function"&&await E.call(m),m}}var ve=xe(async()=>{let{createRequire:t}=await import("module"),e=t(import.meta.url);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 ke(t){try{Promise.resolve(t.end()).catch(()=>{})}catch{}}var K=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(i=>({session:i,responses:new G(i)}));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=>ke(o.session),()=>{}))}closeAll(){for(let e of[...this.pool.keys()])this.evict(e)}};function Re(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:Ae(n.content)});continue}if(n.role==="assistant"&&Array.isArray(n.content)){let i="",u=()=>{i&&(e.push({role:"assistant",content:i}),i="")};for(let s of n.content)if(s.type==="text")i+=String(s.text??"");else if(s.type==="toolCall")u(),e.push({type:"function_call",call_id:String(s.id??""),name:String(s.name??""),arguments:JSON.stringify(s.arguments??{})});else{if(s.type==="thinking")continue;throw new Error(`urun pi extension: unsupported assistant content part "${String(s.type)}"`)}u();continue}let o=n.role==="assistant"?"assistant":"user";e.push({role:o,content:be(n.content)})}return Te(e)}function Te(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(i=>i.length>0).join(`
|
|
2
3
|
|
|
3
|
-
`):e.push({...n})}return e}function
|
|
4
|
+
`):e.push({...n})}return e}function be(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>e&&typeof e=="object"&&"text"in e?String(e.text):"").join(""):""}function Ae(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 Ee(t){if(!(!Array.isArray(t)||t.length===0))return t.map(e=>({type:"function",name:e.name,description:e.description,parameters:e.parameters}))}function z(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 Ue(t){let e=t?.output;return Array.isArray(e)?e.filter(n=>n.type==="function_call"):[]}function Se(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 i of o.content)i.type==="reasoning_text"&&(n+=String(i.text??""));return n}var Ie=["<tool_call>","<function="];function Pe(t,e){let n=Ie.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)`)}var L=class extends Error{};function Ce(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 Ne(t){return new Promise(e=>setTimeout(e,t))}function Me(t,e,n,o){return new Promise((i,u)=>{let s=!1,d=r=>{s||(s=!0,clearTimeout(x),o?.removeEventListener("abort",a),r())},x=setTimeout(()=>d(()=>u(n())),e),a=()=>d(()=>u(new Error("aborted")));if(o?.aborted){a();return}o?.addEventListener("abort",a,{once:!0}),Promise.resolve(t).then(r=>d(()=>i(r)),r=>d(()=>u(r)))})}async function*Oe(t,e){let n=t[Symbol.asyncIterator](),o,i=new Promise((u,s)=>{o=()=>s(new Error("aborted")),e.addEventListener("abort",o,{once:!0})});try{for(;;){if(e.aborted)throw new Error("aborted");let u=await Promise.race([n.next(),i]);if(u.done)return;yield u.value}}finally{o&&e.removeEventListener("abort",o),n.return?.(void 0)}}function Q(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 Le(t,e={},n){let o=e.connectDeadlineMs??fe,i=e.stallTimeoutMs??ge,u=e.phaseHeartbeatMs??me;return(s,d,x)=>{let a=oe(),r={role:"assistant",content:[],api:s.api,provider:s.provider,model:s.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()},w=new AbortController,m=x?.signal,E=!1,M=()=>{E=!0,w.abort()};m&&(m.aborted?M():m.addEventListener("abort",M,{once:!0}));let P=!1,U,J=()=>{U&&clearTimeout(U),U=setTimeout(()=>{P=!0,w.abort()},i)},O=()=>{U&&clearTimeout(U),U=void 0},v=null,k=null,y=null,W="",C=!1,$=()=>{if(!k)return;let p=k;k=null,a.push({type:"thinking_end",contentIndex:r.content.indexOf(p),content:p.thinking,partial:r})},q=()=>{if(!v)return;let p=v;v=null,a.push({type:"text_end",contentIndex:r.content.indexOf(p),content:p.text,partial:r})},D=()=>{if(!y)return;let{call:p,args:h,contentIndex:R}=y;y=null,p.arguments=z(p.name,h),a.push({type:"toolcall_end",contentIndex:R,toolCall:p,partial:r})},Z=p=>{let h={type:"toolCall",id:String(p.call_id??p.id??`call_${r.content.length}`),name:String(p.name??""),arguments:{}};r.content.push(h);let R=r.content.length-1;a.push({type:"toolcall_start",contentIndex:R,partial:r});let N=typeof p.arguments=="string"?p.arguments:"";N&&a.push({type:"toolcall_delta",contentIndex:R,delta:N,partial:r}),h.arguments=z(h.name,N),a.push({type:"toolcall_end",contentIndex:R,toolCall:h,partial:r})};return(async()=>{a.push({type:"start",partial:r});let p=!1,h,R=()=>{h&&clearInterval(h),h=void 0},N=Date.now();h=setInterval(()=>{let _=Math.round((Date.now()-N)/1e3);Q(n,`uRun: still opening the "${s.id}" session\u2026 (${_}s \u2014 serve apps scale to zero, first turn can cold-start ~6min)`)},u);let ee=async _=>{let{responses:T}=await Me(t.acquire(s.id),o,()=>new Error(`uRun session for "${s.id}" did not connect within ${Math.round(o/1e3)}s \u2014 likely cold-starting (scaled to zero) or queued behind capacity. Retry shortly.`),w.signal);R();let S,b;for(let l=1;l<=B;l++)try{let g=await T.responses.create({model:s.id,input:_,stream:!0,tools:Ee(d.tools),max_output_tokens:s.maxTokens});J();for await(let A of Oe(g,w.signal)){J();let f=A;if(f.type==="response.output_text.delta"){let c=typeof f.delta=="string"?f.delta:"";c&&(C=!0,$(),D(),v||(v={type:"text",text:""},r.content.push(v),a.push({type:"text_start",contentIndex:r.content.length-1,partial:r})),v.text+=c,W+=c,a.push({type:"text_delta",contentIndex:r.content.indexOf(v),delta:c,partial:r}))}else if(f.type==="response.reasoning_text.delta"){let c=typeof f.delta=="string"?f.delta:"";c&&(C=!0,k||(k={type:"thinking",thinking:""},r.content.push(k),a.push({type:"thinking_start",contentIndex:r.content.length-1,partial:r})),k.thinking+=c,a.push({type:"thinking_delta",contentIndex:r.content.indexOf(k),delta:c,partial:r}))}else if(f.type==="response.function_call_arguments.delta"&&typeof f.tool_index=="number"){let c=f;if(C=!0,$(),q(),!y||y.toolIndex!==c.tool_index){D();let j={type:"toolCall",id:c.call_id??`call_${c.tool_index}`,name:c.name??"",arguments:{}};r.content.push(j),y={call:j,args:"",contentIndex:r.content.length-1,toolIndex:c.tool_index},a.push({type:"toolcall_start",contentIndex:y.contentIndex,partial:r})}c.call_id&&(y.call.id=c.call_id),c.name&&(y.call.name=c.name);let I=typeof c.delta=="string"?c.delta:"";I&&(y.args+=I,a.push({type:"toolcall_delta",contentIndex:y.contentIndex,delta:I,partial:r}))}else if(f.type==="response.completed"){S=f.response;break}else if(f.type==="error"){let c=f.error,I=new Error(`uRun serve error: ${c?.message??"unknown error"}`);throw I.code=c?.code??null,I}}if(!S)throw new L(`uRun backhaul for "${s.id}" closed before the turn completed \u2014 the serving session ended mid-turn (its pod was restarted, drained or deleted).`);b=void 0;break}catch(g){if(b=g,w.signal.aborted)throw g;if(l<B&&Ce(g)&&!C){await Ne(l*500);continue}throw g}if(b)throw b;return S};try{let _=Re(d),T;for(let l=1;l<=X;l++)try{T=await ee(_);break}catch(g){let A=P||g instanceof L;if(l>=X||!A||C||E)throw g;O(),t.evict(s.id),P=!1,w=new AbortController,Q(n,`uRun: the "${s.id}" session ended mid-turn \u2014 re-homing to a fresh assignment and replaying the turn\u2026`)}if(O(),$(),q(),D(),!r.content.some(l=>l.type==="toolCall"))for(let l of Ue(T))Z(l);if(!r.content.some(l=>l.type==="thinking")){let l=Se(T);if(l){let g={type:"thinking",thinking:""};r.content.push(g);let A=r.content.length-1;a.push({type:"thinking_start",contentIndex:A,partial:r}),g.thinking=l,a.push({type:"thinking_delta",contentIndex:A,delta:l,partial:r}),a.push({type:"thinking_end",contentIndex:A,content:l,partial:r})}}let S=r.content.filter(l=>l.type==="toolCall").length;if((d.tools?.length??0)>0&&S===0){let l=Pe(s.id,W);if(l)throw l}let b=S>0?"toolUse":T?.status==="incomplete"?"length":"stop";r.stopReason=b,a.push({type:"done",reason:b,message:r}),a.end(r)}catch(_){if(p=!0,O(),E||m?.aborted&&!P)r.stopReason="aborted",r.errorMessage="aborted by user",a.push({type:"error",reason:"aborted",error:r});else{let T=P?`uRun stream stalled \u2014 no output for ${Math.round(i/1e3)}s; the model may be hung. Retry, or Ctrl-C to abort.`:_ instanceof Error?_.message:String(_);r.stopReason="error",r.errorMessage=T,a.push({type:"error",reason:"error",error:r})}a.end(r)}finally{O(),R(),m&&m.removeEventListener("abort",M),p&&t.evict(s.id)}})(),a}}function $e(t){return{id:t,name:`uRun ${t}`,api:V,reasoning:!0,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:pe,maxTokens:de}}function De(t={}){return async e=>{let n=t.env??process.env,{apiKey:o,apiUrl:i,fnName:u}=ye(n),s=await Y({apiUrl:i,apiKey:o,fnName:u,fetchImpl:t.fetchImpl}),d=new K(t.openSession??ve,n,u);e.on("session_shutdown",()=>d.closeAll());let x={name:"uRun",api:V,baseUrl:"urun://session",apiKey:"$URUN_API_KEY",models:s.map($e),streamSimple:Le(d,t.timing??{},e)};e.registerProvider("urun",x)}}var Xe=De();export{K as SessionPool,V as URUN_API,Te as coalesceSameRole,we as createFileDiagnosticSink,De as createUrunExtension,Xe as default,xe as makeSessionFactory,Le as makeStreamSimple,_e as piDiagnosticLogPath,he as resolveSessionEnv,Re as toResponsesInput};
|