dvgateway-adapters 1.9.7 → 1.9.11

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,250 @@
1
+ /**
2
+ * OpenAI GPT-Live Speech-to-Speech Adapter (@since SDK 1.9.10)
3
+ *
4
+ * GPT-Live (`gpt-live-1`) is a **full-duplex** voice model: it listens while it
5
+ * speaks and decides on its own when to start and stop talking. Reasoning and
6
+ * tool use are **delegated** to a backend — either an OpenAI Responses model
7
+ * (`delegation: { type: 'responses' }`) or your own code (`{ type: 'client' }`).
8
+ *
9
+ * Wiring is the same as the other S2S adapters (`OpenAIRealtimeAdapter`,
10
+ * `GeminiLiveAdapter`): feed `gw.streamAudio(..., { pipelineType: 's2s' })` into
11
+ * `startSession()` and inject `onAudioOutput` chunks with `gw.injectTts()`.
12
+ *
13
+ * What this adapter does for you (each item was measured on the real API,
14
+ * 2026-10-11 — see docs/gpt-live-integration-plan.md §9):
15
+ *
16
+ * - **16 kHz PCM end to end.** GPT-Live accepts `audio/pcm` at 16 kHz, the same
17
+ * format as DVGateway, so there is no resampling.
18
+ * - **Speech gate.** GPT-Live streams output audio continuously, silence included
19
+ * (the output length equals the session length). Injecting it raw would keep
20
+ * the gateway's TTS player "speaking" forever and `tts:complete` would never
21
+ * fire. The adapter forwards only speech segments (RMS gate + hang time).
22
+ * - **No silent defaults.** `delegation` is required (OpenAI treats a missing
23
+ * delegation as client mode) and `store` is sent as `false` explicitly
24
+ * (`store: true` keeps a stereo recording at OpenAI for 30 days).
25
+ * - **Delegation policy prompt.** Without one, the model said "yes, that time is
26
+ * available — I'll book it" without checking in 2 of 5 runs; with the policy
27
+ * prompt it delegated 15 of 15 times and never claimed completion.
28
+ * `buildGptLiveInstructions()` produces that prompt shape.
29
+ * - **Unspoken-result detection.** In 1 of 15 runs the model received the backend
30
+ * result and never said it. `onUnspokenResult` fires when no new speech starts
31
+ * within `unspokenResultMs` after a result is sent, so you can re-send it.
32
+ *
33
+ * What it does NOT do (by design — see the plan doc):
34
+ * - No automatic reconnect (a new connection is a new billed session and a
35
+ * pending action could run twice). Errors go to `onError`; you decide.
36
+ * - No exact wording. GPT-Live paraphrases. Play legally required notices
37
+ * (e.g. "AI 상담원입니다") with `gw.say()` **before** `startSession()`.
38
+ *
39
+ * API reference: https://developers.openai.com/api/docs/guides/live
40
+ * WebSocket: wss://api.openai.com/v1/live/sessions
41
+ */
42
+ import type { AudioChunk, TranscriptResult } from 'dvgateway-sdk';
43
+ import type { RealtimeSpeechActivityEvent, RealtimeSpeechAdapter, RealtimeToolCall } from './openai-realtime.js';
44
+ export declare const GPT_LIVE_URL = "wss://api.openai.com/v1/live/sessions";
45
+ export declare const GPT_LIVE_MODEL = "gpt-live-1";
46
+ /** A function the Responses backend may call (Responses function schema). */
47
+ export interface GptLiveTool {
48
+ type: 'function';
49
+ name: string;
50
+ description?: string;
51
+ parameters?: Record<string, unknown>;
52
+ }
53
+ export interface GptLiveResponsesOptions {
54
+ /** Backend Responses model — required (OpenAI and LiveKit disagree on a default, so we set none). */
55
+ model: string;
56
+ /** Backend instructions: task procedure, business rules, tool usage. */
57
+ instructions?: string;
58
+ tools?: GptLiveTool[];
59
+ /** Allow OpenAI's hosted web search tool. */
60
+ webSearch?: boolean;
61
+ toolChoice?: 'auto' | 'required' | 'none' | {
62
+ type: 'function';
63
+ name: string;
64
+ };
65
+ /** Default false — handle one tool call at a time (OpenAI's migration advice). */
66
+ parallelToolCalls?: boolean;
67
+ reasoning?: Record<string, unknown>;
68
+ serviceTier?: 'auto' | 'default' | 'flex' | 'priority';
69
+ maxOutputTokens?: number;
70
+ }
71
+ export type GptLiveDelegationOptions = {
72
+ type: 'client';
73
+ } | {
74
+ type: 'responses';
75
+ responses: GptLiveResponsesOptions;
76
+ };
77
+ export interface GptLiveHistoryMessage {
78
+ role: 'developer' | 'user' | 'assistant';
79
+ text: string;
80
+ }
81
+ export interface GptLiveSpeechGateOptions {
82
+ /** 20 ms frame RMS at or above this counts as speech (default 0.001; measured silence is 0.0, speech ≈ 0.06). */
83
+ rmsThreshold?: number;
84
+ /** Keep forwarding this long after speech drops below the threshold (default 600 ms). */
85
+ hangMs?: number;
86
+ }
87
+ export interface GptLiveAdapterOptions {
88
+ apiKey: string;
89
+ /** Required — see the file header. */
90
+ delegation: GptLiveDelegationOptions;
91
+ /** Conversation instructions (≤16,384 tokens). Default: `buildGptLiveInstructions({})`. */
92
+ instructions?: string;
93
+ /** Output voice (default "marin"). Fixed for the session. */
94
+ voice?: string;
95
+ /** Prior conversation (≤128 messages, ≤8,192 tokens — the service drops the oldest). */
96
+ history?: GptLiveHistoryMessage[];
97
+ /** Keep a recording at OpenAI for forking (default false). */
98
+ store?: boolean;
99
+ speechGate?: GptLiveSpeechGateOptions;
100
+ /** Transcript pause that closes an utterance (default 800 ms, session clock). */
101
+ transcriptPauseMs?: number;
102
+ /** Fire onUnspokenResult when no new speech starts this long after a result (default 5000 ms, 0 = off). */
103
+ unspokenResultMs?: number;
104
+ connectTimeoutMs?: number;
105
+ closeTimeoutMs?: number;
106
+ /**
107
+ * Accept input that is not caller-only without a warning (default false).
108
+ * 🔴 GPT-Live is full duplex — if its input contains its own voice (a mixed
109
+ * stream), it hears itself and interrupts or answers itself. Use Stasis
110
+ * `mode=customer` and `gw.streamAudio(id, { dir: 'in' })`.
111
+ */
112
+ allowMixedInput?: boolean;
113
+ /** Override for tests / proxies. */
114
+ url?: string;
115
+ }
116
+ /** Client delegation request — GPT-Live gives only an id; the request is in the conversation. */
117
+ export interface GptLiveDelegation {
118
+ linkedId: string;
119
+ delegationId: string;
120
+ /** Finished utterances so far (oldest first). */
121
+ transcript: Array<{
122
+ speaker: 'customer' | 'agent';
123
+ text: string;
124
+ }>;
125
+ /** What the caller is saying right now (not yet finished). */
126
+ pending: string;
127
+ }
128
+ /** Return from an onDelegation handler. A plain string means `{ speak }`. */
129
+ export type GptLiveDelegationResult = string | {
130
+ speak?: string;
131
+ note?: string;
132
+ } | void;
133
+ export interface GptLiveUsage {
134
+ linkedId: string;
135
+ /** Billed voice seconds (cumulative — the latest value is the total). */
136
+ seconds: number;
137
+ /** true only when `session.closed` arrived; otherwise the last snapshot. */
138
+ confirmed: boolean;
139
+ /** close_requested | expired | content | remote_hangup | connection_lost */
140
+ closeReason?: string;
141
+ }
142
+ export interface GptLiveUnspokenResult {
143
+ linkedId: string;
144
+ delegationId: string;
145
+ waitedMs: number;
146
+ }
147
+ /** Error with the OpenAI code attached when there is one. */
148
+ export declare class GptLiveError extends Error {
149
+ readonly code?: string | undefined;
150
+ readonly fatal: boolean;
151
+ readonly status?: number | undefined;
152
+ constructor(message: string, code?: string | undefined, fatal?: boolean, status?: number | undefined);
153
+ }
154
+ export interface GptLiveInstructionsOptions {
155
+ /** Role and tone, e.g. "당신은 ○○ 상담 예약을 돕는 한국어 전화 상담원입니다." */
156
+ persona?: string;
157
+ /** What the backend can do, e.g. ["예약: 가능한 시간 확인과 예약 생성·변경·취소"]. */
158
+ capabilities?: string[];
159
+ delegateWhen?: string[];
160
+ dontDelegateWhen?: string[];
161
+ /** Extra rules appended at the end. */
162
+ rules?: string[];
163
+ }
164
+ /**
165
+ * Build conversation instructions in the shape OpenAI recommends for GPT-Live
166
+ * (Backchannel / Interruption / Delegation policy — the headings are kept in
167
+ * English as OpenAI advises) plus DVGateway's phone rules.
168
+ *
169
+ * The delegation policy is what made the model stop claiming unchecked results
170
+ * in our measurement (2/5 → 0/15).
171
+ */
172
+ export declare function buildGptLiveInstructions(o?: GptLiveInstructionsOptions): string;
173
+ /**
174
+ * Forwards only speech from a continuous output stream.
175
+ * Opens at the first frame with RMS ≥ threshold; stays open until `hangMs` of
176
+ * quieter frames have passed (so pauses inside a sentence survive).
177
+ */
178
+ export declare class SpeechGate {
179
+ private readonly threshold;
180
+ private readonly hangMs;
181
+ private open;
182
+ private quietMs;
183
+ constructor(threshold?: number, hangMs?: number);
184
+ get isOpen(): boolean;
185
+ /**
186
+ * Feed one chunk of 16 kHz PCM16 (little-endian). Returns what to forward and
187
+ * whether the gate opened/closed during this chunk.
188
+ */
189
+ push(pcm: Buffer): {
190
+ out: Buffer;
191
+ opened: boolean;
192
+ closed: boolean;
193
+ };
194
+ }
195
+ export declare function frameRms(pcm: Buffer): number;
196
+ /** Build the `session.start` event (exported for tests). */
197
+ export declare function buildGptLiveSessionStart(o: GptLiveAdapterOptions): Record<string, unknown>;
198
+ /** OpenAI echoes part of a wrong key in error bodies — never pass it on. */
199
+ export declare function redactKey(s: string): string;
200
+ export declare class GptLiveAdapter implements RealtimeSpeechAdapter {
201
+ private readonly o;
202
+ private readonly sessions;
203
+ private audioOutputHandler;
204
+ private transcriptHandler;
205
+ private errorHandler;
206
+ private toolCallHandler;
207
+ private speechActivityHandler;
208
+ private delegationHandler;
209
+ private usageHandler;
210
+ private unspokenHandler;
211
+ constructor(opts: GptLiveAdapterOptions);
212
+ onAudioOutput(h: (chunk: Buffer, linkedId: string) => void): void;
213
+ onTranscript(h: (r: TranscriptResult) => void): void;
214
+ onError(h: (err: Error, linkedId?: string) => void): void;
215
+ /** Responses delegation: a backend function call to run. Answer with submitToolResult(). */
216
+ onToolCall(h: (c: RealtimeToolCall) => void): void;
217
+ /** caller: from input transcript timing · callee: from the output speech gate (both approximate). */
218
+ onSpeechActivity(h: (e: RealtimeSpeechActivityEvent) => void): void;
219
+ /** Client delegation: return `{ speak }` (said aloud, paraphrased) or `{ note }` (silent context). */
220
+ onDelegation(h: (d: GptLiveDelegation) => GptLiveDelegationResult | Promise<GptLiveDelegationResult>): void;
221
+ onUsage(h: (u: GptLiveUsage) => void): void;
222
+ /** A result was sent but the model did not start speaking within `unspokenResultMs`. */
223
+ onUnspokenResult(h: (u: GptLiveUnspokenResult) => void): void;
224
+ startSession(linkedId: string, audioIn: AsyncIterable<AudioChunk>): Promise<void>;
225
+ /** Close gracefully: session.close → wait for session.closed (final usage) → close the socket. */
226
+ stop(linkedId?: string): Promise<void>;
227
+ /** Responses delegation: return a function result. Continues the backend once every pending call is answered. */
228
+ submitToolResult(linkedId: string, callId: string, result: unknown): void;
229
+ /** Something to say now (paraphrased). Pass the client delegation id for a task result, else null. */
230
+ appendCommentary(linkedId: string, delegationId: string | null, text: string): void;
231
+ /** Silent context the model may use later. */
232
+ appendThinking(linkedId: string, delegationId: string | null, text: string): void;
233
+ /** Trusted instructions (can interrupt current speech). */
234
+ appendInstructions(linkedId: string, text: string): void;
235
+ muteInput(linkedId: string): void;
236
+ unmuteInput(linkedId: string): void;
237
+ private eid;
238
+ private send;
239
+ private append;
240
+ private connect;
241
+ private waitStarted;
242
+ private pipeAudio;
243
+ private handle;
244
+ private transcriptDelta;
245
+ private closeUtterance;
246
+ private watchResult;
247
+ private markSpoken;
248
+ private finish;
249
+ }
250
+ //# sourceMappingURL=gpt-live.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpt-live.d.ts","sourceRoot":"","sources":["../../src/realtime/gpt-live.ts"],"names":[],"mappings":"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"}