@urun-sh/openai 0.6.21 → 0.6.23

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.
@@ -1,8 +1,8 @@
1
1
  import { Server } from 'node:http';
2
2
  import * as _prometheus_io_client from '@prometheus-io/client';
3
3
  import { Registry } from '@prometheus-io/client';
4
- import { c as LedgerOutcome, I as InferenceRecord, S as SessionGoneError, P as ProxyClients, M as ModelRouter, i as UsageRowReporter, b as InferenceUsageRecord, e as LedgerWrite, d as LedgerRecorded, L as LedgerFailure } from '../responses-turn-Cb1qQBA7.cjs';
5
- import { createClientToken } from '@urun-sh/core';
4
+ import { c as LedgerOutcome, I as InferenceRecord, S as SessionGoneError, j as billingIdentityOf, P as ProxyClients, M as ModelRouter, i as UsageRowReporter, b as InferenceUsageRecord, e as LedgerWrite, d as LedgerRecorded, L as LedgerFailure } from '../responses-turn-C0PBaF29.cjs';
5
+ import { createClientToken, SessionPhaseName } from '@urun-sh/core';
6
6
  import { U as UrunResponses } from '../ResponsesClient-_OZERUjH.cjs';
7
7
  import { b as UrunSessionLike } from '../types-CHPtJx6d.cjs';
8
8
  import '../models-DUdx_Y6X.cjs';
@@ -235,6 +235,29 @@ declare class OrgResolver {
235
235
  clear(): void;
236
236
  }
237
237
 
238
+ /** Live gauges for the proxy's /metrics surface. */
239
+ interface DecisionPoolStats {
240
+ /** Slots that exist (any state) — submitted session requests. */
241
+ requested: number;
242
+ attached: number;
243
+ /** Slots submitted whose session has not attached (or re-attached) yet. */
244
+ queued: number;
245
+ paused: number;
246
+ /** Decisions currently riding the pool. */
247
+ inFlight: number;
248
+ /** GOAWAY sent: admissions closed, in-flight finishing, slots ending. */
249
+ draining: boolean;
250
+ /** Acquire misses total, and how many found the pool PAST its own idle
251
+ * window (cold-by-design after pause) vs INSIDE it (hold failure). The
252
+ * inside-window count climbing is the hold failing; the past-window count
253
+ * climbing is the pause/scale-to-zero working as ruled. */
254
+ misses: number;
255
+ missesPastWindow: number;
256
+ /** ms since the pool last saw demand at the most recent miss (null = the
257
+ * pool had never seen demand). Time-since-last-traffic on the miss. */
258
+ lastMissAgeMs: number | null;
259
+ }
260
+
238
261
  /**
239
262
  * SESSION GONE for the proxy serve lane — level-triggered, keyed off the
240
263
  * transport's OWN close/rejection signals (live defect, prod-usw2 2026-08-12).
@@ -368,6 +391,21 @@ type OwnedSession = UrunSessionLike & {
368
391
  timeout?: number;
369
392
  signal?: AbortSignal;
370
393
  }) => Promise<void>;
394
+ /**
395
+ * The session's current phase snapshot (core `Session.phase`): the server's
396
+ * wake hint (`phase.runtime.wake.expectedWakePath`) rides it and picks the
397
+ * explicit `whenLive` bound ({@link whenLiveTimeoutOf}). Optional — a
398
+ * session double without it reads as not waking (the fast 45s fence,
399
+ * unchanged from the pre-fix behavior).
400
+ */
401
+ phase?: {
402
+ name?: SessionPhaseName;
403
+ runtime?: {
404
+ wake?: {
405
+ expectedWakePath?: string;
406
+ };
407
+ };
408
+ };
371
409
  /**
372
410
  * Core's NATIVE admission-ticket cancel (`Session.cancel`): hands back the
373
411
  * claim a still-QUEUED call waits on — once the call HAS a session, the
@@ -387,6 +425,53 @@ type PoolEntry = {
387
425
  responses: UrunResponses;
388
426
  gone: SessionGoneWatch;
389
427
  };
428
+ /**
429
+ * The replica's DECISION POOL wiring (serving-plan.md Phase 2) — built from
430
+ * the SAME BackhaulConfig the router uses, so slot sessions open through the
431
+ * ONE `openSessionFor` path with a per-slot `concurrency_key` (STABLE per
432
+ * slot: a replica restart re-adopts its own slot sessions instead of minting
433
+ * garbage, and N slots are N genuinely concurrent sessions — no singleton 403
434
+ * `session_name_not_yours`). The pool's ATTACHED sessions ARE readiness: the
435
+ * decision lane never consults presence or capacity to pick one.
436
+ */
437
+ interface DecisionPools {
438
+ /** Submit `min` session requests for the default target (called at boot). */
439
+ boot(): Promise<void>;
440
+ /** The rehome seam's sessionFor: least-loaded attached slot lease.
441
+ *
442
+ * THE NO-WAIT CONTRACT (owner ruling 2026-10-03): never awaits a slot
443
+ * open — throws {@link DecisionCapacityError} when no attached slot is
444
+ * ready, after submitting the out-of-band add. */
445
+ sessionFor(model: string | undefined): Promise<{
446
+ app: string;
447
+ entry: PoolEntry;
448
+ identity: ReturnType<typeof billingIdentityOf>;
449
+ }>;
450
+ /** The out-of-band warm: submit `min` slot opens for `model`'s target,
451
+ * never on a request's critical path and never awaited by a request. */
452
+ warmFor(model: string): Promise<void>;
453
+ /** THE READINESS PING: a real round trip against one attached slot
454
+ * (core `Session.whenLive`, short deadline) — false when none answers. */
455
+ pingReady(timeoutMs: number): Promise<boolean>;
456
+ /** Release the lease a decision stream rode (stream end — success or not). */
457
+ end(entry: PoolEntry): void;
458
+ /** A pool entry's runtime detached: PAUSED + re-submit (re-adopt). */
459
+ evict(entry: PoolEntry): void;
460
+ /** Idle scale-down, above min. Owner-driven cadence (the 5s reap tick). */
461
+ reap(): void;
462
+ stats(): Array<{
463
+ poolKey: string;
464
+ } & DecisionPoolStats>;
465
+ /**
466
+ * THE GOAWAY DRAIN (spec docs/design/session-stream-semantics.md §3):
467
+ * rollout/SIGTERM path — stop admitting (typed 503 `draining`), let
468
+ * in-flight decisions finish (bounded by `timeoutMs`), then explicitly end
469
+ * every slot's session. Call BEFORE `server.close()` so no resident is
470
+ * killed mid-stream and no caller sees a bare 429/000.
471
+ */
472
+ drain(timeoutMs?: number): Promise<void>;
473
+ close(): Promise<void>;
474
+ }
390
475
 
