@urun-sh/openai 0.5.6 → 0.6.1

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.
Files changed (52) hide show
  1. package/dist/{ResponsesClient-BE3-hx3m.d.ts → ResponsesClient-CSSrOYD8.d.ts} +5 -1
  2. package/dist/{ResponsesClient-DjZWjlFH.d.cts → ResponsesClient-_OZERUjH.d.cts} +9 -1
  3. package/dist/{chunk-7M6LY6DR.js → chunk-3JWYIKHM.js} +1 -1
  4. package/dist/{chunk-BSHT6RZZ.js → chunk-6M5JK4YC.js} +1 -1
  5. package/dist/chunk-76BZLCGT.js +1 -0
  6. package/dist/chunk-7V2JKPIG.js +1 -0
  7. package/dist/{chunk-5HKWNK3O.js → chunk-K23AZPI4.js} +1 -1
  8. package/dist/chunk-T2LNHDPS.js +7 -0
  9. package/dist/chunk-TMQJY56F.js +4 -0
  10. package/dist/chunk-WEBOBE7Z.js +58 -0
  11. package/dist/chunk-X3GLH2HQ.js +1 -0
  12. package/dist/gemini-live.cjs +2 -2
  13. package/dist/gemini-live.d.cts +75 -7
  14. package/dist/gemini-live.d.ts +30 -7
  15. package/dist/gemini-live.js +1 -1
  16. package/dist/hosted/bin.cjs +37 -35
  17. package/dist/hosted/bin.js +1 -1
  18. package/dist/hosted/index.cjs +33 -31
  19. package/dist/hosted/index.d.cts +70 -4
  20. package/dist/hosted/index.d.ts +21 -4
  21. package/dist/hosted/index.js +1 -1
  22. package/dist/index.cjs +1 -1
  23. package/dist/index.d.cts +4 -4
  24. package/dist/index.d.ts +4 -4
  25. package/dist/index.js +1 -1
  26. package/dist/pi-extension/index.cjs +7 -7
  27. package/dist/pi-extension/index.d.cts +2 -2
  28. package/dist/pi-extension/index.d.ts +2 -2
  29. package/dist/pi-extension/index.js +1 -1
  30. package/dist/pi-extension/standalone.cjs +53 -53
  31. package/dist/proxy/cli.cjs +48 -46
  32. package/dist/proxy/cli.js +15 -14
  33. package/dist/proxy/index.cjs +25 -24
  34. package/dist/proxy/index.d.cts +142 -25
  35. package/dist/proxy/index.d.ts +22 -11
  36. package/dist/proxy/index.js +1 -1
  37. package/dist/{responses-turn-Dr37N3kH.d.ts → responses-turn-EwxfRJJg.d.ts} +187 -7
  38. package/dist/{responses-turn-tNUHq5b0.d.cts → responses-turn-vMefRdgJ.d.cts} +707 -23
  39. package/dist/{translator-Bh0Bp_Ie.d.cts → translator-CO8W_hmJ.d.cts} +1 -1
  40. package/dist/{translator-BCoRFaTs.d.ts → translator-Ddd65sXR.d.ts} +1 -1
  41. package/dist/{types-lsVTbNcH.d.cts → types-CHPtJx6d.d.cts} +13 -0
  42. package/dist/{types-lsVTbNcH.d.ts → types-CHPtJx6d.d.ts} +4 -0
  43. package/dist/{video-out-CCksIcj8.d.cts → video-out-BsuLqlID.d.cts} +1 -1
  44. package/dist/{video-out-IGQ4YQ-c.d.ts → video-out-Cawtm7SF.d.ts} +1 -1
  45. package/package.json +4 -2
  46. package/dist/chunk-2T2YYBVX.js +0 -1
  47. package/dist/chunk-3WAJD62J.js +0 -4
  48. package/dist/chunk-FP4RSAIE.js +0 -1
  49. package/dist/chunk-HR5H6S7L.js +0 -1
  50. package/dist/chunk-NY23USZF.js +0 -57
  51. package/dist/chunk-VLRMJRLS.js +0 -6
  52. /package/dist/{chunk-5CCJUNH7.js → chunk-YSFSRI3D.js} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { Server, IncomingMessage } from 'node:http';
