realtime-voice-agents 2.3.0 → 2.5.0
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/README.md +35 -12
- package/dist/{BaseRealtimeProvider-CWJ81HIt.d.mts → BaseRealtimeProvider-BJQO-hpu.d.mts} +44 -1
- package/dist/{BaseRealtimeProvider-BL75_HHh.d.cts → BaseRealtimeProvider-CO9N8jt-.d.cts} +44 -1
- package/dist/{BaseRealtimeProvider-C9C3s8jx.mjs → BaseRealtimeProvider-Cj6JWR2k.mjs} +1 -1
- package/dist/{BaseRealtimeProvider-C2mRn1V_.cjs → BaseRealtimeProvider-ZfFzijdr.cjs} +1 -1
- package/dist/{GeminiLiveProvider-Cc1dkxW6.d.cts → GeminiLiveProvider-C_LQCTX5.d.mts} +1 -1
- package/dist/{GeminiLiveProvider-TvY_cQQZ.d.mts → GeminiLiveProvider-DM-GwD0w.d.cts} +1 -1
- package/dist/{InMemorySessionStore-B5_rq61L.d.cts → InMemorySessionStore-BlsyPnIp.d.cts} +12 -6
- package/dist/{InMemorySessionStore-B5_rq61L.d.mts → InMemorySessionStore-BlsyPnIp.d.mts} +12 -6
- package/dist/{OpenAICompatibleProvider-D-2OOVBU.mjs → OpenAICompatibleProvider-Dqje-boq.mjs} +3 -3
- package/dist/{OpenAICompatibleProvider-Mp0Mefbh.cjs → OpenAICompatibleProvider-j2Nza2q2.cjs} +8 -2
- package/dist/{events-BylBSBW-.mjs → events-D-pvCH_F.mjs} +2 -1
- package/dist/{events-BxDTIKKq.cjs → events-DWX9535M.cjs} +2 -1
- package/dist/gemini.cjs +1 -1
- package/dist/gemini.d.cts +2 -2
- package/dist/gemini.d.mts +2 -2
- package/dist/gemini.mjs +1 -1
- package/dist/gpt-live.cjs +954 -0
- package/dist/gpt-live.d.cts +261 -0
- package/dist/gpt-live.d.mts +261 -0
- package/dist/gpt-live.mjs +936 -0
- package/dist/index.cjs +194 -25
- package/dist/index.d.cts +32 -3
- package/dist/index.d.mts +32 -3
- package/dist/index.mjs +194 -25
- package/dist/openai.cjs +2 -2
- package/dist/openai.d.cts +1 -1
- package/dist/openai.d.mts +1 -1
- package/dist/openai.mjs +2 -2
- package/dist/{rest-BYqiVOhe.mjs → rest-D-DWWVIj.mjs} +1 -1
- package/dist/{rest-BvUKut_k.cjs → rest-OR4VhEif.cjs} +1 -1
- package/dist/{session-config-CbifLlkV.mjs → session-config-C31WZESg.mjs} +1 -1
- package/dist/{session-config-CqJm2Kxz.cjs → session-config-CYjxBqpF.cjs} +1 -1
- package/dist/store.d.cts +2 -2
- package/dist/store.d.mts +2 -2
- package/dist/testing.cjs +376 -0
- package/dist/testing.d.cts +119 -2
- package/dist/testing.d.mts +119 -2
- package/dist/testing.mjs +374 -2
- package/dist/twilio.cjs +1 -1
- package/dist/twilio.mjs +1 -1
- package/dist/xai.cjs +3 -3
- package/dist/xai.d.cts +1 -1
- package/dist/xai.d.mts +1 -1
- package/dist/xai.mjs +3 -3
- package/package.json +14 -2
package/README.md
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/realtime-voice-agents)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
**Provider-agnostic bridge between Twilio Media Streams and realtime speech-to-speech AI.** Build phone voice agents in Node.js with one `Agent` / `tool()` / session API across **OpenAI Realtime**, **xAI Grok Voice**, and **Gemini Live** — with multi-agent handoffs, tool execution strategies, hardware-confirmed playback tracking, true barge-in, and hold audio.
|
|
8
|
+
**Provider-agnostic bridge between Twilio Media Streams and realtime speech-to-speech AI.** Build phone voice agents in Node.js with one `Agent` / `tool()` / session API across **OpenAI Realtime**, **OpenAI GPT-Live** (full-duplex), **xAI Grok Voice**, and **Gemini Live** — with multi-agent handoffs, tool execution strategies, hardware-confirmed playback tracking, true barge-in, and hold audio.
|
|
9
9
|
|
|
10
10
|
```
|
|
11
|
-
Caller ── PSTN ── Twilio ── Media Stream WS ──▶ TwilioRealtimeBridge ──▶ OpenAI / xAI / Gemini
|
|
11
|
+
Caller ── PSTN ── Twilio ── Media Stream WS ──▶ TwilioRealtimeBridge ──▶ OpenAI Realtime / GPT-Live / xAI / Gemini
|
|
12
12
|
μ-law 8kHz CallSession realtime S2S
|
|
13
13
|
```
|
|
14
14
|
|
|
@@ -81,6 +81,7 @@ Point your Twilio number's Voice webhook at `POST /twilio/voice`. That's a worki
|
|
|
81
81
|
|
|
82
82
|
```ts
|
|
83
83
|
import { openaiRealtime } from 'realtime-voice-agents/openai';
|
|
84
|
+
import { gptLive } from 'realtime-voice-agents/gpt-live';
|
|
84
85
|
import { xaiRealtime } from 'realtime-voice-agents/xai';
|
|
85
86
|
import { geminiLive } from 'realtime-voice-agents/gemini';
|
|
86
87
|
|
|
@@ -89,20 +90,37 @@ openaiRealtime({
|
|
|
89
90
|
voice: 'marin',
|
|
90
91
|
vad: { type: 'server', silenceDurationMs: 700 },
|
|
91
92
|
});
|
|
93
|
+
gptLive({
|
|
94
|
+
voice: 'marin',
|
|
95
|
+
delegation: { model: 'gpt-5.6-terra', instructions: 'Backend procedures and tool rules.' },
|
|
96
|
+
});
|
|
92
97
|
xaiRealtime({ model: 'grok-voice-latest', voice: 'eve' });
|
|
93
98
|
geminiLive({ model: 'gemini-2.5-flash-native-audio-preview-12-2025', voice: 'Aoede' });
|
|
94
99
|
// or bring your own: implement BaseRealtimeProvider and pass a factory.
|
|
95
100
|
```
|
|
96
101
|
|
|
97
|
-
| | OpenAI
|
|
98
|
-
| ---------------------- | --------------------------------- | --------------------------------- | -------------------------------------- |
|
|
99
|
-
| Audio path | μ-law passthrough | μ-law passthrough | transcoded (stateful resampler) |
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
102
|
+
| | OpenAI Realtime | GPT-Live | xAI | Gemini Live |
|
|
103
|
+
| ---------------------- | --------------------------------- | ------------------------------------------- | --------------------------------- | -------------------------------------- |
|
|
104
|
+
| Audio path | μ-law passthrough | μ-law passthrough (continuous stream) | μ-law passthrough | transcoded (stateful resampler) |
|
|
105
|
+
| Turn-taking / barge-in | bridge-owned (guards, truncate) | model-owned (full-duplex; guards observe) | server VAD, buffer flush only | server self-truncates |
|
|
106
|
+
| Tools run on | the voice model | a backend Responses model (voice keeps talking) | the voice model | the voice model |
|
|
107
|
+
| Mid-session agent swap | ✅ `session.update` | reconnect + history seeded via `session.input` | ✅ `session.update` | reconnect + context carry |
|
|
108
|
+
| Session resumption | — | — | — | ✅ handles, replayed on reconnect |
|
|
109
|
+
| Reconnect | backoff + transcript re-injection | backoff + seeded history | backoff + transcript re-injection | backoff + resumption (or re-injection) |
|
|
110
|
+
|
|
111
|
+
One `SessionOptions` surface configures all four; where a provider can't honor a knob, the fallback is documented and pinned by the parity test suite.
|
|
112
|
+
|
|
113
|
+
### GPT-Live: full-duplex, two prompts
|
|
104
114
|
|
|
105
|
-
|
|
115
|
+
[GPT-Live](https://developers.openai.com/api/docs/guides/live) is a different API from Realtime (`/v1/live/sessions`), not a new Realtime model. The voice model listens while it speaks and decides on its own when to answer and when to stop; a **backend** Responses model does the reasoning and calls your tools while the conversation keeps going. The bridge translates that into the same `Agent` / `tool()` surface, with these differences:
|
|
116
|
+
|
|
117
|
+
- **Two prompts.** `Agent.instructions` is the *voice* prompt (style, backchannel and interruption policy, when to delegate). `gptLive({ delegation: { instructions } })` is the *backend* prompt (procedures, tool rules). Per-agent backend overrides go through `providerOptions: { delegation: { responses: { ... } } }`.
|
|
118
|
+
- **Barge-in is the model's.** `interruptions`, `vad`, `noiseAdaptiveVad`, `session.interrupt()` and `updateVad()` become documented no-ops: nothing is cancelled, cleared or truncated, and `user.speech.*` events are not emitted (the wire has no VAD events). Protect a greeting through the voice prompt ("finish the opening sentence before yielding").
|
|
119
|
+
- **Tools never pause the voice.** Results are delivered the moment they are ready regardless of `toolResultDelivery`; an interruption does not cancel a running tool, and its result still reaches the backend. Results are relayed in the model's own words — use exact wording only through the voice prompt.
|
|
120
|
+
- **Greetings, nudges and goodbyes** (`greeting.instructions`, `idle.prompts`, `finish_call`) are delivered as `session.commentary.append` — the append that reliably produces speech on demand. Keypad entries and deferred results are `session.thinking.append`; runtime instructions are `session.instructions.append`. Each append is capped at 500 tokens (long texts are split).
|
|
121
|
+
- **Immutable session.** Instructions, voice and audio format cannot change after start, so handoffs and reconnects open a fresh session and seed the attributed transcript through `session.input` (≤ 128 messages) — the anti-loop replay is preserved. Sessions expire after 120 minutes; an expiry reconnects the same way.
|
|
122
|
+
- **Deafness feeds silence.** The model's session clock runs on input audio, so `deafness` options replace caller audio with silence instead of dropping frames.
|
|
123
|
+
- **Billing is per second** of session (plus backend tokens). `session.usage.audioSeconds` carries the running total; backend token usage is summed from `response.completed`. The provider sends `session.close` on teardown and waits for `session.closed`, so a hung-up call never keeps billing.
|
|
106
124
|
|
|
107
125
|
## Provider fallbacks
|
|
108
126
|
|
|
@@ -184,6 +202,10 @@ const receptionist = new Agent({ name: 'Receptionist', instructions: '…', hand
|
|
|
184
202
|
|
|
185
203
|
Each agent in `handoffs` becomes a `transfer_to_<id>` tool. On handoff the session settles the function call, swaps instructions + tools (`session.update` on OpenAI/xAI; close-and-reopen with context carry on Gemini), and triggers a natural continuation — the caller never hears a seam. Also available programmatically: `session.handoffTo('billing')`. Cycles are fine (billing can hand back).
|
|
186
204
|
|
|
205
|
+
**An agent that just took over cannot transfer again until the caller speaks.** The transfer tool is refused (`agent.handoff.blocked` fires, the model is told why, the active agent does not change); a caller turn — speech or a keypad entry — unlocks it. This makes transfer loops structurally impossible rather than merely discouraged: given the same replayed transcript, each incoming agent otherwise re-derives intent, decides the request is somebody else's, and passes it on. The trade-off is that a pure router node costs an extra caller turn, so direct arcs between agents beat hub-and-spoke. `session.handoffTo()` is host intent and bypasses the lock (it still arms it for the agent it installs).
|
|
206
|
+
|
|
207
|
+
The context an incoming agent receives is attributed, not flat: each replayed line names the agent that said it, and completed transfers appear as `[transfer] A -> B (reason: …)` lines — so it can see what was already answered and already routed.
|
|
208
|
+
|
|
187
209
|
## Built-in call controls
|
|
188
210
|
|
|
189
211
|
```ts
|
|
@@ -301,7 +323,7 @@ session.on('dtmf', ({ digit }) => {
|
|
|
301
323
|
|
|
302
324
|
## Events (session)
|
|
303
325
|
|
|
304
|
-
`call.started/ended/failed` · `provider.connected/fallback/reconnecting/reconnected/closed` · `agent.speech.started/ended` (generation) · **`playback.started/finished/interrupted`** (what the caller heard, mark-confirmed) · `user.speech.started/ended` · `transcript.user/agent` · `tool.started/completed/failed` · `tool.approval.required` · `agent.handoff` · `interruption` / `interruption.blocked` · `vad.suggestion` / `vad.adjusted` (noise-adaptive VAD) · `background_audio.started/stopped` · `dtmf` (raw keypress) · `keypad.entry` / `keypad.cleared` (keypad input) · `usage.updated` · `error`.
|
|
326
|
+
`call.started/ended/failed` · `provider.connected/fallback/reconnecting/reconnected/closed` · `agent.speech.started/ended` (generation) · **`playback.started/finished/interrupted`** (what the caller heard, mark-confirmed) · `user.speech.started/ended` · `transcript.user/agent` · `tool.started/completed/failed` · `tool.approval.required` · `agent.handoff` / `agent.handoff.blocked` · `interruption` / `interruption.blocked` · `vad.suggestion` / `vad.adjusted` (noise-adaptive VAD) · `background_audio.started/stopped` · `dtmf` (raw keypress) · `keypad.entry` / `keypad.cleared` (keypad input) · `usage.updated` · `error`.
|
|
305
327
|
|
|
306
328
|
```ts
|
|
307
329
|
bridge.on('session.started', (session) => {
|
|
@@ -347,6 +369,7 @@ Outbound calls: the greeting waits for a human — feed your status callback int
|
|
|
347
369
|
|
|
348
370
|
- **`FakeTwilioMediaStream`** — a scripted caller with an exact playout simulation: marks echo only after the media before them "plays"; `clear` discards buffered audio and echoes pending marks, like real Twilio.
|
|
349
371
|
- **`FakeOpenAIServer`** — a real-WebSocket GA-protocol server you script (`sendAudioResponse`, `sendToolCall`, `sendSpeechStarted`, drops, `refuseConnections` for down-provider/fallback scenarios).
|
|
372
|
+
- **`FakeGptLiveServer`** — a real-WebSocket Live-protocol server: `sendSpeech` (speech chunks + the silence that closes the gate), timed transcripts, backend function calls in `response.event` envelopes, usage ticks, server-side closes.
|
|
350
373
|
- **`FakeGeminiLive`** — a scripted `@google/genai` seam for the Gemini provider.
|
|
351
374
|
|
|
352
375
|
```ts
|
|
@@ -364,7 +387,7 @@ caller.advancePlayback(200); // deterministic playout — assert on playback eve
|
|
|
364
387
|
|
|
365
388
|
## Subpath exports
|
|
366
389
|
|
|
367
|
-
`realtime-voice-agents` (core) · `/openai` · `/xai` · `/gemini` · `/twilio` (wire types, TwiML, REST) · `/audio` (μ-law, resampler, transcoders, background player) · `/store` (SessionStore + in-memory) · `/testing`.
|
|
390
|
+
`realtime-voice-agents` (core) · `/openai` · `/gpt-live` · `/xai` · `/gemini` · `/twilio` (wire types, TwiML, REST) · `/audio` (μ-law, resampler, transcoders, background player) · `/store` (SessionStore + in-memory) · `/testing`.
|
|
368
391
|
|
|
369
392
|
## Observability & state
|
|
370
393
|
|
|
@@ -63,6 +63,32 @@ interface ProviderCapabilities {
|
|
|
63
63
|
* means the provider declared none (see VadTuningProfile).
|
|
64
64
|
*/
|
|
65
65
|
vadTuning?: VadTuningProfile;
|
|
66
|
+
/**
|
|
67
|
+
* Who decides when the agent speaks and stops. `'bridge'` (absent): the
|
|
68
|
+
* provider's server VAD detects turns and the bridge arbitrates barge-ins
|
|
69
|
+
* (cancel / clear / truncate through the interruption guard). `'model'`: a
|
|
70
|
+
* full-duplex model listens while it talks and handles interruptions itself
|
|
71
|
+
* (GPT-Live). The bridge then never cancels, clears or truncates, the
|
|
72
|
+
* interruption guard is observe-only, `user.speech.*` events are not
|
|
73
|
+
* available, and deafness options substitute silence for caller audio
|
|
74
|
+
* instead of dropping frames (the model's session clock runs on input).
|
|
75
|
+
* Documented fallback, pinned in the parity tests.
|
|
76
|
+
*/
|
|
77
|
+
turnTaking?: 'bridge' | 'model';
|
|
78
|
+
/**
|
|
79
|
+
* `connect()` seeds `init.history` into the new server session, so the
|
|
80
|
+
* engine skips post-connect transcript re-injection on reconnects and
|
|
81
|
+
* handoff-reconnects (GPT-Live `session.input`).
|
|
82
|
+
*/
|
|
83
|
+
startupHistory?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Tool results feed a backend that runs independently of speech (the voice
|
|
86
|
+
* model keeps talking while it works), so holding them until playback
|
|
87
|
+
* finishes only adds latency: the engine delivers results and deferred
|
|
88
|
+
* injections immediately, regardless of `toolResultDelivery`. Usage is
|
|
89
|
+
* accounted from the provider's `usage` events (no response carries it).
|
|
90
|
+
*/
|
|
91
|
+
decoupledBackend?: boolean;
|
|
66
92
|
}
|
|
67
93
|
//#endregion
|
|
68
94
|
//#region src/providers/base/events.d.ts
|
|
@@ -83,6 +109,11 @@ interface ProviderUsage {
|
|
|
83
109
|
textTokens?: number;
|
|
84
110
|
audioTokens?: number;
|
|
85
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* Cumulative session audio seconds for duration-billed providers (GPT-Live).
|
|
114
|
+
* A running total, not an increment: accumulators keep the latest value.
|
|
115
|
+
*/
|
|
116
|
+
audioSeconds?: number;
|
|
86
117
|
/** Provider-native payload for advanced analytics. */
|
|
87
118
|
raw?: RawUsage;
|
|
88
119
|
}
|
|
@@ -171,6 +202,12 @@ interface VadConfig {
|
|
|
171
202
|
/** Server-side auto-response on turn commit (OpenAI `create_response`). */
|
|
172
203
|
createResponse?: boolean;
|
|
173
204
|
}
|
|
205
|
+
/** One prior conversation turn, for providers that seed history at session start. */
|
|
206
|
+
interface ProviderHistoryEntry {
|
|
207
|
+
/** `developer` carries engine notes (transfer records, continuation context). */
|
|
208
|
+
role: 'user' | 'assistant' | 'developer';
|
|
209
|
+
text: string;
|
|
210
|
+
}
|
|
174
211
|
interface ProviderToolSchema {
|
|
175
212
|
name: string;
|
|
176
213
|
description?: string;
|
|
@@ -209,6 +246,12 @@ interface ProviderSessionInit {
|
|
|
209
246
|
* legacy fire-and-forget update behavior exactly as before.
|
|
210
247
|
*/
|
|
211
248
|
serializedSessionUpdates?: boolean;
|
|
249
|
+
/**
|
|
250
|
+
* Conversation so far, oldest first, for providers that seed history into
|
|
251
|
+
* the new session at connect time (capability `startupHistory`); ignored by
|
|
252
|
+
* providers that re-inject history as text after connecting.
|
|
253
|
+
*/
|
|
254
|
+
history?: ProviderHistoryEntry[];
|
|
212
255
|
/** Provider-native session options, deep-merged last (escape hatch). */
|
|
213
256
|
providerOptions?: Record<string, unknown>;
|
|
214
257
|
}
|
|
@@ -286,4 +329,4 @@ interface ProviderFactoryContext {
|
|
|
286
329
|
/** A fresh provider per call; connection config is captured in the factory closure. */
|
|
287
330
|
type ProviderFactory = (context: ProviderFactoryContext) => BaseRealtimeProvider;
|
|
288
331
|
//#endregion
|
|
289
|
-
export {
|
|
332
|
+
export { VadTuningProfile as _, ProviderSessionInit as a, noopLogger as b, SendToolResultOptions as c, ProviderAudioDelta as d, ProviderCloseInfo as f, ProviderCapabilities as g, ProviderUsage as h, ProviderHistoryEntry as i, SessionUpdateOptions as l, ProviderToolCall as m, ProviderFactory as n, ProviderToolSchema as o, ProviderEvents as p, ProviderFactoryContext as r, SendTextOptions as s, BaseRealtimeProvider as t, VadConfig as u, Logger as v, consoleLogger as y };
|
|
@@ -63,6 +63,32 @@ interface ProviderCapabilities {
|
|
|
63
63
|
* means the provider declared none (see VadTuningProfile).
|
|
64
64
|
*/
|
|
65
65
|
vadTuning?: VadTuningProfile;
|
|
66
|
+
/**
|
|
67
|
+
* Who decides when the agent speaks and stops. `'bridge'` (absent): the
|
|
68
|
+
* provider's server VAD detects turns and the bridge arbitrates barge-ins
|
|
69
|
+
* (cancel / clear / truncate through the interruption guard). `'model'`: a
|
|
70
|
+
* full-duplex model listens while it talks and handles interruptions itself
|
|
71
|
+
* (GPT-Live). The bridge then never cancels, clears or truncates, the
|
|
72
|
+
* interruption guard is observe-only, `user.speech.*` events are not
|
|
73
|
+
* available, and deafness options substitute silence for caller audio
|
|
74
|
+
* instead of dropping frames (the model's session clock runs on input).
|
|
75
|
+
* Documented fallback, pinned in the parity tests.
|
|
76
|
+
*/
|
|
77
|
+
turnTaking?: 'bridge' | 'model';
|
|
78
|
+
/**
|
|
79
|
+
* `connect()` seeds `init.history` into the new server session, so the
|
|
80
|
+
* engine skips post-connect transcript re-injection on reconnects and
|
|
81
|
+
* handoff-reconnects (GPT-Live `session.input`).
|
|
82
|
+
*/
|
|
83
|
+
startupHistory?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Tool results feed a backend that runs independently of speech (the voice
|
|
86
|
+
* model keeps talking while it works), so holding them until playback
|
|
87
|
+
* finishes only adds latency: the engine delivers results and deferred
|
|
88
|
+
* injections immediately, regardless of `toolResultDelivery`. Usage is
|
|
89
|
+
* accounted from the provider's `usage` events (no response carries it).
|
|
90
|
+
*/
|
|
91
|
+
decoupledBackend?: boolean;
|
|
66
92
|
}
|
|
67
93
|
//#endregion
|
|
68
94
|
//#region src/providers/base/events.d.ts
|
|
@@ -83,6 +109,11 @@ interface ProviderUsage {
|
|
|
83
109
|
textTokens?: number;
|
|
84
110
|
audioTokens?: number;
|
|
85
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* Cumulative session audio seconds for duration-billed providers (GPT-Live).
|
|
114
|
+
* A running total, not an increment: accumulators keep the latest value.
|
|
115
|
+
*/
|
|
116
|
+
audioSeconds?: number;
|
|
86
117
|
/** Provider-native payload for advanced analytics. */
|
|
87
118
|
raw?: RawUsage;
|
|
88
119
|
}
|
|
@@ -171,6 +202,12 @@ interface VadConfig {
|
|
|
171
202
|
/** Server-side auto-response on turn commit (OpenAI `create_response`). */
|
|
172
203
|
createResponse?: boolean;
|
|
173
204
|
}
|
|
205
|
+
/** One prior conversation turn, for providers that seed history at session start. */
|
|
206
|
+
interface ProviderHistoryEntry {
|
|
207
|
+
/** `developer` carries engine notes (transfer records, continuation context). */
|
|
208
|
+
role: 'user' | 'assistant' | 'developer';
|
|
209
|
+
text: string;
|
|
210
|
+
}
|
|
174
211
|
interface ProviderToolSchema {
|
|
175
212
|
name: string;
|
|
176
213
|
description?: string;
|
|
@@ -209,6 +246,12 @@ interface ProviderSessionInit {
|
|
|
209
246
|
* legacy fire-and-forget update behavior exactly as before.
|
|
210
247
|
*/
|
|
211
248
|
serializedSessionUpdates?: boolean;
|
|
249
|
+
/**
|
|
250
|
+
* Conversation so far, oldest first, for providers that seed history into
|
|
251
|
+
* the new session at connect time (capability `startupHistory`); ignored by
|
|
252
|
+
* providers that re-inject history as text after connecting.
|
|
253
|
+
*/
|
|
254
|
+
history?: ProviderHistoryEntry[];
|
|
212
255
|
/** Provider-native session options, deep-merged last (escape hatch). */
|
|
213
256
|
providerOptions?: Record<string, unknown>;
|
|
214
257
|
}
|
|
@@ -286,4 +329,4 @@ interface ProviderFactoryContext {
|
|
|
286
329
|
/** A fresh provider per call; connection config is captured in the factory closure. */
|
|
287
330
|
type ProviderFactory = (context: ProviderFactoryContext) => BaseRealtimeProvider;
|
|
288
331
|
//#endregion
|
|
289
|
-
export {
|
|
332
|
+
export { VadTuningProfile as _, ProviderSessionInit as a, noopLogger as b, SendToolResultOptions as c, ProviderAudioDelta as d, ProviderCloseInfo as f, ProviderCapabilities as g, ProviderUsage as h, ProviderHistoryEntry as i, SessionUpdateOptions as l, ProviderToolCall as m, ProviderFactory as n, ProviderToolSchema as o, ProviderEvents as p, ProviderFactoryContext as r, SendTextOptions as s, BaseRealtimeProvider as t, VadConfig as u, Logger as v, consoleLogger as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as ProviderSessionInit, c as SendToolResultOptions, g as ProviderCapabilities, s as SendTextOptions, t as BaseRealtimeProvider, u as VadConfig, v as Logger } from "./BaseRealtimeProvider-BJQO-hpu.mjs";
|
|
2
2
|
//#region src/providers/gemini/GeminiLiveProvider.d.ts
|
|
3
3
|
/** Structural slice of @google/genai's live session (also what fakes implement). */
|
|
4
4
|
interface GeminiLiveSessionLike {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as ProviderSessionInit, c as SendToolResultOptions, g as ProviderCapabilities, s as SendTextOptions, t as BaseRealtimeProvider, u as VadConfig, v as Logger } from "./BaseRealtimeProvider-CO9N8jt-.cjs";
|
|
2
2
|
//#region src/providers/gemini/GeminiLiveProvider.d.ts
|
|
3
3
|
/** Structural slice of @google/genai's live session (also what fakes implement). */
|
|
4
4
|
interface GeminiLiveSessionLike {
|
|
@@ -9,6 +9,14 @@ interface TranscriptEntry {
|
|
|
9
9
|
/** The caller cut this utterance off mid-playback. */
|
|
10
10
|
interrupted?: boolean;
|
|
11
11
|
}
|
|
12
|
+
/** One completed transfer, as recorded in the session's handoff history. */
|
|
13
|
+
interface HandoffRecord {
|
|
14
|
+
from: string;
|
|
15
|
+
to: string;
|
|
16
|
+
/** Milliseconds since call start. */
|
|
17
|
+
atMs: number;
|
|
18
|
+
reason?: string;
|
|
19
|
+
}
|
|
12
20
|
//#endregion
|
|
13
21
|
//#region src/session/usage.d.ts
|
|
14
22
|
/** Accumulated token consumption for a call, normalized across providers. */
|
|
@@ -27,6 +35,8 @@ interface UsageInfo {
|
|
|
27
35
|
};
|
|
28
36
|
/** Number of model responses accounted. */
|
|
29
37
|
responses: number;
|
|
38
|
+
/** Cumulative session audio seconds, for duration-billed providers (GPT-Live). */
|
|
39
|
+
audioSeconds?: number;
|
|
30
40
|
}
|
|
31
41
|
declare function emptyUsage(): UsageInfo;
|
|
32
42
|
//#endregion
|
|
@@ -40,11 +50,7 @@ interface CallSnapshot {
|
|
|
40
50
|
transcript: TranscriptEntry[];
|
|
41
51
|
usage: UsageInfo;
|
|
42
52
|
context: Record<string, unknown>;
|
|
43
|
-
handoffHistory:
|
|
44
|
-
from: string;
|
|
45
|
-
to: string;
|
|
46
|
-
atMs: number;
|
|
47
|
-
}>;
|
|
53
|
+
handoffHistory: HandoffRecord[];
|
|
48
54
|
/** Gemini session-resumption handle, when the provider supplies one. */
|
|
49
55
|
resumptionHandle?: string;
|
|
50
56
|
startedAtMs: number;
|
|
@@ -80,4 +86,4 @@ declare class InMemorySessionStore implements SessionStore {
|
|
|
80
86
|
list(): CallSnapshot[];
|
|
81
87
|
}
|
|
82
88
|
//#endregion
|
|
83
|
-
export { emptyUsage as a, UsageInfo as i, SessionStore as n,
|
|
89
|
+
export { emptyUsage as a, UsageInfo as i, SessionStore as n, HandoffRecord as o, CallSnapshot as r, TranscriptEntry as s, InMemorySessionStore as t };
|
|
@@ -9,6 +9,14 @@ interface TranscriptEntry {
|
|
|
9
9
|
/** The caller cut this utterance off mid-playback. */
|
|
10
10
|
interrupted?: boolean;
|
|
11
11
|
}
|
|
12
|
+
/** One completed transfer, as recorded in the session's handoff history. */
|
|
13
|
+
interface HandoffRecord {
|
|
14
|
+
from: string;
|
|
15
|
+
to: string;
|
|
16
|
+
/** Milliseconds since call start. */
|
|
17
|
+
atMs: number;
|
|
18
|
+
reason?: string;
|
|
19
|
+
}
|
|
12
20
|
//#endregion
|
|
13
21
|
//#region src/session/usage.d.ts
|
|
14
22
|
/** Accumulated token consumption for a call, normalized across providers. */
|
|
@@ -27,6 +35,8 @@ interface UsageInfo {
|
|
|
27
35
|
};
|
|
28
36
|
/** Number of model responses accounted. */
|
|
29
37
|
responses: number;
|
|
38
|
+
/** Cumulative session audio seconds, for duration-billed providers (GPT-Live). */
|
|
39
|
+
audioSeconds?: number;
|
|
30
40
|
}
|
|
31
41
|
declare function emptyUsage(): UsageInfo;
|
|
32
42
|
//#endregion
|
|
@@ -40,11 +50,7 @@ interface CallSnapshot {
|
|
|
40
50
|
transcript: TranscriptEntry[];
|
|
41
51
|
usage: UsageInfo;
|
|
42
52
|
context: Record<string, unknown>;
|
|
43
|
-
handoffHistory:
|
|
44
|
-
from: string;
|
|
45
|
-
to: string;
|
|
46
|
-
atMs: number;
|
|
47
|
-
}>;
|
|
53
|
+
handoffHistory: HandoffRecord[];
|
|
48
54
|
/** Gemini session-resumption handle, when the provider supplies one. */
|
|
49
55
|
resumptionHandle?: string;
|
|
50
56
|
startedAtMs: number;
|
|
@@ -80,4 +86,4 @@ declare class InMemorySessionStore implements SessionStore {
|
|
|
80
86
|
list(): CallSnapshot[];
|
|
81
87
|
}
|
|
82
88
|
//#endregion
|
|
83
|
-
export { emptyUsage as a, UsageInfo as i, SessionStore as n,
|
|
89
|
+
export { emptyUsage as a, UsageInfo as i, SessionStore as n, HandoffRecord as o, CallSnapshot as r, TranscriptEntry as s, InMemorySessionStore as t };
|
package/dist/{OpenAICompatibleProvider-D-2OOVBU.mjs → OpenAICompatibleProvider-Dqje-boq.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as noopLogger, t as BaseRealtimeProvider } from "./BaseRealtimeProvider-
|
|
2
|
-
import { t as buildSessionUpdate } from "./session-config-
|
|
1
|
+
import { a as noopLogger, t as BaseRealtimeProvider } from "./BaseRealtimeProvider-Cj6JWR2k.mjs";
|
|
2
|
+
import { t as buildSessionUpdate } from "./session-config-C31WZESg.mjs";
|
|
3
3
|
import WebSocket$1 from "ws";
|
|
4
4
|
//#region src/providers/openai-compatible/OpenAICompatibleProvider.ts
|
|
5
5
|
/**
|
|
@@ -486,4 +486,4 @@ function normalizeUsage(raw) {
|
|
|
486
486
|
};
|
|
487
487
|
}
|
|
488
488
|
//#endregion
|
|
489
|
-
export { OpenAICompatibleProvider as t };
|
|
489
|
+
export { normalizeUsage as n, OpenAICompatibleProvider as t };
|
package/dist/{OpenAICompatibleProvider-Mp0Mefbh.cjs → OpenAICompatibleProvider-j2Nza2q2.cjs}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const require_BaseRealtimeProvider = require("./BaseRealtimeProvider-
|
|
3
|
-
const require_session_config = require("./session-config-
|
|
2
|
+
const require_BaseRealtimeProvider = require("./BaseRealtimeProvider-ZfFzijdr.cjs");
|
|
3
|
+
const require_session_config = require("./session-config-CYjxBqpF.cjs");
|
|
4
4
|
let ws = require("ws");
|
|
5
5
|
ws = require_rolldown_runtime.__toESM(ws, 1);
|
|
6
6
|
//#region src/providers/openai-compatible/OpenAICompatibleProvider.ts
|
|
@@ -494,3 +494,9 @@ Object.defineProperty(exports, "OpenAICompatibleProvider", {
|
|
|
494
494
|
return OpenAICompatibleProvider;
|
|
495
495
|
}
|
|
496
496
|
});
|
|
497
|
+
Object.defineProperty(exports, "normalizeUsage", {
|
|
498
|
+
enumerable: true,
|
|
499
|
+
get: function() {
|
|
500
|
+
return normalizeUsage;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
@@ -28,7 +28,8 @@ var TypedEmitter = class {
|
|
|
28
28
|
return this;
|
|
29
29
|
}
|
|
30
30
|
removeAllListeners(event) {
|
|
31
|
-
this.emitter.removeAllListeners(
|
|
31
|
+
if (event === void 0) this.emitter.removeAllListeners();
|
|
32
|
+
else this.emitter.removeAllListeners(event);
|
|
32
33
|
return this;
|
|
33
34
|
}
|
|
34
35
|
emit(event, ...args) {
|
|
@@ -28,7 +28,8 @@ var TypedEmitter = class {
|
|
|
28
28
|
return this;
|
|
29
29
|
}
|
|
30
30
|
removeAllListeners(event) {
|
|
31
|
-
this.emitter.removeAllListeners(
|
|
31
|
+
if (event === void 0) this.emitter.removeAllListeners();
|
|
32
|
+
else this.emitter.removeAllListeners(event);
|
|
32
33
|
return this;
|
|
33
34
|
}
|
|
34
35
|
emit(event, ...args) {
|
package/dist/gemini.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_BaseRealtimeProvider = require("./BaseRealtimeProvider-
|
|
2
|
+
const require_BaseRealtimeProvider = require("./BaseRealtimeProvider-ZfFzijdr.cjs");
|
|
3
3
|
const require_env = require("./env-DSnGaERV.cjs");
|
|
4
4
|
const require_transcode = require("./transcode-C9aJG7_W.cjs");
|
|
5
5
|
//#region src/providers/gemini/GeminiLiveProvider.ts
|
package/dist/gemini.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as GeminiLiveSessionLike, i as GeminiLiveProviderConfig, n as GeminiLiveConnector, r as GeminiLiveProvider, t as GeminiConnectParams } from "./GeminiLiveProvider-
|
|
1
|
+
import { n as ProviderFactory, u as VadConfig } from "./BaseRealtimeProvider-CO9N8jt-.cjs";
|
|
2
|
+
import { a as GeminiLiveSessionLike, i as GeminiLiveProviderConfig, n as GeminiLiveConnector, r as GeminiLiveProvider, t as GeminiConnectParams } from "./GeminiLiveProvider-DM-GwD0w.cjs";
|
|
3
3
|
//#region src/gemini.d.ts
|
|
4
4
|
/** Env vars checked (in order) when no explicit apiKey is passed. */
|
|
5
5
|
declare const GEMINI_KEY_ENV_VARS: readonly ["GOOGLE_API_KEY", "GEMINI_API_KEY", "GOOGLE_GENAI_API_KEY"];
|
package/dist/gemini.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as GeminiLiveSessionLike, i as GeminiLiveProviderConfig, n as GeminiLiveConnector, r as GeminiLiveProvider, t as GeminiConnectParams } from "./GeminiLiveProvider-
|
|
1
|
+
import { n as ProviderFactory, u as VadConfig } from "./BaseRealtimeProvider-BJQO-hpu.mjs";
|
|
2
|
+
import { a as GeminiLiveSessionLike, i as GeminiLiveProviderConfig, n as GeminiLiveConnector, r as GeminiLiveProvider, t as GeminiConnectParams } from "./GeminiLiveProvider-C_LQCTX5.mjs";
|
|
3
3
|
//#region src/gemini.d.ts
|
|
4
4
|
/** Env vars checked (in order) when no explicit apiKey is passed. */
|
|
5
5
|
declare const GEMINI_KEY_ENV_VARS: readonly ["GOOGLE_API_KEY", "GEMINI_API_KEY", "GOOGLE_GENAI_API_KEY"];
|
package/dist/gemini.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as noopLogger, n as deepMerge, t as BaseRealtimeProvider } from "./BaseRealtimeProvider-
|
|
1
|
+
import { a as noopLogger, n as deepMerge, t as BaseRealtimeProvider } from "./BaseRealtimeProvider-Cj6JWR2k.mjs";
|
|
2
2
|
import { t as resolveApiKey } from "./env-DUwUWTsg.mjs";
|
|
3
3
|
import { n as OutboundTranscoder, t as InboundTranscoder } from "./transcode-CsAp97G9.mjs";
|
|
4
4
|
//#region src/providers/gemini/GeminiLiveProvider.ts
|