391
476
  /**
392
477
  * PER-CALLER BACKHAULS — the multi-tenant half of the hosted endpoint.
@@ -459,10 +544,12 @@ interface TenantRegistryOptions {
459
544
  apiUrl: string;
460
545
  /** The model-catalog oracle for routing rule 5, or null. */
461
546
  catalog: CatalogConfig | null;
462
- /** Injected in tests; production builds real uRun backhauls. */
547
+ /** Injected in tests; production builds real uRun backhauls. A stub may
548
+ * also carry its own `decision` pool (tests drive the readiness ping). */
463
549
  build?: (caller: CallerIdentity) => {
464
550
  router: ModelRouter<PoolEntry>;
465
551
  clients: ProxyClients;
552
+ decision?: DecisionPools;
466
553
  };
467
554
  }
468
555
  /**
@@ -496,10 +583,34 @@ declare class TenantRegistry {
496
583
  */
497
584
  private label;
498
585
  private build;
586
+ /**
587
+ * THE POOL'S OWNER-DRIVEN IDLE SCALE-DOWN. The pool owns no timers
588
+ * (decision-pool.ts) — someone must call `reap()` on a cadence. One
589
+ * unref'd interval per registry, started only when a tenant actually built
590
+ * a decision pool, reaps every live tenant's pool on the same 5s cadence
591
+ * the local CLI proxy uses.
592
+ */
593
+ private ensureDecisionReaper;
594
+ private decisionReaper;
499
595
  /** The backhaul for THIS caller, opened on first use and reused after. */
500
596
  clientsFor(caller: CallerIdentity): ProxyClients;
