@zhivex-ai/openai 0.15.0 → 0.16.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.
- package/README.md +18 -5
- package/dist/image-generation.d.ts +3 -2
- package/dist/image-generation.d.ts.map +1 -1
- package/dist/image-generation.js +11 -1
- package/dist/image-generation.js.map +1 -1
- package/dist/live-audio.d.ts +6 -0
- package/dist/live-audio.d.ts.map +1 -0
- package/dist/live-audio.js +23 -0
- package/dist/live-audio.js.map +1 -0
- package/dist/live-session.d.ts +85 -0
- package/dist/live-session.d.ts.map +1 -0
- package/dist/live-session.js +166 -0
- package/dist/live-session.js.map +1 -0
- package/dist/live-webrtc-browser.d.ts +31 -0
- package/dist/live-webrtc-browser.d.ts.map +1 -0
- package/dist/live-webrtc-browser.js +235 -0
- package/dist/live-webrtc-browser.js.map +1 -0
- package/dist/live-webrtc-protocol.d.ts +15 -0
- package/dist/live-webrtc-protocol.d.ts.map +1 -0
- package/dist/live-webrtc-protocol.js +21 -0
- package/dist/live-webrtc-protocol.js.map +1 -0
- package/dist/live-webrtc-server.d.ts +34 -0
- package/dist/live-webrtc-server.d.ts.map +1 -0
- package/dist/live-webrtc-server.js +79 -0
- package/dist/live-webrtc-server.js.map +1 -0
- package/dist/live.d.ts +4 -5
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +6 -150
- package/dist/live.js.map +1 -1
- package/dist/model-profiles.d.ts +2 -0
- package/dist/model-profiles.d.ts.map +1 -1
- package/dist/model-profiles.js +11 -7
- package/dist/model-profiles.js.map +1 -1
- package/package.json +9 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { ConfigurationError, withTimeoutSignal } from "@zhivex-ai/core/runtime";
|
|
2
|
+
import { createLiveSession, isOpenAILiveModel } from "./live-session.js";
|
|
3
|
+
import { liveAnswer, liveSdp, liveSessionId } from "./live-webrtc-protocol.js";
|
|
4
|
+
/** Experimental browser transport over the shared RealtimeSession lifecycle. */
|
|
5
|
+
export async function experimentalConnectOpenAILiveWebRTC(options) {
|
|
6
|
+
const modelId = options.modelId ?? "gpt-live-1";
|
|
7
|
+
if (!isOpenAILiveModel(modelId))
|
|
8
|
+
throw new ConfigurationError("A supported GPT-Live-1 model is required.");
|
|
9
|
+
if (typeof options.exchangeSdp !== "function" || typeof options.releaseSession !== "function")
|
|
10
|
+
throw new ConfigurationError("Application SDP exchange and session cleanup callbacks are required.");
|
|
11
|
+
if (!options.mediaStream?.getAudioTracks().length)
|
|
12
|
+
throw new ConfigurationError("WebRTC requires an application-provided audio track.");
|
|
13
|
+
if (options.closeTimeoutMs !== undefined && (!Number.isSafeInteger(options.closeTimeoutMs) || options.closeTimeoutMs <= 0))
|
|
14
|
+
throw new ConfigurationError("Invalid close timeout.");
|
|
15
|
+
if (!options.peerConnectionFactory && typeof globalThis.RTCPeerConnection !== "function")
|
|
16
|
+
throw new ConfigurationError("This browser does not support RTCPeerConnection.");
|
|
17
|
+
const deadline = withTimeoutSignal({ timeoutMs: options.timeoutMs ?? 15_000, abortSignal: options.signal });
|
|
18
|
+
let pc;
|
|
19
|
+
try {
|
|
20
|
+
deadline.signal.throwIfAborted();
|
|
21
|
+
pc = (options.peerConnectionFactory ?? (() => new RTCPeerConnection({ iceServers: [] })))();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
deadline.cleanup();
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
const tracks = [];
|
|
28
|
+
const enabled = [];
|
|
29
|
+
let channel;
|
|
30
|
+
let closed = false, acknowledged = false, sessionId;
|
|
31
|
+
let failure;
|
|
32
|
+
let receiver;
|
|
33
|
+
const queue = [];
|
|
34
|
+
let queuedBytes = 0;
|
|
35
|
+
let released;
|
|
36
|
+
let rejectInterrupted;
|
|
37
|
+
const interrupted = new Promise((_, reject) => { rejectInterrupted = reject; });
|
|
38
|
+
void interrupted.catch(() => { });
|
|
39
|
+
const bounded = (promise) => Promise.race([promise, interrupted]);
|
|
40
|
+
const report = (error) => { try {
|
|
41
|
+
options.onError?.(error);
|
|
42
|
+
}
|
|
43
|
+
catch { /* Teardown must proceed. */ } };
|
|
44
|
+
const release = () => {
|
|
45
|
+
if (acknowledged || !sessionId)
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
if (!released) {
|
|
48
|
+
// An aborted handshake signal must not cancel the backend's cleanup request.
|
|
49
|
+
released = (async () => {
|
|
50
|
+
let timer;
|
|
51
|
+
try {
|
|
52
|
+
await Promise.race([options.releaseSession({ sessionId: sessionId }), new Promise((_, reject) => {
|
|
53
|
+
timer = setTimeout(() => reject(new Error("Backend session cleanup timed out; finalization is unconfirmed.")), 5000);
|
|
54
|
+
})]);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
report(error instanceof Error ? error : new Error("Backend session cleanup failed; finalization is unconfirmed."));
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
if (timer)
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
}
|
|
63
|
+
})();
|
|
64
|
+
}
|
|
65
|
+
return released;
|
|
66
|
+
};
|
|
67
|
+
const cleanup = () => {
|
|
68
|
+
if (closed)
|
|
69
|
+
return;
|
|
70
|
+
closed = true;
|
|
71
|
+
deadline.cleanup();
|
|
72
|
+
deadline.signal.removeEventListener("abort", abortSetup);
|
|
73
|
+
options.signal?.removeEventListener("abort", abortCaller);
|
|
74
|
+
pc.ontrack = null;
|
|
75
|
+
pc.onconnectionstatechange = null;
|
|
76
|
+
if (channel) {
|
|
77
|
+
channel.onmessage = null;
|
|
78
|
+
channel.onerror = null;
|
|
79
|
+
channel.onclose = null;
|
|
80
|
+
channel.close();
|
|
81
|
+
}
|
|
82
|
+
for (const track of tracks)
|
|
83
|
+
track.stop();
|
|
84
|
+
pc.close();
|
|
85
|
+
queue.length = 0;
|
|
86
|
+
queuedBytes = 0;
|
|
87
|
+
receiver?.reject(failure ?? new Error("WebRTC connection closed."));
|
|
88
|
+
receiver = undefined;
|
|
89
|
+
rejectInterrupted(failure ?? new Error("WebRTC connection closed."));
|
|
90
|
+
};
|
|
91
|
+
const fail = (error) => {
|
|
92
|
+
if (closed || acknowledged)
|
|
93
|
+
return;
|
|
94
|
+
failure = error;
|
|
95
|
+
cleanup();
|
|
96
|
+
deadline.abort(error);
|
|
97
|
+
void release();
|
|
98
|
+
report(error);
|
|
99
|
+
};
|
|
100
|
+
const abortSetup = () => fail(deadline.signal.reason instanceof Error ? deadline.signal.reason : new Error("WebRTC connection aborted; finalization is unconfirmed."));
|
|
101
|
+
const abortCaller = () => fail(options.signal?.reason instanceof Error ? options.signal.reason : new Error("WebRTC session aborted; finalization is unconfirmed."));
|
|
102
|
+
const connection = {
|
|
103
|
+
async sendJson(payload) {
|
|
104
|
+
if (closed || channel?.readyState !== "open")
|
|
105
|
+
throw new ConfigurationError("WebRTC data channel is not open.");
|
|
106
|
+
const json = JSON.stringify(payload), bytes = new TextEncoder().encode(json).length;
|
|
107
|
+
if (bytes > 64 * 1024 || bytes + channel.bufferedAmount > 256 * 1024)
|
|
108
|
+
throw new ConfigurationError("WebRTC outgoing buffer limit exceeded.");
|
|
109
|
+
channel.send(json);
|
|
110
|
+
},
|
|
111
|
+
async recvJson() {
|
|
112
|
+
if (failure)
|
|
113
|
+
throw failure;
|
|
114
|
+
if (queue.length) {
|
|
115
|
+
const entry = queue.shift();
|
|
116
|
+
queuedBytes -= entry.bytes;
|
|
117
|
+
return entry.payload;
|
|
118
|
+
}
|
|
119
|
+
if (closed)
|
|
120
|
+
return undefined;
|
|
121
|
+
if (receiver)
|
|
122
|
+
throw new ConfigurationError("Concurrent WebRTC receives are unsupported.");
|
|
123
|
+
return new Promise((resolve, reject) => { receiver = { resolve, reject }; });
|
|
124
|
+
},
|
|
125
|
+
async close() { cleanup(); await release(); }
|
|
126
|
+
};
|
|
127
|
+
deadline.signal.addEventListener("abort", abortSetup, { once: true });
|
|
128
|
+
try {
|
|
129
|
+
pc.ontrack = event => { try {
|
|
130
|
+
options.onTrack?.(event);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
fail(new Error("Application track callback failed; finalization is unconfirmed."));
|
|
134
|
+
} };
|
|
135
|
+
pc.onconnectionstatechange = () => { if (["failed", "closed", "disconnected"].includes(pc.connectionState))
|
|
136
|
+
fail(new Error("WebRTC connection lost; final usage is unconfirmed.")); };
|
|
137
|
+
for (const source of options.mediaStream.getAudioTracks()) {
|
|
138
|
+
const track = source.clone();
|
|
139
|
+
tracks.push(track);
|
|
140
|
+
enabled.push(source.enabled);
|
|
141
|
+
track.enabled = false;
|
|
142
|
+
pc.addTrack(track, options.mediaStream);
|
|
143
|
+
}
|
|
144
|
+
channel = pc.createDataChannel("oai-events");
|
|
145
|
+
channel.onerror = () => fail(new Error("WebRTC data channel failed; finalization is unconfirmed."));
|
|
146
|
+
channel.onclose = () => fail(new Error("WebRTC data channel closed before session.closed; final usage is unconfirmed."));
|
|
147
|
+
channel.onmessage = event => {
|
|
148
|
+
if (closed)
|
|
149
|
+
return;
|
|
150
|
+
try {
|
|
151
|
+
if (typeof event.data !== "string")
|
|
152
|
+
throw new Error("WebRTC events must be JSON text.");
|
|
153
|
+
const bytes = new TextEncoder().encode(event.data).length;
|
|
154
|
+
if (bytes > 64 * 1024)
|
|
155
|
+
throw new Error("WebRTC event exceeds 64 KiB.");
|
|
156
|
+
const payload = JSON.parse(event.data);
|
|
157
|
+
if (!payload || Array.isArray(payload) || typeof payload.type !== "string")
|
|
158
|
+
throw new Error("Invalid WebRTC event.");
|
|
159
|
+
if (payload.type === "session.started" && payload.session?.id !== sessionId)
|
|
160
|
+
throw new Error("WebRTC session ID mismatch.");
|
|
161
|
+
if (payload.type === "session.closed") {
|
|
162
|
+
if (payload.session?.id !== sessionId || !Number.isFinite(payload.usage?.seconds) || payload.usage.seconds < 0)
|
|
163
|
+
throw new Error("Invalid WebRTC finalization event; final usage is unconfirmed.");
|
|
164
|
+
acknowledged = true;
|
|
165
|
+
}
|
|
166
|
+
if (receiver) {
|
|
167
|
+
const waiter = receiver;
|
|
168
|
+
receiver = undefined;
|
|
169
|
+
waiter.resolve(payload);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
if (queue.length >= 128 || queuedBytes + bytes > 256 * 1024)
|
|
173
|
+
throw new Error("WebRTC incoming queue limit exceeded.");
|
|
174
|
+
queue.push({ payload, bytes });
|
|
175
|
+
queuedBytes += bytes;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
fail(error instanceof Error ? error : new Error("Invalid WebRTC event."));
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const offer = await bounded(pc.createOffer());
|
|
183
|
+
if (closed)
|
|
184
|
+
throw failure;
|
|
185
|
+
await bounded(pc.setLocalDescription(offer));
|
|
186
|
+
if (pc.iceGatheringState !== "complete")
|
|
187
|
+
await new Promise((resolve, reject) => {
|
|
188
|
+
const finish = (error) => { pc.removeEventListener("icegatheringstatechange", check); deadline.signal.removeEventListener("abort", abort); error ? reject(error) : resolve(); };
|
|
189
|
+
const check = () => { if (pc.iceGatheringState === "complete")
|
|
190
|
+
finish(); };
|
|
191
|
+
const abort = () => finish(deadline.signal.reason);
|
|
192
|
+
pc.addEventListener("icegatheringstatechange", check);
|
|
193
|
+
deadline.signal.addEventListener("abort", abort, { once: true });
|
|
194
|
+
check();
|
|
195
|
+
if (deadline.signal.aborted)
|
|
196
|
+
abort();
|
|
197
|
+
});
|
|
198
|
+
if (closed)
|
|
199
|
+
throw failure;
|
|
200
|
+
const exchange = options.exchangeSdp({ offerSdp: liveSdp(pc.localDescription?.sdp), signal: deadline.signal }).then(raw => {
|
|
201
|
+
sessionId = liveSessionId(raw?.session?.id);
|
|
202
|
+
const answer = liveAnswer(raw);
|
|
203
|
+
if (closed) {
|
|
204
|
+
void release();
|
|
205
|
+
throw failure ?? new Error("WebRTC closed during signaling.");
|
|
206
|
+
}
|
|
207
|
+
return answer;
|
|
208
|
+
});
|
|
209
|
+
const answer = await bounded(exchange);
|
|
210
|
+
await bounded(pc.setRemoteDescription({ type: "answer", sdp: answer.transport.sdp }));
|
|
211
|
+
if (closed)
|
|
212
|
+
throw failure;
|
|
213
|
+
const session = createLiveSession(modelId, { delegation: { type: "client" }, providerOptions: { closeTimeoutMs: options.closeTimeoutMs } }, connection, { started: true, webrtc: true, timeoutMs: options.timeoutMs });
|
|
214
|
+
await bounded(session.initialize());
|
|
215
|
+
if (closed)
|
|
216
|
+
throw failure;
|
|
217
|
+
deadline.cleanup();
|
|
218
|
+
deadline.signal.removeEventListener("abort", abortSetup);
|
|
219
|
+
options.signal?.addEventListener("abort", abortCaller, { once: true });
|
|
220
|
+
if (options.signal?.aborted) {
|
|
221
|
+
abortCaller();
|
|
222
|
+
throw failure;
|
|
223
|
+
}
|
|
224
|
+
tracks.forEach((track, index) => { track.enabled = enabled[index]; });
|
|
225
|
+
return Object.assign(session, { sessionId: answer.session.id, peerConnection: pc });
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
failure ??= error instanceof Error ? error : new Error("WebRTC setup failed.");
|
|
229
|
+
deadline.abort(failure);
|
|
230
|
+
cleanup();
|
|
231
|
+
await release();
|
|
232
|
+
throw failure;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=live-webrtc-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-webrtc-browser.js","sourceRoot":"","sources":["../src/live-webrtc-browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Experimental, secret-free response returned to the browser. */
|
|
2
|
+
export interface OpenAILiveWebRTCAnswer {
|
|
3
|
+
session: {
|
|
4
|
+
id: string;
|
|
5
|
+
};
|
|
6
|
+
transport: {
|
|
7
|
+
type: "webrtc";
|
|
8
|
+
sdp: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare const LIVE_SDP_MAX_BYTES: number;
|
|
12
|
+
export declare function liveSdp(value: unknown): string;
|
|
13
|
+
export declare function liveSessionId(value: unknown): string;
|
|
14
|
+
export declare function liveAnswer(value: unknown): OpenAILiveWebRTCAnswer;
|
|
15
|
+
//# sourceMappingURL=live-webrtc-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-webrtc-protocol.d.ts","sourceRoot":"","sources":["../src/live-webrtc-protocol.ts"],"names":[],"mappings":"AAEA,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,SAAS,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AACD,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAK9C;AACD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGpD;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAKjE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ConfigurationError } from "@zhivex-ai/core/runtime";
|
|
2
|
+
export const LIVE_SDP_MAX_BYTES = 64 * 1024;
|
|
3
|
+
export function liveSdp(value) {
|
|
4
|
+
if (typeof value !== "string" || !value.startsWith("v=0\r\n") && !value.startsWith("v=0\n") || new TextEncoder().encode(value).length > LIVE_SDP_MAX_BYTES) {
|
|
5
|
+
throw new ConfigurationError("GPT-Live requires a valid SDP of at most 64 KiB.");
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
export function liveSessionId(value) {
|
|
10
|
+
if (typeof value !== "string" || !value || value === "." || value === ".." || value.length > 256 || /[\s\x00-\x1f\x7f]/.test(value))
|
|
11
|
+
throw new ConfigurationError("Invalid GPT-Live session ID.");
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
export function liveAnswer(value) {
|
|
15
|
+
const result = value;
|
|
16
|
+
if (result?.transport?.type !== "webrtc")
|
|
17
|
+
throw new ConfigurationError("Invalid GPT-Live WebRTC answer.");
|
|
18
|
+
// Whitelist fields: never serialize the provider's session configuration or secrets.
|
|
19
|
+
return { session: { id: liveSessionId(result.session?.id) }, transport: { type: "webrtc", sdp: liveSdp(result.transport.sdp) } };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=live-webrtc-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-webrtc-protocol.js","sourceRoot":"","sources":["../src/live-webrtc-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAO7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;QAC3J,MAAM,IAAI,kBAAkB,CAAC,kDAAkD,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AACD,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,kBAAkB,CAAC,8BAA8B,CAAC,CAAC;IAClM,OAAO,KAAK,CAAC;AACf,CAAC;AACD,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,MAAM,MAAM,GAAG,KAAoD,CAAC;IACpE,IAAI,MAAM,EAAE,SAAS,EAAE,IAAI,KAAK,QAAQ;QAAE,MAAM,IAAI,kBAAkB,CAAC,iCAAiC,CAAC,CAAC;IAC1G,qFAAqF;IACrF,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;AACnI,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type RealtimeConnectionFactory, type RealtimeConnectOptions, type RealtimeSessionConfig } from "@zhivex-ai/core/provider";
|
|
2
|
+
import { type OpenAILiveWebRTCAnswer } from "./live-webrtc-protocol.js";
|
|
3
|
+
export type { OpenAILiveWebRTCAnswer } from "./live-webrtc-protocol.js";
|
|
4
|
+
export interface OpenAILiveServerOptions {
|
|
5
|
+
/** Trusted server only. No environment lookup or browser credential flow. */
|
|
6
|
+
apiKey: string;
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
safetyIdentifier?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface OpenAILiveWebRTCCreateOptions extends OpenAILiveServerOptions, Pick<RealtimeConnectOptions, "signal" | "timeoutMs"> {
|
|
11
|
+
modelId?: string;
|
|
12
|
+
offerSdp: string;
|
|
13
|
+
session?: RealtimeSessionConfig;
|
|
14
|
+
/** Bind the known ID to an application creation lease before delivering the answer. */
|
|
15
|
+
onSessionCreated?: (input: {
|
|
16
|
+
sessionId: string;
|
|
17
|
+
}) => void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/** Experimental trusted-server SDP exchange. One request, no retries. */
|
|
20
|
+
export declare function experimentalCreateOpenAILiveWebRTCSession(options: OpenAILiveWebRTCCreateOptions): Promise<OpenAILiveWebRTCAnswer>;
|
|
21
|
+
export interface OpenAILiveAttachOptions extends OpenAILiveServerOptions, RealtimeConnectOptions {
|
|
22
|
+
/** Authorize this ID against the authenticated user's server-side session record first. */
|
|
23
|
+
sessionId: string;
|
|
24
|
+
modelId?: string;
|
|
25
|
+
session?: RealtimeSessionConfig;
|
|
26
|
+
connectionFactory?: RealtimeConnectionFactory;
|
|
27
|
+
}
|
|
28
|
+
/** Experimental sideband for runRealtimeDelegations. Does not start another paid session. */
|
|
29
|
+
export declare function experimentalAttachOpenAILiveSession(options: OpenAILiveAttachOptions): Promise<import("@zhivex-ai/core/provider").CallbackRealtimeSession & {
|
|
30
|
+
sessionId: string;
|
|
31
|
+
/** Detach only; the primary session continues billing. close() ends the shared session. */
|
|
32
|
+
disconnect: () => Promise<void>;
|
|
33
|
+
}>;
|
|
34
|
+
//# sourceMappingURL=live-webrtc-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-webrtc-server.d.ts","sourceRoot":"","sources":["../src/live-webrtc-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,yBAAyB,EAAE,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EACxF,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAsC,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAC5G,YAAY,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAExE,MAAM,WAAW,uBAAuB;IACtC,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AACD,MAAM,WAAW,6BAA8B,SAAQ,uBAAuB,EAAE,IAAI,CAAC,sBAAsB,EAAE,QAAQ,GAAG,WAAW,CAAC;IAClI,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAMD,yEAAyE;AACzE,wBAAsB,yCAAyC,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAkCvI;AACD,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB,EAAE,sBAAsB;IAC9F,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,iBAAiB,CAAC,EAAE,yBAAyB,CAAC;CAC/C;AACD,6FAA6F;AAC7F,wBAAsB,mCAAmC,CAAC,OAAO,EAAE,uBAAuB;;IActF,2FAA2F;;GAG9F"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ConfigurationError, ProviderHTTPError, assertTrustedEndpoint, openWebSocketConnection, readJsonWithLimit, withTimeoutSignal } from "@zhivex-ai/core/provider";
|
|
2
|
+
import { liveAudioCallbacks } from "./live-audio.js";
|
|
3
|
+
import { createLiveSession, isOpenAILiveModel, resolveLiveWebRTCConfig } from "./live-session.js";
|
|
4
|
+
import { liveAnswer, liveSdp, liveSessionId } from "./live-webrtc-protocol.js";
|
|
5
|
+
const headers = (options) => {
|
|
6
|
+
if (typeof options.apiKey !== "string" || !options.apiKey.trim() || /[\r\n]/.test(options.apiKey))
|
|
7
|
+
throw new ConfigurationError("A server API key is required.");
|
|
8
|
+
if (options.safetyIdentifier !== undefined && (!/^[\x21-\x7e]{1,256}$/.test(options.safetyIdentifier)))
|
|
9
|
+
throw new ConfigurationError("Invalid safety identifier.");
|
|
10
|
+
return { authorization: `Bearer ${options.apiKey}`, ...(options.safetyIdentifier ? { "OpenAI-Safety-Identifier": options.safetyIdentifier } : {}) };
|
|
11
|
+
};
|
|
12
|
+
/** Experimental trusted-server SDP exchange. One request, no retries. */
|
|
13
|
+
export async function experimentalCreateOpenAILiveWebRTCSession(options) {
|
|
14
|
+
const modelId = options.modelId ?? "gpt-live-1";
|
|
15
|
+
if (!isOpenAILiveModel(modelId))
|
|
16
|
+
throw new ConfigurationError("A supported GPT-Live-1 model is required.");
|
|
17
|
+
const config = resolveLiveWebRTCConfig(options.session);
|
|
18
|
+
const requestHeaders = headers(options);
|
|
19
|
+
const body = JSON.stringify({ session: {
|
|
20
|
+
model: modelId, delegation: { type: "client" }, store: config.providerOptions?.store ?? false,
|
|
21
|
+
...(config.instructions !== undefined ? { instructions: config.instructions } : {}),
|
|
22
|
+
audio: { output: { voice: config.voice ?? "marin" } },
|
|
23
|
+
...(config.providerOptions?.input !== undefined ? { input: config.providerOptions.input } : {}),
|
|
24
|
+
// The browser may close/mute, but cannot append instructions or backend results.
|
|
25
|
+
client: { data_channel: {
|
|
26
|
+
allowed_client_events: ["session.close", "session.input_audio.mute", "session.input_audio.unmute"],
|
|
27
|
+
allowed_server_events: ["session.started", "session.closed", "session.input_transcript.delta", "session.output_transcript.delta", "session.usage.updated", "error"].map(type => ({ type }))
|
|
28
|
+
} }
|
|
29
|
+
}, transport: { type: "webrtc", sdp: liveSdp(options.offerSdp) } });
|
|
30
|
+
if (new TextEncoder().encode(body).length > 256 * 1024)
|
|
31
|
+
throw new ConfigurationError("GPT-Live session request exceeds 256 KiB.");
|
|
32
|
+
const deadline = withTimeoutSignal({ timeoutMs: options.timeoutMs ?? 15_000, abortSignal: options.signal });
|
|
33
|
+
try {
|
|
34
|
+
deadline.signal.throwIfAborted();
|
|
35
|
+
const response = await (options.fetch ?? fetch)("https://api.openai.com/v1/live/sessions", {
|
|
36
|
+
method: "POST", headers: { ...requestHeaders, "content-type": "application/json" }, body, signal: deadline.signal, redirect: "error"
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
await response.body?.cancel();
|
|
40
|
+
throw new ProviderHTTPError(`OpenAI Live session creation failed (${response.status}).`, response.status);
|
|
41
|
+
}
|
|
42
|
+
const raw = await readJsonWithLimit(response, { maxBytes: 128 * 1024, provider: "openai", endpoint: "live/sessions", abort: deadline.abort });
|
|
43
|
+
// Record a valid ID even if the remaining response is malformed or the caller aborted.
|
|
44
|
+
const sessionId = liveSessionId(raw?.session?.id);
|
|
45
|
+
await options.onSessionCreated?.({ sessionId });
|
|
46
|
+
deadline.signal.throwIfAborted();
|
|
47
|
+
return liveAnswer(raw);
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
deadline.cleanup();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Experimental sideband for runRealtimeDelegations. Does not start another paid session. */
|
|
54
|
+
export async function experimentalAttachOpenAILiveSession(options) {
|
|
55
|
+
const modelId = options.modelId ?? "gpt-live-1";
|
|
56
|
+
if (!isOpenAILiveModel(modelId))
|
|
57
|
+
throw new ConfigurationError("A supported GPT-Live-1 model is required.");
|
|
58
|
+
const config = resolveLiveWebRTCConfig(options.session);
|
|
59
|
+
const url = assertTrustedEndpoint(`wss://api.openai.com/v1/live/sessions/${encodeURIComponent(liveSessionId(options.sessionId))}/attach`, {
|
|
60
|
+
label: "OpenAI Live sideband", protocols: ["wss"], allowedHosts: ["api.openai.com"]
|
|
61
|
+
});
|
|
62
|
+
const connection = await (options.connectionFactory ?? openWebSocketConnection)(url.toString(), headers(options), { signal: options.signal, timeoutMs: options.timeoutMs ?? 15_000, maxIncomingFrameBytes: options.maxIncomingFrameBytes, subprotocols: options.subprotocols });
|
|
63
|
+
// Attachment observes an already-running session: no session.start or started wait.
|
|
64
|
+
const reflected = { ...config, outputAudioMediaType: "audio/pcm", outputSampleRateHz: 24000 };
|
|
65
|
+
const session = createLiveSession(modelId, reflected, connection, { expectedSessionId: options.sessionId, started: true, attached: true, parseOutputAudio: liveAudioCallbacks(reflected).parseOutputAudio });
|
|
66
|
+
try {
|
|
67
|
+
await session.initialize();
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
await connection.close();
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
return Object.assign(session, {
|
|
74
|
+
sessionId: options.sessionId,
|
|
75
|
+
/** Detach only; the primary session continues billing. close() ends the shared session. */
|
|
76
|
+
disconnect: () => connection.close()
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=live-webrtc-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-webrtc-server.js","sourceRoot":"","sources":["../src/live-webrtc-server.ts"],"names":[],"mappings":"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"}
|
package/dist/live.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
export declare const liveCapabilities: ModelCapabilities;
|
|
1
|
+
import { type RealtimeModel, type RealtimeConnectOptions, type RealtimeConnectionFactory, type RealtimeSessionConfig } from "@zhivex-ai/core/provider";
|
|
2
|
+
export { isOpenAILiveModel } from "./live-session.js";
|
|
4
3
|
/** Server WebSocket adapter. The application owns the delegated agent and its tools. */
|
|
5
4
|
export declare class OpenAILiveModel implements RealtimeModel {
|
|
6
5
|
readonly modelId: string;
|
|
@@ -10,9 +9,9 @@ export declare class OpenAILiveModel implements RealtimeModel {
|
|
|
10
9
|
private readonly realtimeURL?;
|
|
11
10
|
private readonly allowUnsafeEndpoints;
|
|
12
11
|
readonly provider = "openai";
|
|
13
|
-
readonly capabilities: ModelCapabilities;
|
|
12
|
+
readonly capabilities: import("@zhivex-ai/core/provider").ModelCapabilities;
|
|
14
13
|
constructor(modelId: string, baseURL: string, headers: (options: Record<string, unknown> | undefined) => Record<string, string>, connectionFactory: RealtimeConnectionFactory, realtimeURL?: string | undefined, allowUnsafeEndpoints?: boolean);
|
|
15
|
-
connect(config?: RealtimeSessionConfig, options?: RealtimeConnectOptions): Promise<CallbackRealtimeSession>;
|
|
14
|
+
connect(config?: RealtimeSessionConfig, options?: RealtimeConnectOptions): Promise<import("@zhivex-ai/core/provider").CallbackRealtimeSession>;
|
|
16
15
|
createBrowserToken(): Promise<never>;
|
|
17
16
|
}
|
|
18
17
|
//# sourceMappingURL=live.d.ts.map
|
package/dist/live.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsE,KAAK,aAAa,EAAE,KAAK,sBAAsB,EAAE,KAAK,yBAAyB,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAG3N,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,wFAAwF;AACxF,qBAAa,eAAgB,YAAW,aAAa;IAIjD,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IARvC,QAAQ,CAAC,QAAQ,YAAY;IAC7B,QAAQ,CAAC,YAAY,uDAAoB;IACzC,YACW,OAAO,EAAE,MAAM,EACP,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjF,iBAAiB,EAAE,yBAAyB,EAC5C,WAAW,CAAC,EAAE,MAAM,YAAA,EACpB,oBAAoB,UAAQ,EAC3C;IAEE,OAAO,CAAC,MAAM,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE,sBAAsB,uEAgBjF;IAEK,kBAAkB,IAAI,OAAO,CAAC,KAAK,CAAC,CAEzC;CACF"}
|