2
- import { f as ProxyHandlerOptions, P as ProxyClients } from '../responses-turn-tNUHq5b0.cjs';
3
- export { D as DialObserver, a as DialReport, g as ProxyIdentity, h as ProxyVideoOutLane, S as SessionGoneError, U as UnknownModelError } from '../responses-turn-tNUHq5b0.cjs';
4
- export { h as GEMINI_LIVE_PATH, V as VIDEO_OUT_SETUP_KEY } from '../translator-Bh0Bp_Ie.cjs';
2
+ import { f as ProxyHandlerOptions, P as ProxyClients } from '../responses-turn-vMefRdgJ.cjs';
3
+ export { D as DialObserver, a as DialReport, g as ProxyIdentity, h as ProxyVideoOutLane, S as SessionGoneError, U as UnknownModelError } from '../responses-turn-vMefRdgJ.cjs';
4
+ export { h as GEMINI_LIVE_PATH, V as VIDEO_OUT_SETUP_KEY } from '../translator-CO8W_hmJ.cjs';
5
5
  import { WebSocket } from 'ws';
6
6
  import '../models-DUdx_Y6X.cjs';
7
- import '../video-out-CCksIcj8.cjs';
8
- import '../types-lsVTbNcH.cjs';
7
+ import '../video-out-BsuLqlID.cjs';
8
+ import '../types-CHPtJx6d.cjs';
9
9
 
10
10
  /**
11
11
  * The local OpenAI-compatible proxy — `npx @urun-sh/openai proxy`.
@@ -253,9 +253,19 @@ declare function serveGeminiLiveSocket(ws: WebSocket, call: GeminiLiveCall, regi
253
253
  * `next()` listener, so sibling lanes (Gemini Live, Responses WS) and the
254
254
  * hosted composition keep their own upgrade hooks.
255
255
  * - Clients are resolved/authenticated ASYNCHRONOUSLY BEFORE the upgrade is
256
- * accepted: no 101 is written until `resolver.resolve(req)` settles. A
257
- * thrown error maps `err.status` (default 502) to the HTTP reject;
258
- * 401/403 keep their status.
256
+ * accepted: no 101 is written until `resolver.resolve(req, signal)`
257
+ * settles. A thrown error maps `err.status` (default 502) to the HTTP
258
+ * reject; 401/403 keep their status.
259
+ * - THE CLIENT SOCKET'S OWN CLOSE is the cancellation signal for the wait:
260
+ * a `close`/`error` on the raw pre-upgrade socket aborts the signal the
261
+ * resolver rides. A resolver that settles AFTER the client vanished never
262
+ * upgrades — its binding is released through the binding's own `release`
263
+ * seam (the native detach; a still-queued admission ticket is cancelled
264
+ * underneath it by the backhaul's abort path). A client that closes after
265
+ * admission tears down through the connection's own ws-close wiring.
266
+ * - ONE structured log line per upgrade lifecycle event (`realtime_upgrade`:
267
+ * accept → admit → close, with the binding's session id and the client
268
+ * close reason) — the lane was previously invisible in the process log.
259
269
  * - The resolved binding carries a PRIVATE native uRun session (fresh or
260
270
  * explicitly-resumed) and, iff voice, a PRIVATE audio bridge — never the
261
271
  * pooled tenant lane. The connection's cross-caller claim is invariant
@@ -271,11 +281,16 @@ declare const OPENAI_REALTIME_PATH = "/v1/realtime";
271
281
  * The resolver seam — the ONLY credential, modality, and session-allocation
272
282
  * authority this adapter recognizes. Implemented by Main's composition (and
273
283
  * by tests with an injected fake). Accepted in EITHER form: a bare
274
- * `(req) => Promise<binding>` (the {@link ProxyClientsFor}-style convention)
275
- * or a `{ resolve(req) }` object.
284
+ * `(req, signal) => Promise<binding>` (the {@link ProxyClientsFor}-style
285
+ * convention) or a `{ resolve(req, signal) }` object. `signal` aborts when
286
+ * the CLIENT SOCKET closes/errors before the upgrade is accepted — the
287
+ * resolver SHOULD abandon its admission wait on it (the backhaul's
288
+ * `openAudioOn` rides the same signal into core `whenLive`'s own abort
289
+ * support); a resolver that ignores it still cannot admit an upgrade to a
290
+ * vanished client: the settled binding is released, never upgraded.
276
291
  */