501
597
  /** Live tenant count — the readiness/ops view, and the tests' assertion. */
502
598
  get size(): number;
599
+ /**
600
+ * THE READINESS SEAM: the live decision pools this replica could serve a
601
+ * decision from, for the hosted `/readyz` composition (a REAL session ping
602
+ * against one attached slot — owner ruling 2026-10-03). Empty when no
603
+ * tenant has built a pool (the honest "nothing to ping yet").
604
+ */
605
+ decisionPools(): IterableIterator<DecisionPools>;
606
+ /**
607
+ * THE OUT-OF-BAND WARM SEAM (owner ruling 2026-10-03: adding is never on
608
+ * the request path). Builds the tenant for `caller` (the SHARED org
609
+ * credential at boot) and returns its decision pool, whose `warmFor(model)`
610
+ * submits the slot opens WITHOUT any request waiting on them. Null when
611
+ * the caller built no pool (env gate off).
612
+ */
613
+ decisionWarmerFor(caller: CallerIdentity): DecisionPools | null;
503
614
  /** Shutdown: end every pooled session through `Session.end()`. */
504
615
  closeAll(): Promise<void>;
505
616
  }
@@ -1,8 +1,8 @@
1
1
  import { Server } from 'node:http';
2
2
  import * as _prometheus_io_client from '@prometheus-io/client';
3
3
  import { Registry } from '@prometheus-io/client';
4
- import { c as LedgerOutcome, I as InferenceRecord, S as SessionGoneError, P as ProxyClients, M as ModelRouter, i as UsageRowReporter, b as InferenceUsageRecord, e as LedgerWrite, d as LedgerRecorded, L as LedgerFailure } from '../responses-turn-DmzWIpmO.js';
5
- import { createClientToken } from '@urun-sh/core';
4
+ import { c as LedgerOutcome, I as InferenceRecord, S as SessionGoneError, j as billingIdentityOf, P as ProxyClients, M as ModelRouter, i as UsageRowReporter, b as InferenceUsageRecord, e as LedgerWrite, d as LedgerRecorded, L as LedgerFailure } from '../responses-turn-2UJImii3.js';
5
+ import { createClientToken, SessionPhaseName } from '@urun-sh/core';
6
6
  import { U as UrunResponses } from '../ResponsesClient-CSSrOYD8.js';
7
7
  import { b as UrunSessionLike } from '../types-CHPtJx6d.js';
8
8
  import '../models-DUdx_Y6X.js';
@@ -105,6 +105,24 @@ declare class OrgResolver {
105
105
  clear(): void;
106
106
  }
107
107
 
108
+ interface DecisionPoolStats {
109
+
110
+ requested: number;
111
+ attached: number;
112
+
113
+ queued: number;
114
+ paused: number;
115
+
116
+ inFlight: number;
117
+
118
+ draining: boolean;
119
+
120
+ misses: number;
121
+ missesPastWindow: number;
122
+
123
+ lastMissAgeMs: number | null;
124
+ }
125
+
108
126
  interface SessionGoneWatch {
109
127
 
110
128
  gone(): SessionGoneError | null;
@@ -134,6 +152,15 @@ type OwnedSession = UrunSessionLike & {
134
152
  signal?: AbortSignal;
135
153
  }) => Promise<void>;
136
154
 
155
+ phase?: {
156
+ name?: SessionPhaseName;
157
+ runtime?: {
158
+ wake?: {
159
+ expectedWakePath?: string;
160
+ };
161
+ };
162
+ };
163
+
137
164
  cancel?: () => Promise<unknown>;
138
165
  };
139
166
 
@@ -143,6 +170,33 @@ type PoolEntry = {
143
170
  gone: SessionGoneWatch;
144
171
  };
145
172
 
173
+ interface DecisionPools {
174
+
175
+ boot(): Promise<void>;
176
+
177
+ sessionFor(model: string | undefined): Promise<{
178
+ app: string;
179
+ entry: PoolEntry;
180
+ identity: ReturnType<typeof billingIdentityOf>;
181
+ }>;
182
+
183
+ warmFor(model: string): Promise<void>;
184
+
185
+ pingReady(timeoutMs: number): Promise<boolean>;
186
+
187
+ end(entry: PoolEntry): void;
188
+
189
+ evict(entry: PoolEntry): void;
190
+
191
+ reap(): void;
192
+ stats(): Array<{
193
+ poolKey: string;
194
+ } & DecisionPoolStats>;
195
+
196
+ drain(timeoutMs?: number): Promise<void>;
197
+ close(): Promise<void>;
198
+ }
199
+
146
200
  declare const MAX_TENANTS = 512;
