@urun-sh/openai 0.2.50 → 0.2.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,222 @@
1
+ import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
2
+ import { Api, Model, Context, SimpleStreamOptions, AssistantMessageEventStream } from '@earendil-works/pi-ai';
3
+ import { a as UrunSessionLike, U as UrunResponses } from '../ResponsesClient-CQ3l8Wft.cjs';
4
+
5
+ /**
6
+ * Pi coding-agent extension: register the `urun` model provider, with one pi
7
+ * model PER DEPLOYED SERVE APP discovered from the org API, streaming over
8
+ * this package's OWN Responses lane (`UrunResponses` — the SAME transport the
9
+ * compat proxy uses; one canonical transport, no shim).
10
+ *
11
+ * HOW PI LOADS THIS (verified against @earendil-works/pi-coding-agent 0.74.2,
12
+ * `dist/core/extensions/loader.js`):
13
+ * - Extensions are modules loaded with jiti (`loadExtensionModule`), which
14
+ * handles TS and JS (ESM or CJS). The published entry is the BUILT dist
15
+ * file: `pi -e node_modules/@urun-sh/openai/dist/pi-extension/index.js`
16
+ * (or `.cjs`); in this repo's worktree the same path under
17
+ * `packages/openai/dist/` after `pnpm build`.
18
+ * - The default export must be the ExtensionFactory; the loader `await`s it
19
+ * (`await factory(api)`), so an async factory that discovers BEFORE
20
+ * registering is the canonical shape (`registerProvider` during load is
21
+ * queued and flushed at runner bind — `pendingProviderRegistrations`).
22
+ * - Imports of pi packages are resolved BY THE LOADER: jiti `alias` (Node
23
+ * mode) / `virtualModules` (compiled Bun binary) map `@earendil-works/
24
+ * pi-ai` and `@earendil-works/pi-coding-agent` (and the legacy
25
+ * `@mariozechner/*` names) to pi's bundled copies. So the ONE value import
26
+ * below (`createAssistantMessageEventStream`) is left external by tsup and
27
+ * resolves at pi runtime without pi being a dependency of this package;
28
+ * `pi-types.d.ts` supplies the types for tsc/tsup, and vitest aliases the
29
+ * module to a local stub.
30
+ * - `@urun-sh/core` stays external in dist too (tsup config) and resolves
31
+ * from the consumer's node_modules — it is this package's peerDependency.
32
+ *
33
+ * WHAT IT DOES:
34
+ * 1. factory (async): discovers the org's deployed serve apps via
35
+ * `GET {URUN_API_URL}/apps` (Authorization: Bearer URUN_API_KEY — the
36
+ * canonical `proxy/routing.ts` helper) and registers provider "urun"
37
+ * with one model per active app exposing the serve function (model id =
38
+ * app slug). Missing URUN_API_KEY or a failed/empty discovery THROWS,
39
+ * which pi surfaces as "Failed to load extension: …" — never a silent
40
+ * empty provider.
41
+ * 2. `streamSimple` (pi's custom-API hook, keyed by `api: "urun-serve"`):
42
+ * opens ONE uRun session per app slug, POOLED and reused across turns,
43
+ * translates pi's Context into Responses `input` items, drives
44
+ * `UrunResponses.responses.create({stream: true})`, and maps
45
+ * `response.output_text.delta` events into pi `text_delta` events.
46
+ * Text-only, matching the precedent extension's fidelity (no tool-call
47
+ * streaming through the serve lane; pi's toolResult turns are folded
48
+ * into user-role input items — the Responses `function_call_output` item
49
+ * form needs call ids this lane never emits).
50
+ * 3. ABORT/CANCEL (loud contract): the Responses lane has NO request-cancel
51
+ * primitive (`SdkTransport.sendResponses` writes an envelope and the
52
+ * decode loop just reads the reply lane), so Ctrl-C / the stall watchdog
53
+ * stop consuming AND evict+close the pooled session — tearing down the
54
+ * WebRTC transport is what stops server-side generation. A clean turn
55
+ * keeps its session for the next turn; a failed/aborted/stalled turn
56
+ * always reopens.
57
+ * 4. cleanup: pooled sessions are released (`session.close()`) on pi's
58
+ * `session_shutdown` lifecycle event.
59
+ *
60
+ * RUNTIME DEPENDENCY STORY (owner requirement — stated honestly): token
61
+ * streams are named-DATA session streams, i.e. SCTP data channels over
62
+ * WebRTC (core session contract). Under pi's Node runtime `@urun-sh/core`
63
+ * installs its Node WebRTC backend from `node-webrtc.ts`: **werift** (pure-TS,
64
+ * H.264-capable; explicitly NOT @roamhq/wrtc, whose prebuilt libwebrtc lacks
65
+ * H.264) plus `ws` for Node < 22 — both declared as OPTIONAL dependencies of
66
+ * `@urun-sh/core`, and `werift` is ALSO declared in this package's
67
+ * `optionalDependencies` (same story the proxy relies on; its `build:bin`
68
+ * marks them external). Optional deps install by default, but a
69
+ * `--no-optional` install would leave core to swallow the missing backend
70
+ * with a warning and the extension would hang waiting for a data channel —
71
+ * so `defaultSessionFactory` PREFLIGHTS the backend and fails loudly instead.
72
+ *
73
+ * ENV CONTRACT (discovery env is read at FACTORY time because pi models must
74
+ * exist at load; session env is read at STREAM time so a registered model
75
+ * fails loudly on first use, not at load):
76
+ * URUN_API_KEY org API key — REQUIRED at load (discovery) and used to
77
+ * mint per-app client tokens at stream time (api-key lane)
78
+ * URUN_API_URL org control-plane base (default DEFAULT_ORG_API_URL)
79
+ * URUN_FUNCTION serve function name (default "serve")
80
+ * URUN_BASE_URL session-gateway base — required at stream time
81
+ * URUN_ORG_ID org id — required at stream time
82
+ * URUN_JWT optional pre-vended session token; WINS over the api-key
83
+ * lane when set (same precedence as the compat proxy)
84
+ * URUN_GATEWAY_URL optional createClientToken baseUrl override
85
+ *
86
+ * CLI (verified against dist/core/model-resolver.js resolveCliModel):
87
+ * pi -e node_modules/@urun-sh/openai/dist/pi-extension/index.js \
88
+ * --provider urun --model <app-slug> -p "..."
89
+ * or equivalently `--model urun/<app-slug>` (provider inferred from the
90
+ * slash prefix), e.g. `--model urun/qwen3-6-27b-bf16`.
91
+ */
92
+
93
+ /**
94
+ * Custom `api` id. Pi dispatches the stream function by `model.api`, so a
95
+ * unique id keeps our in-process `streamSimple` scoped to this provider and
96
+ * never overrides a built-in API provider.
97
+ */
98
+ declare const URUN_API: Api;
99
+ /** Session-target env, read at stream time. Loud on anything missing. */
100
+ declare function resolveSessionEnv(env: NodeJS.ProcessEnv): {
101
+ baseUrl: string;
102
+ orgId: string;
103
+ auth: {
104
+ lane: 'jwt';
105
+ jwt: string;
106
+ } | {
107
+ lane: 'api-key';
108
+ apiKey: string;
109
+ gatewayUrl?: string;
110
+ };
111
+ };
112
+ /**
113
+ * How a uRun session is opened for one app slug. Injectable so tests drive
114
+ * `streamSimple` against the package's MockSession with no network and no
115
+ * `@urun-sh/core`.
116
+ */
117
+ interface SessionFactory {
118
+ (env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<UrunSessionLike> | UrunSessionLike;
119
+ }
120
+ /**
121
+ * The subset of `@urun-sh/core` a session factory needs — typed locally so
122
+ * core stays OUT of this module's static import graph (the npm lane resolves
123
+ * it at runtime; only the standalone bundle imports it statically).
124
+ */
125
+ interface CoreModuleLike {
126
+ App: (id: string, opts: {
127
+ baseUrl: string;
128
+ orgId: string;
129
+ jwt?: string;
130
+ getAccessToken?: () => Promise<string>;
131
+ }) => Record<string, (args?: Record<string, unknown>) => UrunSessionLike>;
132
+ createClientToken: (apiKey: string, opts: {
133
+ baseUrl?: string;
134
+ expiresIn: number;
135
+ allowedFunctions: string[];
136
+ }) => Promise<{
137
+ token: string;
138
+ }>;
139
+ }
140
+ /**
141
+ * Build a {@link SessionFactory} over one way of loading `@urun-sh/core` —
142
+ * the ONE session-opening implementation (the compat proxy's two auth lanes:
143
+ * URUN_JWT explicit override > URUN_API_KEY vending a scoped client token),
144
+ * shared by both entry lanes:
145
+ *
146
+ * - npm lane ({@link defaultSessionFactory}): runtime createRequire + the
147
+ * werift preflight, resolving core from the consumer's node_modules;
148
+ * - standalone lane (standalone-entry.ts): a STATIC core import, so the
149
+ * self-contained bundle INLINES core (and, through core's own dynamic
150
+ * werift import, the WebRTC backend) — that lane has no node_modules.
151
+ */
152
+ declare function makeSessionFactory(loadCore: () => Promise<CoreModuleLike> | CoreModuleLike): SessionFactory;
153
+ /** One pooled backhaul: the session plus its Responses client (cli.ts shape). */
154
+ interface PoolEntry {
155
+ session: UrunSessionLike;
156
+ responses: UrunResponses;
157
+ }
158
+ /**
159
+ * The session pool: one uRun session per app slug, opened lazily on the first
160
+ * turn that uses the model and REUSED across turns (same shape as the compat
161
+ * proxy's ModelRouter pool). A failed open never poisons the slot; a turn
162
+ * that ends in error/abort/stall evicts its entry — closing the session is
163
+ * ALSO the cancel mechanism (see the header's abort contract).
164
+ */
165
+ declare class SessionPool {
166
+ private readonly open;
167
+ private readonly env;
168
+ private readonly fnName;
169
+ private readonly pool;
170
+ constructor(open: SessionFactory, env: NodeJS.ProcessEnv, fnName: string);
171
+ acquire(appSlug: string): Promise<PoolEntry>;
172
+ /** Drop + release one entry (turn ended badly / user aborted). */
173
+ evict(appSlug: string): void;
174
+ /** Release everything (pi session_shutdown). */
175
+ closeAll(): void;
176
+ }
177
+ /** A Responses input item (message form; content stays a plain string). */
178
+ interface ResponsesInputItem {
179
+ role: 'system' | 'user' | 'assistant';
180
+ content: string;
181
+ }
182
+ /**
183
+ * Pi `Context` -> Responses `input` items. Pi models tool results as
184
+ * `role:"toolResult"`; the Responses item form for those
185
+ * (`{type:'function_call_output', call_id, …}`) needs call ids this text-only
186
+ * lane never emits, so tool results are folded into `user`-role items, then
187
+ * any consecutive same-role runs are coalesced into one item so a chat
188
+ * template that assumes strict role alternation never sees two turns of the
189
+ * same role back-to-back (same rationale as the precedent extension).
190
+ */
191
+ declare function toResponsesInput(context: Context): ResponsesInputItem[];
192
+ /** Fold consecutive same-role items into one, joining with a blank line. */
193
+ declare function coalesceSameRole(items: ResponsesInputItem[]): ResponsesInputItem[];
194
+ /** Tunable timeouts (overridable so tests can drive them deterministically). */
195
+ interface StreamTiming {
196
+ connectDeadlineMs?: number;
197
+ stallTimeoutMs?: number;
198
+ phaseHeartbeatMs?: number;
199
+ }
200
+ /**
201
+ * Build the `streamSimple` handler over a {@link SessionPool}. Returns the
202
+ * event stream synchronously (pi consumes it as an async iterable) and drives
203
+ * the pooled session's Responses lane on a microtask.
204
+ */
205
+ declare function makeStreamSimple(pool: SessionPool, timing?: StreamTiming, pi?: ExtensionAPI): (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;
206
+ /** Injectable seams for tests; production uses the defaults. */
207
+ interface UrunExtensionOptions {
208
+ env?: NodeJS.ProcessEnv;
209
+ fetchImpl?: typeof fetch;
210
+ openSession?: SessionFactory;
211
+ timing?: StreamTiming;
212
+ }
213
+ /**
214
+ * Build the extension factory. Async: pi's loader `await`s the factory, and
215
+ * `registerProvider` calls during load are queued and applied once the runner
216
+ * binds, so discovering BEFORE registering is the canonical shape.
217
+ */
218
+ declare function createUrunExtension(opts?: UrunExtensionOptions): (pi: ExtensionAPI) => Promise<void>;
219
+ /** The pi extension factory (default export — what pi's loader invokes). */
220
+ declare const _default: (pi: ExtensionAPI) => Promise<void>;
221
+
222
+ export { type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, resolveSessionEnv, toResponsesInput };
@@ -0,0 +1,88 @@
1
+ import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
2
+ import { Api, Model, Context, SimpleStreamOptions, AssistantMessageEventStream } from '@earendil-works/pi-ai';
3
+ import { a as UrunSessionLike, U as UrunResponses } from '../ResponsesClient-CQ3l8Wft.js';
4
+
5
+ declare const URUN_API: Api;
6
+
7
+ declare function resolveSessionEnv(env: NodeJS.ProcessEnv): {
8
+ baseUrl: string;
9
+ orgId: string;
10
+ auth: {
11
+ lane: 'jwt';
12
+ jwt: string;
13
+ } | {
14
+ lane: 'api-key';
15
+ apiKey: string;
16
+ gatewayUrl?: string;
17
+ };
18
+ };
19
+
20
+ interface SessionFactory {
21
+ (env: NodeJS.ProcessEnv, appSlug: string, fnName: string): Promise<UrunSessionLike> | UrunSessionLike;
22
+ }
23
+
24
+ interface CoreModuleLike {
25
+ App: (id: string, opts: {
26
+ baseUrl: string;
27
+ orgId: string;
28
+ jwt?: string;
29
+ getAccessToken?: () => Promise<string>;
30
+ }) => Record<string, (args?: Record<string, unknown>) => UrunSessionLike>;
31
+ createClientToken: (apiKey: string, opts: {
32
+ baseUrl?: string;
33
+ expiresIn: number;
34
+ allowedFunctions: string[];
35
+ }) => Promise<{
36
+ token: string;
37
+ }>;
38
+ }
39
+
40
+ declare function makeSessionFactory(loadCore: () => Promise<CoreModuleLike> | CoreModuleLike): SessionFactory;
41
+
42
+ interface PoolEntry {
43
+ session: UrunSessionLike;
44
+ responses: UrunResponses;
45
+ }
46
+
47
+ declare class SessionPool {
48
+ private readonly open;
49
+ private readonly env;
50
+ private readonly fnName;
51
+ private readonly pool;
52
+ constructor(open: SessionFactory, env: NodeJS.ProcessEnv, fnName: string);
53
+ acquire(appSlug: string): Promise<PoolEntry>;
54
+
55
+ evict(appSlug: string): void;
56
+
57
+ closeAll(): void;
58
+ }
59
+
60
+ interface ResponsesInputItem {
61
+ role: 'system' | 'user' | 'assistant';
62
+ content: string;
63
+ }
64
+
65
+ declare function toResponsesInput(context: Context): ResponsesInputItem[];
66
+
67
+ declare function coalesceSameRole(items: ResponsesInputItem[]): ResponsesInputItem[];
68
+
69
+ interface StreamTiming {
70
+ connectDeadlineMs?: number;
71
+ stallTimeoutMs?: number;
72
+ phaseHeartbeatMs?: number;
73
+ }
74
+
75
+ declare function makeStreamSimple(pool: SessionPool, timing?: StreamTiming, pi?: ExtensionAPI): (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;
76
+
77
+ interface UrunExtensionOptions {
78
+ env?: NodeJS.ProcessEnv;
79
+ fetchImpl?: typeof fetch;
80
+ openSession?: SessionFactory;
81
+ timing?: StreamTiming;
82
+ }
83
+
84
+ declare function createUrunExtension(opts?: UrunExtensionOptions): (pi: ExtensionAPI) => Promise<void>;
85
+
86
+ declare const _default: (pi: ExtensionAPI) => Promise<void>;
87
+
88
+ export { type CoreModuleLike, type ResponsesInputItem, type SessionFactory, SessionPool, type StreamTiming, URUN_API, type UrunExtensionOptions, coalesceSameRole, createUrunExtension, _default as default, makeSessionFactory, makeStreamSimple, resolveSessionEnv, toResponsesInput };
@@ -0,0 +1,3 @@
1
+ import{c as C}from"../chunk-FSS2A7IU.js";import{a as A,c as D}from"../chunk-PS4BLX7J.js";import{createAssistantMessageEventStream as J}from"@earendil-works/pi-ai";async function F(t){let e=await D(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 O="urun-serve",G="serve",H=131072,Y=16384,$=3,B=42e4,X=6e4,z=15e3;function Q(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()||A,fnName:(t.URUN_FUNCTION??"").trim()||G}}function V(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 a=(t.URUN_GATEWAY_URL??"").trim()||void 0;return{baseUrl:e,orgId:n,auth:{lane:"api-key",apiKey:i,gatewayUrl:a}}}function Z(t){return async(e,n,o)=>{let{baseUrl:i,orgId:a,auth:s}=V(e),{App:u,createClientToken:l}=await t(),r=(s.lane==="jwt"?u(n,{baseUrl:i,orgId:a,jwt:s.jwt}):u(n,{baseUrl:i,orgId:a,getAccessToken:async()=>(await l(s.apiKey,{baseUrl:s.gatewayUrl,expiresIn:300,allowedFunctions:[`${n}/${o}`]})).token}))[o];if(typeof r!="function")throw new Error(`urun pi extension: app "${n}" has no function "${o}"`);let d=r(),p=d.connect;return typeof p=="function"&&await p.call(d),d}}var ee=Z(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 te(t){try{Promise.resolve(t.close?.()).catch(()=>{})}catch{}}var x=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 C(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=>te(o.session),()=>{}))}closeAll(){for(let e of[...this.pool.keys()])this.evict(e)}};function ne(t){let e=[];t.systemPrompt&&e.push({role:"system",content:t.systemPrompt});for(let n of t.messages){let o=n.role==="assistant"?"assistant":"user";e.push({role:o,content:re(n.content)})}return oe(e)}function oe(t){let e=[];for(let n of t){let o=e[e.length-1];o&&o.role===n.role?o.content=[o.content,n.content].filter(i=>i.length>0).join(`
2
+
3
+ `):e.push({...n})}return e}function re(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>e&&typeof e=="object"&&"text"in e?String(e.text):"").join(""):""}function se(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 ie(t){return new Promise(e=>setTimeout(e,t))}function ae(t,e,n,o){return new Promise((i,a)=>{let s=!1,u=r=>{s||(s=!0,clearTimeout(l),o?.removeEventListener("abort",c),r())},l=setTimeout(()=>u(()=>a(n())),e),c=()=>u(()=>a(new Error("aborted")));if(o?.aborted){c();return}o?.addEventListener("abort",c,{once:!0}),Promise.resolve(t).then(r=>u(()=>i(r)),r=>u(()=>a(r)))})}async function*ce(t,e){let n=t[Symbol.asyncIterator](),o,i=new Promise((a,s)=>{o=()=>s(new Error("aborted")),e.addEventListener("abort",o,{once:!0})});try{for(;;){if(e.aborted)throw new Error("aborted");let a=await Promise.race([n.next(),i]);if(a.done)return;yield a.value}}finally{o&&e.removeEventListener("abort",o),n.return?.(void 0)}}function ue(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 pe(t,e={},n){let o=e.connectDeadlineMs??B,i=e.stallTimeoutMs??X,a=e.phaseHeartbeatMs??z;return(s,u,l)=>{let c=J(),r={role:"assistant",content:[{type:"text",text:""}],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()},d=r.content[0],p=new AbortController,m=l?.signal,P=!1,b=()=>{P=!0,p.abort()};m&&(m.aborted?b():m.addEventListener("abort",b,{once:!0}));let E=!1,y,I=()=>{y&&clearTimeout(y),y=setTimeout(()=>{E=!0,p.abort()},i)},_=()=>{y&&clearTimeout(y),y=void 0};return(async()=>{c.push({type:"start",partial:r}),c.push({type:"text_start",contentIndex:0,partial:r});let k=!1,v,S=()=>{v&&clearInterval(v),v=void 0},K=Date.now();v=setInterval(()=>{let f=Math.round((Date.now()-K)/1e3);ue(n,`uRun: still opening the "${s.id}" session\u2026 (${f}s \u2014 serve apps scale to zero, first turn can cold-start ~6min)`)},a);try{let{responses:f}=await ae(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.`),p.signal);S();let T=ne(u),N,U;for(let R=1;R<=$;R++)try{let h=await f.responses.create({model:s.id,input:T,stream:!0,max_output_tokens:s.maxTokens});I();for await(let W of ce(h,p.signal)){I();let g=W;if(g.type==="response.output_text.delta"){let w=typeof g.delta=="string"?g.delta:"";w&&(d.text+=w,c.push({type:"text_delta",contentIndex:0,delta:w,partial:r}))}else if(g.type==="response.completed"){N=g.response;break}else if(g.type==="error"){let w=g.error,L=new Error(`uRun serve error: ${w?.message??"unknown error"}`);throw L.code=w?.code??null,L}}U=void 0;break}catch(h){if(U=h,p.signal.aborted)throw h;if(R<$&&se(h)&&d.text.length===0){await ie(R*500);continue}throw h}if(U)throw U;_(),c.push({type:"text_end",contentIndex:0,content:d.text,partial:r});let M=N?.status==="incomplete"?"length":"stop";r.stopReason=M,c.push({type:"done",reason:M,message:r}),c.end(r)}catch(f){if(k=!0,_(),P||m?.aborted&&!E)r.stopReason="aborted",r.errorMessage="aborted by user",c.push({type:"error",reason:"aborted",error:r});else{let T=E?`uRun stream stalled \u2014 no output for ${Math.round(i/1e3)}s; the model may be hung. Retry, or Ctrl-C to abort.`:f instanceof Error?f.message:String(f);r.stopReason="error",r.errorMessage=T,c.push({type:"error",reason:"error",error:r})}c.end(r)}finally{_(),S(),m&&m.removeEventListener("abort",b),k&&t.evict(s.id)}})(),c}}function le(t){return{id:t,name:`uRun ${t}`,api:O,reasoning:!1,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:H,maxTokens:Y}}function de(t={}){return async e=>{let n=t.env??process.env,{apiKey:o,apiUrl:i,fnName:a}=Q(n),s=await F({apiUrl:i,apiKey:o,fnName:a,fetchImpl:t.fetchImpl}),u=new x(t.openSession??ee,n,a);e.on("session_shutdown",()=>u.closeAll());let l={name:"uRun",api:O,baseUrl:"urun://session",apiKey:"$URUN_API_KEY",models:s.map(le),streamSimple:pe(u,t.timing??{},e)};e.registerProvider("urun",l)}}var Ue=de();export{x as SessionPool,O as URUN_API,oe as coalesceSameRole,de as createUrunExtension,Ue as default,Z as makeSessionFactory,pe as makeStreamSimple,V as resolveSessionEnv,ne as toResponsesInput};