277
- type OpenAIRealtimeResolver<S = unknown> = ((req: IncomingMessage) => Promise<RealtimeBinding<S>>) | {
278
- resolve(req: IncomingMessage): Promise<RealtimeBinding<S>>;
292
+ type OpenAIRealtimeResolver<S = unknown> = ((req: IncomingMessage, signal?: AbortSignal) => Promise<RealtimeBinding<S>>) | {
293
+ resolve(req: IncomingMessage, signal?: AbortSignal): Promise<RealtimeBinding<S>>;
279
294
  };
280
295
  interface RealtimeBinding<S = unknown> {
281
296
  /**
@@ -287,11 +302,15 @@ interface RealtimeBinding<S = unknown> {
287
302
  * - `session.sendResponseCreate(params, input, requestId)` (the direct
288
303
  * SdkTransport-style seam), or
289
304
  * - `clients.createResponse(params)` — the canonical ProxyClients seam
290
- * the conversation factory hands out (`input` rides inside `params`).
305
+ * shape (`input` rides inside `params`). The shared binding composition
306
+ * (binding.ts, ENG-446) hands out a PINNED view of it: the call dials
307
+ * `createResponseOn(handle, …)` on the ONE pooled session the binding
308
+ * resolved with the audio bridge, so no turn on the connection can
309
+ * reach a second pooled session behind the bridge's back.
291
310
  * A binding with neither is rejected at upgrade time, LOUD.
292
311
  */
293
312
  session?: S & {
294
- sendResponseCreate?(params: unknown, input: unknown[], requestId: string): AsyncIterable<unknown>;
313
+ sendResponseCreate?(params: unknown, input: unknown[], requestId: string): Promise<AsyncIterable<unknown>>;
295
314
  };
296
315
  clients?: Pick<ProxyClients, 'createResponse'>;
297
316
  /**
@@ -305,6 +324,15 @@ interface RealtimeBinding<S = unknown> {
305
324
  audio: {
306
325
  appendInputAudio(base64Pcm16: string): void;
307
326
  onOutputAudio(handler: (b64: string) => void): () => void;
327
+ /**
328
+ * The pooled uRun session this lane rides (backhaul `openAudioOn`
329
+ * reports core `Session.id`), when the backhaul knows it — the field the
330
+ * `realtime_upgrade` log line puts on every lifecycle event so an
331
+ * orphaned session is traceable from the proxy log alone. Null is the
332
+ * honest absence (an id-less session reports no id); sessionIdOf
333
+ * normalizes it to the omitted field below.
334
+ */
335
+ sessionId?: string | null;
308
336
  };
309
337
  /** Cross-caller reuse registry (invariant validation; see connection.ts). */
310
338
  openaiRealtimeClaims?: Set<RealtimeBinding['audioSession']>;
@@ -340,6 +368,17 @@ interface RealtimeBinding<S = unknown> {
340
368
  }
341
369
  interface OpenAIRealtimeOptions<S = unknown> {
342
370
  resolver: OpenAIRealtimeResolver<S>;
371
+ /**
372
+ * Where the per-upgrade structured `realtime_upgrade` lines go (ONE
373
+ * newline-terminated JSON object per lifecycle event: accept → admit →
374
+ * close). Absent, the line goes to this process's stdout through the repo's
375
+ * canonical guarded write — the hosted container's collected log stream.
376
+ * Emitted unconditionally, never behind a verbosity flag: this lane's
377
+ * lifecycle was previously invisible in the process log, which is exactly
378
+ * why an orphaned queued admission could only be diagnosed from the
379
+ * session-server side.
380
+ */
381
+ log?: (line: string) => void;
343
382
  }
344
383
  /**
345
384
  * Attach the OpenAI Realtime WS endpoint to `server`. Upgrades on any other
@@ -360,6 +399,22 @@ declare function attachOpenAIRealtime<S = unknown>(server: Server, options: Open
360
399
  * Multi-attach on the SAME authorized session (explicit resume) is the one
361
400
  * sanctioned shared form: one bridge owner at a time, validated by claim.
362
401
  *
402
+ * ONE SESSION IDENTITY PER CONNECTION (ENG-446): the shared binding
403
+ * composition resolves the connection's pooled session ONCE and pins BOTH the
404
+ * audio bridge (`openAudioOn(handle)`) and every turn (`createResponseOn
405
+ * (handle, …)`, threaded through the binding's `clients` view) to that one
406
+ * handle. This adapter therefore treats a turn seam failure that means THE
407
+ * SESSION (not the request) is dead — a {@link SessionGoneError} (the pool
408
+ * replaced or dropped the pinned entry), or a dial that dies before any
409
+ * client-visible content — as the LOUD `session_gone` CLOSE of the whole
410
+ * connection: an `error` event naming the cause, then the 1011 close. The
411
+ * bridge stays bound to the dead session and NEVER rebinds, and the turn is
412
+ * never retried on a replacement behind the bridge's back (the two-session
413
+ * race the speech lane's #500 pin fixed for its lane). The ONE exception is
414
+ * core's own BOUNDED ADMISSION VERDICT (`SessionFailedError` never-live /
415
+ * create-failed — the platform's answer about this assignment, not a death):
416
+ * it stays the per-turn `response.failed`, exactly as before.
417
+ *
363
418
  * NO-OP POLICY: every unsupported client event or backend gap renders as a
364
419
  * LOUD `error` server event (or a close) — never a silently ignored frame.
365
420
  */
@@ -398,7 +453,10 @@ declare class OpenAIRealtimeConnection<S = unknown> {
398
453
  constructor(opts: {
399
454
  ws: WebSocket;
400
455
  binding: RealtimeBinding<S>;
401
- onClosed?: (conn: OpenAIRealtimeConnection<S>) => void;
456
+ /** Fired once at teardown, with the reason (the surface's structured close log rides it). */
457
+ onClosed?: (conn: OpenAIRealtimeConnection<S>, info: {
458
+ reason: string;
459
+ }) => void;
402
460
  });
403
461
  /**
404
462
  * Consume the backend's OWN turn/transcript lane (§5 stt stream): the
@@ -428,7 +486,9 @@ declare class OpenAIRealtimeConnection<S = unknown> {
428
486
  * The upstream turn seam, normalized: a binding carries EITHER
429
487
  * `session.sendResponseCreate(params, input, requestId)` (direct
430
488
  * SdkTransport-style) OR `clients.createResponse(params)` (the canonical
431
- * ProxyClients seam the shared conversation factory hands out). A binding
489
+ * ProxyClients seam SHAPE — the shared binding composition hands out a
490
+ * PINNED view whose call dials `createResponseOn(handle, …)` on the ONE
491
+ * pooled session the audio bridge rides, ENG-446). A binding
432
492
  * with neither was already rejected at upgrade time; this is the loud
433
493
  * backstop. The ProxyClients seam is PROMISE-VALUED
434
494
  * (`rehomingCreateResponse` dials inside an async function — its
@@ -474,6 +534,45 @@ declare class OpenAIRealtimeConnection<S = unknown> {
474
534
  */
475
535
  private doneResponse;
476
536
  private upstreamErrorBody;
537
+ /**
538
+ * THE SESSION-GONE LOUD CLOSE (ENG-446): an `error` event naming the cause
539
+ * (`session_gone`), then the abnormal close and teardown. The connection's
540
+ * audio bridge is bound to the dead/replaced session and NEVER rebinds, and
541
+ * the turn is never retried on another session behind the bridge's back —
542
+ * the only honest moves are to say why and close.
543
+ */
544
+ private failSessionGone;
545
+ /**
546
+ * Classify ONE upstream turn failure (the dial throwing, or the stream
547
+ * throwing mid-read) — the two outcomes are the LOUD `session_gone` close
548
+ * and the per-turn fault the lane always had:
549
+ *
550
+ * - a {@link SessionGoneError} (the pool no longer holds the handle's
551
+ * session, or a replacement serves under it now) closes the connection
552
+ * LOUDLY, pre- or post-content alike — and post-CANCEL alike: the
553
+ * bridge is orphaned either way, and a cancelled turn must never mute
554
+ * a dead pinned session (round-1 review, CodeRabbit + Greptile);
555
+ * - a CANCELLED turn suppresses every OTHER late fault (round-1 review):
556
+ * `response.cancel` does not abort a pending dial, and the dial's
557
+ * rejection settles AFTER `cancelled` was set — the lane's pre-#511
558
+ * behaviour stands (`response.cancelled` from `inFlight.finally`, the
559
+ * connection stays open), so a generic late fault from the settling
560
+ * dial/read is swallowed here rather than closing the connection as
561
+ * `session_gone`;
562
+ * - a dial that dies BEFORE any client-visible content (nothing flushed)
563
+ * closes the connection LOUDLY too — under the pin there is no re-home,
564
+ * and keeping the connection open would leave the bridge attached to a
565
+ * session that cannot serve a turn, silently mute on the next
566
+ * response.create. The ONE exception is core's own BOUNDED ADMISSION
567
+ * VERDICT (`SessionFailedError` never-live / create-failed — the
568
+ * platform's answer about this assignment, not a death), which keeps
569
+ * the per-turn failure exactly as before;
570
+ * - everything else (content already flowed; the upstream answered with
571
+ * an `error` EVENT, handled elsewhere) is the per-turn fault — the
572
+ * connection stays open, and a later turn on the same pinned handle
573
+ * decides the connection's fate.
574
+ */
575
+ private upstreamTurnFault;
477
576
  private emitUpstreamFault;
478
577
  /**
479
578
  * Cancel the in-flight response. The upstream iterator is stopped through
@@ -502,11 +601,24 @@ declare class OpenAIRealtimeConnection<S = unknown> {
502
601
  * placements) through the SAME router-backed gate seam the Images lane uses
503
602
  * (`ProxyClients.supportsAudio` — `ModelRouter.supportsAudio`). A non-audio
504
603
  * model is refused LOUDLY with a 404 before anything is opened; a voice
505
- * binding acquires its PRIVATE audio bridge from `ProxyClients.openAudio`
506
- * (the pooled session's native `audio` lane at 24 kHz — the ONE canonical
507
- * session-audio wiring, `transport/media.ts` AUDIO_STREAM). There is no env-var
508
- * switch and no chat-default fall-through: an absent model resolves through
509
- * the router exactly like every other lane, and a chat default is refused
604
+ * binding rides ONE pooled-session identity for BOTH of its legs (ENG-446,
605
+ * the speech lane's #500 pin applied to the realtime lane): the connection
606
+ * resolves its pooled session ONCE (`ProxyClients.sessionHandle` — the same
607
+ * handle seam the speech lane pins its collector and turn with, here naming
608
+ * the INTERACTIVE pooled slot), opens its PRIVATE audio bridge on that exact
609
+ * handle (`openAudioOn(handle, signal)` — the pinned open), and drives every
610
+ * turn on the SAME handle (`createResponseOn(handle, …)`, threaded through
611
+ * the binding's `clients` view). The unpinned shape — the bridge via
612
+ * `openAudio(model)`, turns via the re-homing `createResponse` — let each leg
613
+ * resolve its OWN pooled session, so a dial that died before client-visible
614
+ * content re-homed the turn onto a REPLACEMENT session while the bridge
615
+ * stayed attached to the evicted one: the turn's audio was delivered to a
616
+ * session the client was not attached to, or a concurrent bridge on the
617
+ * replacement received another caller's audio. Behind the pin, a dead or
618
+ * replaced session is the connection's LOUD `session_gone` close
619
+ * (connection.ts), never a retry across sessions. There is no env-var switch
620
+ * and no chat-default fall-through: an absent model resolves through the
621
+ * router exactly like every other lane, and a chat default is refused
510
622
  * exactly like an explicitly named chat model.
511
623
  *
512
624
  * Used by BOTH compositions — the local `urun compat proxy` (fixed clients,
@@ -528,10 +640,15 @@ declare function realtimeModelOf(req: IncomingMessage): string | undefined;
528
640
  * - {@link UnknownModelError} ⇒ 404 with the router's own loud message.
529
641
  * - A non-audio verdict ⇒ 404 — the realtime lane never falls through to
530
642
  * the chat lane, in either direction.
531
- * - A voice verdict with no `openAudio` seam ⇒ 501 (a voice binding cannot
532
- * be served without its bridge; a voiceless downgrade is never silent).
643
+ * - A voice verdict with no `openAudioOn` seam ⇒ 501 (a voice binding cannot
644
+ * be served without its pinned bridge; a voiceless downgrade is never
645
+ * silent).
646
+ * - ONE pooled-session identity for the bridge AND every turn
647
+ * (`sessionHandle` once → `openAudioOn(handle, signal)` +
648
+ * `createResponseOn(handle, …)`), so no turn on this connection can ever
649
+ * resolve a different pooled session than the bridge.
533
650
  */
534
- declare function realtimeBindingFor(clients: Pick<ProxyClients, 'createResponse'> & Partial<Pick<ProxyClients, 'supportsAudio' | 'openAudio'>>, model: string | undefined): Promise<RealtimeBinding<ProxyClients>>;
651
+ declare function realtimeBindingFor(clients: Pick<ProxyClients, 'sessionHandle' | 'createResponseOn'> & Partial<Pick<ProxyClients, 'supportsAudio' | 'openAudioOn'>>, model: string | undefined, signal?: AbortSignal): Promise<RealtimeBinding<ProxyClients>>;
535
652
  /**
536
653
  * The LOCAL lane resolver: fixed pooled clients, optional fixed apiKey (the
537
654
  * same shared-secret rule the local Gemini Live lane applies — a mismatched
@@ -541,7 +658,7 @@ declare function realtimeBindingFor(clients: Pick<ProxyClients, 'createResponse'
541
658
  * {@link realtimeBindingFor} for the binding itself.
542
659
  */
543
660
  declare function fixedClientsResolver(clients: ProxyClients, apiKey?: string): {
544
- resolve(req: IncomingMessage): Promise<RealtimeBinding<ProxyClients>>;
661
+ resolve(req: IncomingMessage, signal?: AbortSignal): Promise<RealtimeBinding<ProxyClients>>;
545
662
  };
546
663
 
547
664
  export { type GeminiLiveCall, type GeminiLiveClients, OPENAI_REALTIME_PATH, type OpenAIProxyOptions, OpenAIRealtimeConnection, type OpenAIRealtimeOptions, type OpenAIRealtimeResolver, ProxyClients, type RealtimeBinding, ResumptionRegistry, attachGeminiLive, attachOpenAIRealtime, createOpenAIProxy, fixedClientsResolver, realtimeBindingFor, realtimeModelOf, serveGeminiLiveSocket };
@@ -1,11 +1,11 @@
1
1
  import { Server, IncomingMessage } from 'node:http';
2
- import { f as ProxyHandlerOptions, P as ProxyClients } from '../responses-turn-Dr37N3kH.js';
3
- export { D as DialObserver, a as DialReport, g as ProxyIdentity, h as ProxyVideoOutLane, S as SessionGoneError, U as UnknownModelError } from '../responses-turn-Dr37N3kH.js';
4
- export { h as GEMINI_LIVE_PATH, V as VIDEO_OUT_SETUP_KEY } from '../translator-BCoRFaTs.js';
2
+ import { f as ProxyHandlerOptions, P as ProxyClients } from '../responses-turn-EwxfRJJg.js';
3
+ export { D as DialObserver, a as DialReport, g as ProxyIdentity, h as ProxyVideoOutLane, S as SessionGoneError, U as UnknownModelError } from '../responses-turn-EwxfRJJg.js';
4
+ export { h as GEMINI_LIVE_PATH, V as VIDEO_OUT_SETUP_KEY } from '../translator-Ddd65sXR.js';
5
5
  import { WebSocket } from 'ws';
6
6
  import '../models-DUdx_Y6X.js';
7
- import '../video-out-IGQ4YQ-c.js';
8
- import '../types-lsVTbNcH.js';
7
+ import '../video-out-Cawtm7SF.js';
8
+ import '../types-CHPtJx6d.js';
9
9
 
10
10
  interface OpenAIProxyOptions extends ProxyHandlerOptions {
11
11
  clients: ProxyClients;
@@ -56,13 +56,13 @@ declare function serveGeminiLiveSocket(ws: WebSocket, call: GeminiLiveCall, regi
56
56
 
57
57
  declare const OPENAI_REALTIME_PATH = "/v1/realtime";
58
58
 
59
- type OpenAIRealtimeResolver<S = unknown> = ((req: IncomingMessage) => Promise<RealtimeBinding<S>>) | {
60
- resolve(req: IncomingMessage): Promise<RealtimeBinding<S>>;
59
+ type OpenAIRealtimeResolver<S = unknown> = ((req: IncomingMessage, signal?: AbortSignal) => Promise<RealtimeBinding<S>>) | {
60
+ resolve(req: IncomingMessage, signal?: AbortSignal): Promise<RealtimeBinding<S>>;
61
61
  };
62
62
  interface RealtimeBinding<S = unknown> {
63
63
 
64
64
  session?: S & {
65
- sendResponseCreate?(params: unknown, input: unknown[], requestId: string): AsyncIterable<unknown>;
65
+ sendResponseCreate?(params: unknown, input: unknown[], requestId: string): Promise<AsyncIterable<unknown>>;
66
66
  };
67
67
  clients?: Pick<ProxyClients, 'createResponse'>;
68
68
 
@@ -72,6 +72,8 @@ interface RealtimeBinding<S = unknown> {
72
72
  audio: {
73
73
  appendInputAudio(base64Pcm16: string): void;
74
74
  onOutputAudio(handler: (b64: string) => void): () => void;
75
+
76
+ sessionId?: string | null;
75
77
  };
76
78
 
77
79
  openaiRealtimeClaims?: Set<RealtimeBinding['audioSession']>;
@@ -92,6 +94,8 @@ interface RealtimeBinding<S = unknown> {
92
94
  }
93
95
  interface OpenAIRealtimeOptions<S = unknown> {
94
96
  resolver: OpenAIRealtimeResolver<S>;
97
+
98
+ log?: (line: string) => void;
95
99
  }
96
100
 
97
101
  declare function attachOpenAIRealtime<S = unknown>(server: Server, options: OpenAIRealtimeOptions<S>): () => Promise<void>;
@@ -130,7 +134,10 @@ declare class OpenAIRealtimeConnection<S = unknown> {
130
134
  constructor(opts: {
131
135
  ws: WebSocket;
132
136
  binding: RealtimeBinding<S>;
133
- onClosed?: (conn: OpenAIRealtimeConnection<S>) => void;
137
+
138
+ onClosed?: (conn: OpenAIRealtimeConnection<S>, info: {
139
+ reason: string;
140
+ }) => void;
134
141
  });
135
142
 
136
143
  private startTurnLane;
@@ -164,6 +171,10 @@ declare class OpenAIRealtimeConnection<S = unknown> {
164
171
 
165
172
  private doneResponse;
166
173
  private upstreamErrorBody;
174
+
175
+ private failSessionGone;
176
+
177
+ private upstreamTurnFault;
167
178
  private emitUpstreamFault;
168
179
 
169
180
  private cancelResponse;
@@ -177,10 +188,10 @@ declare class OpenAIRealtimeConnection<S = unknown> {
177
188
 
178
189
  declare function realtimeModelOf(req: IncomingMessage): string | undefined;
179
190
 
180
- declare function realtimeBindingFor(clients: Pick<ProxyClients, 'createResponse'> & Partial<Pick<ProxyClients, 'supportsAudio' | 'openAudio'>>, model: string | undefined): Promise<RealtimeBinding<ProxyClients>>;
191
+ declare function realtimeBindingFor(clients: Pick<ProxyClients, 'sessionHandle' | 'createResponseOn'> & Partial<Pick<ProxyClients, 'supportsAudio' | 'openAudioOn'>>, model: string | undefined, signal?: AbortSignal): Promise<RealtimeBinding<ProxyClients>>;
181
192
 
182
193
  declare function fixedClientsResolver(clients: ProxyClients, apiKey?: string): {
183
- resolve(req: IncomingMessage): Promise<RealtimeBinding<ProxyClients>>;
194
+ resolve(req: IncomingMessage, signal?: AbortSignal): Promise<RealtimeBinding<ProxyClients>>;
184
195
  };
185
196
 
186
197
  export { type GeminiLiveCall, type GeminiLiveClients, OPENAI_REALTIME_PATH, type OpenAIProxyOptions, OpenAIRealtimeConnection, type OpenAIRealtimeOptions, type OpenAIRealtimeResolver, ProxyClients, type RealtimeBinding, ResumptionRegistry, attachGeminiLive, attachOpenAIRealtime, createOpenAIProxy, fixedClientsResolver, realtimeBindingFor, realtimeModelOf, serveGeminiLiveSocket };
@@ -1 +1 @@
1
- import{Q as I,a as n,b as p,c as m,f as l,g as a,h as x,i as s,j as O,k as f}from"../chunk-NY23USZF.js";import{d as r,e as i}from"../chunk-3WAJD62J.js";import{a as o,h as t}from"../chunk-7M6LY6DR.js";import"../chunk-BSHT6RZZ.js";import{c as e}from"../chunk-5CCJUNH7.js";e();export{o as GEMINI_LIVE_PATH,a as OPENAI_REALTIME_PATH,l as OpenAIRealtimeConnection,n as ResumptionRegistry,i as SessionGoneError,r as UnknownModelError,t as VIDEO_OUT_SETUP_KEY,p as attachGeminiLive,x as attachOpenAIRealtime,I as createOpenAIProxy,f as fixedClientsResolver,O as realtimeBindingFor,s as realtimeModelOf,m as serveGeminiLiveSocket};
1
+ import{B as l,C as a,D as x,E as s,F as O,G as f,S as I,a as n,b as p,c as m}from"../chunk-WEBOBE7Z.js";import{d as r,e as i}from"../chunk-TMQJY56F.js";import{a as o,h as t}from"../chunk-3JWYIKHM.js";import"../chunk-6M5JK4YC.js";import{c as e}from"../chunk-YSFSRI3D.js";e();export{o as GEMINI_LIVE_PATH,a as OPENAI_REALTIME_PATH,l as OpenAIRealtimeConnection,n as ResumptionRegistry,i as SessionGoneError,r as UnknownModelError,t as VIDEO_OUT_SETUP_KEY,p as attachGeminiLive,x as attachOpenAIRealtime,I as createOpenAIProxy,f as fixedClientsResolver,O as realtimeBindingFor,s as realtimeModelOf,m as serveGeminiLiveSocket};