147
201
  interface TenantRegistryOptions {
148
202
 
@@ -155,6 +209,7 @@ interface TenantRegistryOptions {
155
209
  build?: (caller: CallerIdentity) => {
156
210
  router: ModelRouter<PoolEntry>;
157
211
  clients: ProxyClients;
212
+ decision?: DecisionPools;
158
213
  };
159
214
  }
160
215
 
@@ -168,10 +223,17 @@ declare class TenantRegistry {
168
223
  private label;
169
224
  private build;
170
225
 
226
+ private ensureDecisionReaper;
227
+ private decisionReaper;
228
+
171
229
  clientsFor(caller: CallerIdentity): ProxyClients;
172
230
 
173
231
  get size(): number;
174
232
 
233
+ decisionPools(): IterableIterator<DecisionPools>;
234
+
235
+ decisionWarmerFor(caller: CallerIdentity): DecisionPools | null;
236
+
175
237
  closeAll(): Promise<void>;
176
238
  }
177
239
 
@@ -1 +1 @@
1
- import{A as x,B as v,C as m,D as y,E as B,F as H,G as P,H as u,I as G,J as U,K as F,L as X,M as Y,N as b,O as h,P as k,Q as K,R as V,S as j,T as W,U as q,a as r,b as o,c as t,d as E,e as n,f as _,g as a,h as T,i as O,j as i,k as s,l as I,m as p,n as A,o as R,p as S,q as N,r as C,s as D,t as L,u as M,v as d,w as f,x as l,y as c,z as g}from"../chunk-CL3LVMNL.js";import"../chunk-7ZH2UHK6.js";import"../chunk-K23AZPI4.js";import"../chunk-5SBYFTBD.js";import"../chunk-76BZLCGT.js";import"../chunk-BAKPG5S3.js";import"../chunk-3JWYIKHM.js";import"../chunk-6M5JK4YC.js";import"../chunk-7V2JKPIG.js";import{c as e}from"../chunk-YSFSRI3D.js";e();export{N as ANONYMOUS_KEY_ID,y as BIND_HOST,R as BUCKET_DOMAIN,O as BoundedLabel,f as ControlPlaneUnavailableError,X as ConversationBackhauls,F as ConversationCapacityError,v as DEFAULT_PORT,I as EDGE_IDENTITY_PORT,A as EDGE_KEY_FINGERPRINT_HEADER,p as EDGE_KEY_ID_HEADER,i as InferenceMetrics,Y as LEDGER_FUNCTION_PATH,b as LEDGER_WRITE_TIMEOUT_MS,V as LedgerClient,h as LedgerDuplicateError,k as LedgerSurfaceError,g as MAX_CACHED_KEYS,G as MAX_CONVERSATIONS,U as MAX_CONVERSATION_HANDLES,n as MAX_MODEL_LABELS,_ as MAX_ORG_LABELS,H as MAX_TENANTS,o as METRICS_PATH,r as METRICS_PORT,E as NO_MODEL_LABEL,c as ORG_BINDING_TTL_MS,t as OTHER_LABEL,x as OrgResolver,d as ProxyAuthError,W as READINESS_TIMEOUT_MS,j as READINESS_TTL_MS,m as SERVE_FUNCTION,S as TIER_DOMAIN,u as TenantRegistry,l as bearerFrom,L as bearerTokenOf,M as createEdgeIdentityServer,q as createHostedProxy,s as createMetricsServer,C as edgeBucketId,D as edgeTierFingerprint,a as laneOf,K as parseLedgerRecorded,B as resolveHostedConfig,T as statusClassOf,P as tenantSubject};
1
+ import{A as x,B as v,C as m,D as y,E as B,F as H,G as P,H as u,I as G,J as U,K as F,L as X,M as Y,N as b,O as h,P as k,Q as K,R as V,S as j,T as W,U as q,a as r,b as o,c as t,d as E,e as n,f as _,g as a,h as T,i as O,j as i,k as s,l as I,m as p,n as A,o as R,p as S,q as N,r as C,s as D,t as L,u as M,v as d,w as f,x as l,y as c,z as g}from"../chunk-FHGSREBO.js";import"../chunk-JOOR4RUT.js";import"../chunk-K23AZPI4.js";import"../chunk-ERRG6R4T.js";import"../chunk-76BZLCGT.js";import"../chunk-CUDFHFNX.js";import"../chunk-3JWYIKHM.js";import"../chunk-6M5JK4YC.js";import"../chunk-7V2JKPIG.js";import{c as e}from"../chunk-YSFSRI3D.js";e();export{N as ANONYMOUS_KEY_ID,y as BIND_HOST,R as BUCKET_DOMAIN,O as BoundedLabel,f as ControlPlaneUnavailableError,X as ConversationBackhauls,F as ConversationCapacityError,v as DEFAULT_PORT,I as EDGE_IDENTITY_PORT,A as EDGE_KEY_FINGERPRINT_HEADER,p as EDGE_KEY_ID_HEADER,i as InferenceMetrics,Y as LEDGER_FUNCTION_PATH,b as LEDGER_WRITE_TIMEOUT_MS,V as LedgerClient,h as LedgerDuplicateError,k as LedgerSurfaceError,g as MAX_CACHED_KEYS,G as MAX_CONVERSATIONS,U as MAX_CONVERSATION_HANDLES,n as MAX_MODEL_LABELS,_ as MAX_ORG_LABELS,H as MAX_TENANTS,o as METRICS_PATH,r as METRICS_PORT,E as NO_MODEL_LABEL,c as ORG_BINDING_TTL_MS,t as OTHER_LABEL,x as OrgResolver,d as ProxyAuthError,W as READINESS_TIMEOUT_MS,j as READINESS_TTL_MS,m as SERVE_FUNCTION,S as TIER_DOMAIN,u as TenantRegistry,l as bearerFrom,L as bearerTokenOf,M as createEdgeIdentityServer,q as createHostedProxy,s as createMetricsServer,C as edgeBucketId,D as edgeTierFingerprint,a as laneOf,K as parseLedgerRecorded,B as resolveHostedConfig,T as statusClassOf,P as tenantSubject};
@@ -1,4 +1,4 @@
1
- import{a as z}from"../chunk-76BZLCGT.js";import{e as W,h as Q}from"../chunk-BAKPG5S3.js";import"../chunk-7V2JKPIG.js";import{c as C}from"../chunk-YSFSRI3D.js";C();import{createAssistantMessageEventStream as he}from"@earendil-works/pi-ai";import{mkdirSync as we,openSync as _e,writeSync as ke}from"fs";import{dirname as ve}from"path";C();import{appendFileSync as de,mkdirSync as pe}from"fs";import fe from"os";import{dirname as ge,join as me}from"path";import{format as ye}from"util";function J(t=fe.homedir()){return me(t,".urun","logs","pi-extension.log")}var V=!1;function te(t,e){let n=J();try{pe(ge(n),{recursive:!0}),de(n,`${new Date().toISOString()} [console.${t}] [urun] ${ye(...e)}
1
+ import{a as z}from"../chunk-76BZLCGT.js";import{e as W,h as Q}from"../chunk-CUDFHFNX.js";import"../chunk-7V2JKPIG.js";import{c as C}from"../chunk-YSFSRI3D.js";C();import{createAssistantMessageEventStream as he}from"@earendil-works/pi-ai";import{mkdirSync as we,openSync as _e,writeSync as ke}from"fs";import{dirname as ve}from"path";C();import{appendFileSync as de,mkdirSync as pe}from"fs";import fe from"os";import{dirname as ge,join as me}from"path";import{format as ye}from"util";function J(t=fe.homedir()){return me(t,".urun","logs","pi-extension.log")}var V=!1;function te(t,e){let n=J();try{pe(ge(n),{recursive:!0}),de(n,`${new Date().toISOString()} [console.${t}] [urun] ${ye(...e)}
2
2
  `)}catch(o){if(!V){V=!0;try{process.stderr.write(`[urun] pi-extension quiet console: cannot write ${n} (${String(o)}); further urun-side console output will be dropped
3
3
  `)}catch{}}}}var f=t=>(...e)=>te(t,e),j={log:f("log"),info:f("info"),warn:f("warn"),error:f("error"),debug:f("debug"),trace:f("trace"),dir:f("dir"),table:f("table"),group:f("group"),groupCollapsed:f("groupCollapsed"),groupEnd:f("groupEnd"),count:f("count"),countReset:f("countReset"),time:f("time"),timeLog:f("timeLog"),timeEnd:f("timeEnd"),assert:(t,...e)=>{t||te("assert",e.length>0?e:["Assertion failed"])}};function q(t){try{process.stderr.write(t)}catch{}}C();async function ne(t){let e=await Q(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 ae="urun-serve",xe="serve",Re=131072,be=16384,oe=3,Te=42e4,Ee=6e4,re=2,Se=15e3;function Ae(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()||W,fnName:(t.URUN_FUNCTION??"").trim()||xe}}function Ue(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 s=(t.URUN_API_KEY??"").trim();if(!s)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:s,gatewayUrl:l}}}function Ie(t){let e=null;return n=>{e===null&&(we(ve(t),{recursive:!0}),e=_e(t,"a"));let o=n.detail?` ${JSON.stringify(n.detail)}`:"";ke(e,`${new Date().toISOString()} [${n.level}] [urun] ${n.message}${o}
4
4
  `)}}function Pe(t){let e=Ie(J());return async(n,o,s)=>{let{baseUrl:l,orgId:i,auth:p}=Ue(n),{App:k,createClientToken:a}=await t(),m=(p.lane==="jwt"?k(o,{baseUrl:l,orgId:i,jwt:p.jwt,diagnosticSink:e}):k(o,{baseUrl:l,orgId:i,diagnosticSink:e,getAccessToken:async()=>(await a(p.apiKey,{baseUrl:p.gatewayUrl,expiresIn:300,allowedFunctions:[`${o}/${s}`]})).token}))[s];if(typeof m!="function")throw new Error(`urun pi extension: app "${o}" has no function "${s}"`);let h=m();if(typeof h.end!="function")throw new Error(`urun pi extension: app "${o}" function "${s}" returned a session without end()`);let A=h.connect;return typeof A=="function"&&await A.call(h),h}}var Ce=Pe(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 Ne(t,e){try{return Promise.resolve(t.end()).then(()=>{},n=>e(n))}catch(n){return e(n),Promise.resolve()}}function $e(t){if(t?.hasUI===!1)return!0;if(t?.hasUI===!0)return!1;let e=process.argv.slice(2);if(e.includes("-p")||e.includes("--print"))return!0;let n=e.indexOf("--mode");return n!==-1&&(e[n+1]==="json"||e[n+1]==="rpc")?!0:!process.stdin.isTTY||!process.stdout.isTTY}function le(t,e){return`uRun: releasing the pooled "${t}" session failed \u2014 the backend session may stay allocated until the platform reclaims it: ${e instanceof Error?e.message:String(e)}`}var H=class{constructor(e,n,o,s=(l,i)=>j.warn(le(l,i))){this.open=e;this.env=n;this.fnName=o;this.onReleaseError=s}open;env;fnName;onReleaseError;pool=new Map;releasing=new Set;acquire(e){let n=this.pool.get(e);if(!n){let o=Promise.resolve(this.open(this.env,e,this.fnName)).then(s=>({session:s,responses:new z(s)}));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);if(!n)return Promise.resolve();this.pool.delete(e);let o=n.then(s=>Ne(s.session,l=>this.onReleaseError(e,l)),()=>{});return this.releasing.add(o),o.then(()=>this.releasing.delete(o)),o}closeAll(){let e=[...this.pool.keys()].map(n=>this.evict(n));return Promise.all([...e,...this.releasing]).then(()=>{})}};function Le(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:De(n.content)});continue}if(n.role==="assistant"&&Array.isArray(n.content)){let s="",l=()=>{s&&(e.push({role:"assistant",content:s}),s="")};for(let i of n.content)if(i.type==="text")s+=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:Me(n.content)})}return Oe(e)}function Oe(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(s=>s.length>0).join(`