@opengeni/sdk 0.52.1 → 1.0.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 +67 -7
- package/dist/artifacts.js +5 -5
- package/dist/{chunk-FRJFNDIR.js → chunk-4DV37UUA.js} +6 -2
- package/dist/chunk-4DV37UUA.js.map +1 -0
- package/dist/{chunk-KIHGPM7H.js → chunk-A5DC5WEM.js} +288 -45
- package/dist/chunk-A5DC5WEM.js.map +1 -0
- package/dist/{chunk-V5F253OG.js → chunk-GU6JF75T.js} +6 -3
- package/dist/chunk-GU6JF75T.js.map +1 -0
- package/dist/{chunk-MZWTWOX6.js → chunk-ST5DDKJP.js} +327 -1
- package/dist/chunk-ST5DDKJP.js.map +1 -0
- package/dist/{chunk-FHI4DFIG.js → chunk-TYZ4JL4J.js} +2 -2
- package/dist/{chunk-ILQZR5N6.js → chunk-YGH5P47G.js} +693 -34
- package/dist/chunk-YGH5P47G.js.map +1 -0
- package/dist/{chunk-DXDL7EEW.js → chunk-YKZME56C.js} +197 -113
- package/dist/chunk-YKZME56C.js.map +1 -0
- package/dist/client.d.ts +108 -18
- package/dist/codex-realtime-controller.d.ts +5 -0
- package/dist/codex-realtime-controller.js +2 -2
- package/dist/codex-realtime-v3.d.ts +13 -2
- package/dist/core.js +7 -7
- package/dist/desktop.d.ts +8 -0
- package/dist/editable-artifacts.js +4 -4
- package/dist/gateway-realtime-transport.d.ts +1 -0
- package/dist/gateway-realtime-transport.js +5 -3
- package/dist/index.d.ts +6 -2
- package/dist/index.js +68 -34
- package/dist/index.js.map +1 -1
- package/dist/interaction-revision-stream.d.ts +11 -0
- package/dist/interaction.d.ts +604 -5
- package/dist/interaction.js +27 -1
- package/dist/realtime.d.ts +3 -3
- package/dist/realtime.js +11 -7
- package/dist/realtime.js.map +1 -1
- package/dist/types.d.ts +283 -69
- package/dist/workspace-live-stream.d.ts +14 -0
- package/package.json +2 -2
- package/src/client.ts +863 -62
- package/src/codex-realtime-controller.ts +239 -12
- package/src/codex-realtime-lifecycle.ts +1 -0
- package/src/codex-realtime-v3.ts +162 -31
- package/src/desktop.ts +11 -1
- package/src/errors.ts +16 -2
- package/src/gateway-realtime-transport.ts +252 -109
- package/src/index.ts +42 -13
- package/src/interaction-revision-stream.ts +117 -0
- package/src/interaction.ts +1049 -5
- package/src/realtime.ts +14 -4
- package/src/types.ts +353 -72
- package/src/workspace-live-stream.ts +137 -0
- package/dist/chunk-DXDL7EEW.js.map +0 -1
- package/dist/chunk-FRJFNDIR.js.map +0 -1
- package/dist/chunk-ILQZR5N6.js.map +0 -1
- package/dist/chunk-KIHGPM7H.js.map +0 -1
- package/dist/chunk-MZWTWOX6.js.map +0 -1
- package/dist/chunk-V5F253OG.js.map +0 -1
- /package/dist/{chunk-FHI4DFIG.js.map → chunk-TYZ4JL4J.js.map} +0 -0
package/src/errors.ts
CHANGED
|
@@ -41,7 +41,9 @@ export class OpenGeniApiError extends Error {
|
|
|
41
41
|
this.retryable = options.retryable ?? decoded?.retryable ?? retryableApiStatus(status);
|
|
42
42
|
this.correlationId = correlationId;
|
|
43
43
|
this.outcomeUnknown =
|
|
44
|
-
options.outcomeUnknown ??
|
|
44
|
+
options.outcomeUnknown ??
|
|
45
|
+
decoded?.outcomeUnknown ??
|
|
46
|
+
(gatewayFailure && !!options.mutation && !decoded);
|
|
45
47
|
this.body = !fromResponse || decoded ? body : "";
|
|
46
48
|
this.details = decoded?.details;
|
|
47
49
|
}
|
|
@@ -52,6 +54,7 @@ function decodeApiErrorBody(body: string): {
|
|
|
52
54
|
message: string | undefined;
|
|
53
55
|
requestId: string | undefined;
|
|
54
56
|
retryable: boolean | undefined;
|
|
57
|
+
outcomeUnknown: boolean | undefined;
|
|
55
58
|
details: Record<string, unknown> | undefined;
|
|
56
59
|
} | null {
|
|
57
60
|
if (!body) return null;
|
|
@@ -67,13 +70,24 @@ function decodeApiErrorBody(body: string): {
|
|
|
67
70
|
const message = boundedApiField(nested.message);
|
|
68
71
|
const requestId = boundedCorrelationId(nested.requestId);
|
|
69
72
|
const retryable = typeof nested.retryable === "boolean" ? nested.retryable : undefined;
|
|
73
|
+
const outcomeUnknown =
|
|
74
|
+
typeof nested.outcomeUnknown === "boolean" ? nested.outcomeUnknown : undefined;
|
|
70
75
|
const details = boundedApiDetails(nested.details);
|
|
71
|
-
if (
|
|
76
|
+
if (
|
|
77
|
+
!code &&
|
|
78
|
+
!message &&
|
|
79
|
+
!requestId &&
|
|
80
|
+
retryable === undefined &&
|
|
81
|
+
outcomeUnknown === undefined &&
|
|
82
|
+
!details
|
|
83
|
+
)
|
|
84
|
+
return null;
|
|
72
85
|
return {
|
|
73
86
|
code,
|
|
74
87
|
message,
|
|
75
88
|
requestId,
|
|
76
89
|
retryable,
|
|
90
|
+
outcomeUnknown,
|
|
77
91
|
details,
|
|
78
92
|
};
|
|
79
93
|
} catch {
|
|
@@ -9,14 +9,33 @@ type GatewayServerEvent = Record<string, unknown> & { type: string };
|
|
|
9
9
|
|
|
10
10
|
const AUDIO_SAMPLE_RATE = 24_000;
|
|
11
11
|
const DELEGATION_TOOL = "delegate_to_session";
|
|
12
|
+
type RealtimeDialect = "gateway" | "xai";
|
|
12
13
|
|
|
13
14
|
export function createGatewayRealtimeTransportStarter(): RealtimeControllerTransportStarter {
|
|
15
|
+
return createWebsocketRealtimeTransportStarter("gateway");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createXaiSubscriptionRealtimeTransportStarter(): RealtimeControllerTransportStarter {
|
|
19
|
+
return createWebsocketRealtimeTransportStarter("xai");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function createWebsocketRealtimeTransportStarter(
|
|
23
|
+
dialect: RealtimeDialect,
|
|
24
|
+
): RealtimeControllerTransportStarter {
|
|
14
25
|
return async (input) => {
|
|
15
26
|
const client = input.client as CodexRealtimeControllerClient;
|
|
16
|
-
|
|
17
|
-
|
|
27
|
+
const negotiate =
|
|
28
|
+
dialect === "xai"
|
|
29
|
+
? client.negotiateXaiSubscriptionRealtime?.bind(client)
|
|
30
|
+
: client.negotiateGatewayRealtime?.bind(client);
|
|
31
|
+
if (!negotiate) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
dialect === "xai"
|
|
34
|
+
? "The OpenGeni client does not support connected SuperGrok realtime"
|
|
35
|
+
: "The OpenGeni client does not support AI Gateway realtime",
|
|
36
|
+
);
|
|
18
37
|
}
|
|
19
|
-
const answer = await
|
|
38
|
+
const answer = await negotiate(
|
|
20
39
|
input.workspaceId,
|
|
21
40
|
input.sessionId,
|
|
22
41
|
{
|
|
@@ -32,16 +51,22 @@ export function createGatewayRealtimeTransportStarter(): RealtimeControllerTrans
|
|
|
32
51
|
);
|
|
33
52
|
throwIfAborted(input.signal);
|
|
34
53
|
|
|
35
|
-
const websocket = new WebSocket(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
const websocket = new WebSocket(
|
|
55
|
+
answer.url,
|
|
56
|
+
dialect === "xai"
|
|
57
|
+
? [`xai-client-secret.${answer.token}`]
|
|
58
|
+
: ["ai-gateway-realtime.v1", `ai-gateway-auth.${answer.token}`],
|
|
59
|
+
);
|
|
39
60
|
const channel = new GatewayRealtimeDataChannel((payload) =>
|
|
40
|
-
handleBridgeOutbound(websocket, payload),
|
|
61
|
+
handleBridgeOutbound(websocket, payload, dialect),
|
|
41
62
|
);
|
|
42
63
|
input.onEventsCreated(channel.asRtcDataChannel());
|
|
43
64
|
const audio = new GatewayRealtimeAudio({
|
|
44
|
-
onAudio: (encoded) =>
|
|
65
|
+
onAudio: (encoded) =>
|
|
66
|
+
send(websocket, {
|
|
67
|
+
type: dialect === "xai" ? "input_audio_buffer.append" : "input-audio-append",
|
|
68
|
+
audio: encoded,
|
|
69
|
+
}),
|
|
45
70
|
onAudibleOutputState: input.onAudibleOutputState,
|
|
46
71
|
});
|
|
47
72
|
let stopped = false;
|
|
@@ -62,8 +87,9 @@ export function createGatewayRealtimeTransportStarter(): RealtimeControllerTrans
|
|
|
62
87
|
return;
|
|
63
88
|
}
|
|
64
89
|
if (!isRecord(parsed) || typeof parsed.type !== "string") return;
|
|
65
|
-
|
|
90
|
+
handleRealtimeEvent({
|
|
66
91
|
event: parsed as GatewayServerEvent,
|
|
92
|
+
dialect,
|
|
67
93
|
channel,
|
|
68
94
|
websocket,
|
|
69
95
|
audio,
|
|
@@ -84,56 +110,6 @@ export function createGatewayRealtimeTransportStarter(): RealtimeControllerTrans
|
|
|
84
110
|
websocket.addEventListener("close", onClose);
|
|
85
111
|
websocket.addEventListener("error", onError);
|
|
86
112
|
|
|
87
|
-
await waitForWebSocketOpen(websocket, input.signal);
|
|
88
|
-
channel.open();
|
|
89
|
-
send(websocket, {
|
|
90
|
-
type: "session-update",
|
|
91
|
-
config: {
|
|
92
|
-
instructions: answer.instructions,
|
|
93
|
-
outputModalities: ["audio"],
|
|
94
|
-
inputAudioFormat: { type: "audio/pcm", rate: AUDIO_SAMPLE_RATE },
|
|
95
|
-
outputAudioFormat: { type: "audio/pcm", rate: AUDIO_SAMPLE_RATE },
|
|
96
|
-
inputAudioTranscription: {},
|
|
97
|
-
outputAudioTranscription: {},
|
|
98
|
-
turnDetection: {
|
|
99
|
-
type: "server-vad",
|
|
100
|
-
prefixPaddingMs: 300,
|
|
101
|
-
silenceDurationMs: 500,
|
|
102
|
-
},
|
|
103
|
-
tools: [
|
|
104
|
-
{
|
|
105
|
-
type: "function",
|
|
106
|
-
name: DELEGATION_TOOL,
|
|
107
|
-
description:
|
|
108
|
-
"Pass execution work, actions, and session tasks to the underlying session agent. Include the complete standalone request and relevant conversational context.",
|
|
109
|
-
parameters: {
|
|
110
|
-
type: "object",
|
|
111
|
-
properties: {
|
|
112
|
-
request: {
|
|
113
|
-
type: "string",
|
|
114
|
-
description: "Complete standalone task for the session agent",
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
required: ["request"],
|
|
118
|
-
additionalProperties: false,
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
],
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
for (const item of answer.initialItems) {
|
|
125
|
-
send(websocket, {
|
|
126
|
-
type: "conversation-item-create",
|
|
127
|
-
item: {
|
|
128
|
-
type: "text-message",
|
|
129
|
-
role: "user",
|
|
130
|
-
text: `<session_initial_item role="${item.role}">\n${item.text}\n</session_initial_item>`,
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
await audio.startCapture(input.media);
|
|
135
|
-
input.onConnectionHealth("connected");
|
|
136
|
-
|
|
137
113
|
const stop = (): void => {
|
|
138
114
|
if (stopped) return;
|
|
139
115
|
stopped = true;
|
|
@@ -153,6 +129,41 @@ export function createGatewayRealtimeTransportStarter(): RealtimeControllerTrans
|
|
|
153
129
|
};
|
|
154
130
|
input.signal.addEventListener("abort", stop, { once: true });
|
|
155
131
|
|
|
132
|
+
try {
|
|
133
|
+
await waitForWebSocketOpen(websocket, input.signal);
|
|
134
|
+
channel.open();
|
|
135
|
+
send(
|
|
136
|
+
websocket,
|
|
137
|
+
dialect === "xai"
|
|
138
|
+
? xaiSessionUpdate(answer.instructions)
|
|
139
|
+
: gatewaySessionUpdate(answer.instructions),
|
|
140
|
+
);
|
|
141
|
+
for (const item of answer.initialItems) {
|
|
142
|
+
const text = `<session_initial_item role="${item.role}">\n${item.text}\n</session_initial_item>`;
|
|
143
|
+
send(
|
|
144
|
+
websocket,
|
|
145
|
+
dialect === "xai"
|
|
146
|
+
? {
|
|
147
|
+
type: "conversation.item.create",
|
|
148
|
+
item: {
|
|
149
|
+
type: "message",
|
|
150
|
+
role: "user",
|
|
151
|
+
content: [{ type: "input_text", text }],
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
: {
|
|
155
|
+
type: "conversation-item-create",
|
|
156
|
+
item: { type: "text-message", role: "user", text },
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
await audio.startCapture(input.media);
|
|
161
|
+
input.onConnectionHealth("connected");
|
|
162
|
+
} catch (error) {
|
|
163
|
+
stop();
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
|
|
156
167
|
return {
|
|
157
168
|
peerConnection: null as unknown as RTCPeerConnection,
|
|
158
169
|
events: channel.asRtcDataChannel(),
|
|
@@ -174,8 +185,73 @@ export function createGatewayRealtimeTransportStarter(): RealtimeControllerTrans
|
|
|
174
185
|
};
|
|
175
186
|
}
|
|
176
187
|
|
|
177
|
-
function
|
|
188
|
+
function delegationTool(): Record<string, unknown> {
|
|
189
|
+
return {
|
|
190
|
+
type: "function",
|
|
191
|
+
name: DELEGATION_TOOL,
|
|
192
|
+
description:
|
|
193
|
+
"Pass execution work, actions, and session tasks to the underlying session agent. Include the complete standalone request and relevant conversational context.",
|
|
194
|
+
parameters: {
|
|
195
|
+
type: "object",
|
|
196
|
+
properties: {
|
|
197
|
+
request: {
|
|
198
|
+
type: "string",
|
|
199
|
+
description: "Complete standalone task for the session agent",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
required: ["request"],
|
|
203
|
+
additionalProperties: false,
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function gatewaySessionUpdate(instructions: string): GatewayClientEvent {
|
|
209
|
+
return {
|
|
210
|
+
type: "session-update",
|
|
211
|
+
config: {
|
|
212
|
+
instructions,
|
|
213
|
+
outputModalities: ["audio"],
|
|
214
|
+
inputAudioFormat: { type: "audio/pcm", rate: AUDIO_SAMPLE_RATE },
|
|
215
|
+
outputAudioFormat: { type: "audio/pcm", rate: AUDIO_SAMPLE_RATE },
|
|
216
|
+
inputAudioTranscription: {},
|
|
217
|
+
outputAudioTranscription: {},
|
|
218
|
+
turnDetection: {
|
|
219
|
+
type: "server-vad",
|
|
220
|
+
prefixPaddingMs: 300,
|
|
221
|
+
silenceDurationMs: 500,
|
|
222
|
+
},
|
|
223
|
+
tools: [delegationTool()],
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function xaiSessionUpdate(instructions: string): GatewayClientEvent {
|
|
229
|
+
return {
|
|
230
|
+
type: "session.update",
|
|
231
|
+
session: {
|
|
232
|
+
instructions,
|
|
233
|
+
voice: "eve",
|
|
234
|
+
reasoning: { effort: "high" },
|
|
235
|
+
turn_detection: {
|
|
236
|
+
type: "server_vad",
|
|
237
|
+
prefix_padding_ms: 300,
|
|
238
|
+
silence_duration_ms: 500,
|
|
239
|
+
},
|
|
240
|
+
audio: {
|
|
241
|
+
input: {
|
|
242
|
+
format: { type: "audio/pcm", rate: AUDIO_SAMPLE_RATE },
|
|
243
|
+
transcription: { model: "grok-transcribe" },
|
|
244
|
+
},
|
|
245
|
+
output: { format: { type: "audio/pcm", rate: AUDIO_SAMPLE_RATE } },
|
|
246
|
+
},
|
|
247
|
+
tools: [delegationTool()],
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function handleRealtimeEvent(input: {
|
|
178
253
|
event: GatewayServerEvent;
|
|
254
|
+
dialect: RealtimeDialect;
|
|
179
255
|
channel: GatewayRealtimeDataChannel;
|
|
180
256
|
websocket: WebSocket;
|
|
181
257
|
audio: GatewayRealtimeAudio;
|
|
@@ -185,8 +261,10 @@ function handleGatewayEvent(input: {
|
|
|
185
261
|
}): void {
|
|
186
262
|
const event = input.event;
|
|
187
263
|
const eventId = providerEventId(event);
|
|
188
|
-
if (event.type === "session-created") {
|
|
189
|
-
const
|
|
264
|
+
if (event.type === "session-created" || event.type === "session.created") {
|
|
265
|
+
const session = isRecord(event.session) ? event.session : null;
|
|
266
|
+
const sessionId =
|
|
267
|
+
stringValue(event.sessionId) ?? stringValue(session?.id) ?? `realtime-${crypto.randomUUID()}`;
|
|
190
268
|
input.channel.providerEvent({
|
|
191
269
|
type: "session.started",
|
|
192
270
|
event_id: eventId,
|
|
@@ -194,23 +272,36 @@ function handleGatewayEvent(input: {
|
|
|
194
272
|
});
|
|
195
273
|
return;
|
|
196
274
|
}
|
|
197
|
-
if (event.type === "speech-started") {
|
|
275
|
+
if (event.type === "speech-started" || event.type === "input_audio_buffer.speech_started") {
|
|
198
276
|
const itemId = input.getCurrentOutputItemId();
|
|
199
277
|
if (itemId && input.audio.isPlaying()) {
|
|
200
278
|
const audioEndMs = input.audio.playbackOffsetMs();
|
|
201
279
|
input.audio.stopPlayback();
|
|
202
|
-
send(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
280
|
+
send(
|
|
281
|
+
input.websocket,
|
|
282
|
+
input.dialect === "xai"
|
|
283
|
+
? {
|
|
284
|
+
type: "conversation.item.truncate",
|
|
285
|
+
item_id: itemId,
|
|
286
|
+
content_index: 0,
|
|
287
|
+
audio_end_ms: Math.max(0, Math.round(audioEndMs)),
|
|
288
|
+
}
|
|
289
|
+
: {
|
|
290
|
+
type: "conversation-item-truncate",
|
|
291
|
+
itemId,
|
|
292
|
+
contentIndex: 0,
|
|
293
|
+
audioEndMs: Math.max(0, Math.round(audioEndMs)),
|
|
294
|
+
},
|
|
295
|
+
);
|
|
208
296
|
}
|
|
209
297
|
return;
|
|
210
298
|
}
|
|
211
|
-
if (
|
|
299
|
+
if (
|
|
300
|
+
event.type === "input-transcription-completed" ||
|
|
301
|
+
event.type === "conversation.item.input_audio_transcription.completed"
|
|
302
|
+
) {
|
|
212
303
|
const transcript = stringValue(event.transcript) ?? "";
|
|
213
|
-
const itemId = stringValue(event.itemId) ?? crypto.randomUUID();
|
|
304
|
+
const itemId = stringValue(event.itemId) ?? stringValue(event.item_id) ?? crypto.randomUUID();
|
|
214
305
|
if (transcript.trim()) {
|
|
215
306
|
input.channel.providerEvent({
|
|
216
307
|
type: "turn.done",
|
|
@@ -220,17 +311,27 @@ function handleGatewayEvent(input: {
|
|
|
220
311
|
}
|
|
221
312
|
return;
|
|
222
313
|
}
|
|
223
|
-
if (
|
|
314
|
+
if (
|
|
315
|
+
event.type === "audio-delta" ||
|
|
316
|
+
event.type === "response.output_audio.delta" ||
|
|
317
|
+
event.type === "response.audio.delta"
|
|
318
|
+
) {
|
|
224
319
|
const delta = stringValue(event.delta);
|
|
225
320
|
if (!delta) return;
|
|
226
|
-
const itemId = stringValue(event.itemId);
|
|
321
|
+
const itemId = stringValue(event.itemId) ?? stringValue(event.item_id);
|
|
227
322
|
if (itemId) input.setCurrentOutputItemId(itemId);
|
|
228
323
|
input.audio.play(delta);
|
|
229
324
|
input.channel.providerEvent({ type: "output_audio.delta", event_id: eventId, audio: delta });
|
|
230
325
|
return;
|
|
231
326
|
}
|
|
232
|
-
if (
|
|
233
|
-
|
|
327
|
+
if (
|
|
328
|
+
event.type === "audio-transcript-done" ||
|
|
329
|
+
event.type === "text-done" ||
|
|
330
|
+
event.type === "response.output_audio_transcript.done" ||
|
|
331
|
+
event.type === "response.audio_transcript.done" ||
|
|
332
|
+
event.type === "response.output_text.done"
|
|
333
|
+
) {
|
|
334
|
+
const itemId = stringValue(event.itemId) ?? stringValue(event.item_id) ?? crypto.randomUUID();
|
|
234
335
|
const transcript = stringValue(event.transcript) ?? stringValue(event.text) ?? "";
|
|
235
336
|
if (transcript.trim() && !input.finalizedAssistantItems.has(itemId)) {
|
|
236
337
|
input.finalizedAssistantItems.add(itemId);
|
|
@@ -242,21 +343,27 @@ function handleGatewayEvent(input: {
|
|
|
242
343
|
}
|
|
243
344
|
return;
|
|
244
345
|
}
|
|
245
|
-
if (event.type === "audio-done") return;
|
|
246
|
-
if (
|
|
247
|
-
|
|
346
|
+
if (event.type === "audio-done" || event.type === "response.output_audio.done") return;
|
|
347
|
+
if (
|
|
348
|
+
event.type === "function-call-arguments-done" ||
|
|
349
|
+
event.type === "response.function_call_arguments.done"
|
|
350
|
+
) {
|
|
351
|
+
const callId =
|
|
352
|
+
stringValue(event.callId) ??
|
|
353
|
+
stringValue(event.call_id) ??
|
|
354
|
+
stringValue(event.itemId) ??
|
|
355
|
+
stringValue(event.item_id) ??
|
|
356
|
+
crypto.randomUUID();
|
|
248
357
|
const name = stringValue(event.name);
|
|
249
358
|
if (name !== DELEGATION_TOOL) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
});
|
|
259
|
-
send(input.websocket, { type: "response-create" });
|
|
359
|
+
sendFunctionOutput(
|
|
360
|
+
input.websocket,
|
|
361
|
+
input.dialect,
|
|
362
|
+
callId,
|
|
363
|
+
name,
|
|
364
|
+
JSON.stringify({ error: "Unsupported realtime tool" }),
|
|
365
|
+
);
|
|
366
|
+
sendResponseCreate(input.websocket, input.dialect);
|
|
260
367
|
return;
|
|
261
368
|
}
|
|
262
369
|
const request = delegationRequest(stringValue(event.arguments) ?? "");
|
|
@@ -273,10 +380,12 @@ function handleGatewayEvent(input: {
|
|
|
273
380
|
return;
|
|
274
381
|
}
|
|
275
382
|
if (event.type === "error") {
|
|
383
|
+
const nested = isRecord(event.error) ? event.error : null;
|
|
276
384
|
input.channel.providerEvent({
|
|
277
385
|
type: "error",
|
|
278
386
|
event_id: eventId,
|
|
279
|
-
message:
|
|
387
|
+
message:
|
|
388
|
+
stringValue(event.message) ?? stringValue(nested?.message) ?? "Realtime provider error",
|
|
280
389
|
});
|
|
281
390
|
}
|
|
282
391
|
}
|
|
@@ -335,6 +444,7 @@ class GatewayRealtimeDataChannel extends EventTarget {
|
|
|
335
444
|
function handleBridgeOutbound(
|
|
336
445
|
websocket: WebSocket,
|
|
337
446
|
messages: Array<Record<string, unknown>>,
|
|
447
|
+
dialect: RealtimeDialect,
|
|
338
448
|
): void {
|
|
339
449
|
const groups = new Map<
|
|
340
450
|
string,
|
|
@@ -361,16 +471,14 @@ function handleBridgeOutbound(
|
|
|
361
471
|
}
|
|
362
472
|
for (const group of groups.values()) {
|
|
363
473
|
if (group.type === "delegation.context.append" && group.id && group.channel === "speakable") {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
});
|
|
373
|
-
send(websocket, { type: "response-create" });
|
|
474
|
+
sendFunctionOutput(
|
|
475
|
+
websocket,
|
|
476
|
+
dialect,
|
|
477
|
+
group.id,
|
|
478
|
+
DELEGATION_TOOL,
|
|
479
|
+
JSON.stringify({ result: group.text }),
|
|
480
|
+
);
|
|
481
|
+
sendResponseCreate(websocket, dialect);
|
|
374
482
|
continue;
|
|
375
483
|
}
|
|
376
484
|
const wrapper =
|
|
@@ -379,18 +487,52 @@ function handleBridgeOutbound(
|
|
|
379
487
|
? "execution_progress"
|
|
380
488
|
: "execution_result"
|
|
381
489
|
: "session_update";
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
490
|
+
const text = `<${wrapper}>\n${group.text}\n</${wrapper}>`;
|
|
491
|
+
send(
|
|
492
|
+
websocket,
|
|
493
|
+
dialect === "xai"
|
|
494
|
+
? {
|
|
495
|
+
type: "conversation.item.create",
|
|
496
|
+
item: {
|
|
497
|
+
type: "message",
|
|
498
|
+
role: "user",
|
|
499
|
+
content: [{ type: "input_text", text }],
|
|
500
|
+
},
|
|
501
|
+
}
|
|
502
|
+
: {
|
|
503
|
+
type: "conversation-item-create",
|
|
504
|
+
item: { type: "text-message", role: "user", text },
|
|
505
|
+
},
|
|
506
|
+
);
|
|
507
|
+
if (group.channel === "speakable") sendResponseCreate(websocket, dialect);
|
|
391
508
|
}
|
|
392
509
|
}
|
|
393
510
|
|
|
511
|
+
function sendFunctionOutput(
|
|
512
|
+
websocket: WebSocket,
|
|
513
|
+
dialect: RealtimeDialect,
|
|
514
|
+
callId: string,
|
|
515
|
+
name: string | null,
|
|
516
|
+
output: string,
|
|
517
|
+
): void {
|
|
518
|
+
send(
|
|
519
|
+
websocket,
|
|
520
|
+
dialect === "xai"
|
|
521
|
+
? {
|
|
522
|
+
type: "conversation.item.create",
|
|
523
|
+
item: { type: "function_call_output", call_id: callId, output },
|
|
524
|
+
}
|
|
525
|
+
: {
|
|
526
|
+
type: "conversation-item-create",
|
|
527
|
+
item: { type: "function-call-output", callId, name, output },
|
|
528
|
+
},
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function sendResponseCreate(websocket: WebSocket, dialect: RealtimeDialect): void {
|
|
533
|
+
send(websocket, { type: dialect === "xai" ? "response.create" : "response-create" });
|
|
534
|
+
}
|
|
535
|
+
|
|
394
536
|
class GatewayRealtimeAudio {
|
|
395
537
|
private captureContext: AudioContext | null = null;
|
|
396
538
|
private captureSource: MediaStreamAudioSourceNode | null = null;
|
|
@@ -560,6 +702,7 @@ function providerEventId(event: Record<string, unknown>): string {
|
|
|
560
702
|
const raw = isRecord(event.raw) ? event.raw : null;
|
|
561
703
|
return (
|
|
562
704
|
stringValue(event.eventId) ??
|
|
705
|
+
stringValue(event.event_id) ??
|
|
563
706
|
stringValue(raw?.event_id) ??
|
|
564
707
|
stringValue(raw?.id) ??
|
|
565
708
|
crypto.randomUUID()
|
package/src/index.ts
CHANGED
|
@@ -96,7 +96,10 @@ export type {
|
|
|
96
96
|
CreateCodexRealtimeControllerOptions,
|
|
97
97
|
RealtimeControllerTransportStarter,
|
|
98
98
|
} from "./codex-realtime-controller";
|
|
99
|
-
export {
|
|
99
|
+
export {
|
|
100
|
+
createGatewayRealtimeTransportStarter,
|
|
101
|
+
createXaiSubscriptionRealtimeTransportStarter,
|
|
102
|
+
} from "./gateway-realtime-transport";
|
|
100
103
|
export { projectSessionRealtimeLifecycle } from "./codex-realtime-lifecycle";
|
|
101
104
|
export type { SessionRealtimeLifecycleProjection } from "./codex-realtime-lifecycle";
|
|
102
105
|
// Provider-neutral Browser/Computer resource client + bounded frame protocol.
|
|
@@ -130,6 +133,14 @@ export type {
|
|
|
130
133
|
} from "./stream";
|
|
131
134
|
export { streamWorkspaceControlEvents } from "./workspace-control-stream";
|
|
132
135
|
export type { WorkspaceControlStreamTransport } from "./workspace-control-stream";
|
|
136
|
+
export { streamWorkspaceInteractionRevisions } from "./interaction-revision-stream";
|
|
137
|
+
export type { WorkspaceInteractionRevisionStreamTransport } from "./interaction-revision-stream";
|
|
138
|
+
export { parseWorkspaceLiveEvent, streamWorkspaceLiveEvents } from "./workspace-live-stream";
|
|
139
|
+
export type {
|
|
140
|
+
WorkspaceLiveEvent,
|
|
141
|
+
WorkspaceLiveStreamOptions,
|
|
142
|
+
WorkspaceLiveStreamTransport,
|
|
143
|
+
} from "./workspace-live-stream";
|
|
133
144
|
export type {
|
|
134
145
|
CreateWorkspaceArtifactRequest,
|
|
135
146
|
PublishWorkspaceArtifactVersionRequest,
|
|
@@ -317,6 +328,8 @@ export type {
|
|
|
317
328
|
BillingEntitlementsResponse,
|
|
318
329
|
BillingMode,
|
|
319
330
|
BillingSummary,
|
|
331
|
+
ListManagedOrganizationMembershipsResponse,
|
|
332
|
+
ManagedOrganizationMembership,
|
|
320
333
|
BillingUsageResponse,
|
|
321
334
|
InsightsRange,
|
|
322
335
|
InsightsBillingPath,
|
|
@@ -394,6 +407,14 @@ export type {
|
|
|
394
407
|
CodexConnectionStatus,
|
|
395
408
|
CodexConnectStart,
|
|
396
409
|
CodexConnectPoll,
|
|
410
|
+
SuperGrokAccount,
|
|
411
|
+
SuperGrokAccountsResponse,
|
|
412
|
+
SuperGrokAccountScope,
|
|
413
|
+
SuperGrokAllocatorUpdate,
|
|
414
|
+
SuperGrokConnectionStatus,
|
|
415
|
+
SuperGrokConnectPoll,
|
|
416
|
+
SuperGrokConnectStart,
|
|
417
|
+
SuperGrokRotationSettings,
|
|
397
418
|
CodexFleetConfidence,
|
|
398
419
|
CodexFleetCacheState,
|
|
399
420
|
CodexFleetDecisionEventPayload,
|
|
@@ -449,7 +470,10 @@ export type {
|
|
|
449
470
|
CreateWorkspaceRequest,
|
|
450
471
|
DiscoverMcpCapabilitiesResponse,
|
|
451
472
|
InstallSkillRequest,
|
|
473
|
+
InstallLibrarySkillRequest,
|
|
452
474
|
InstalledSkill,
|
|
475
|
+
InstalledSkillSummary,
|
|
476
|
+
ListInstalledSkillsResponse,
|
|
453
477
|
Document,
|
|
454
478
|
DocumentAuthorityKind,
|
|
455
479
|
DocumentBase,
|
|
@@ -792,6 +816,10 @@ export type {
|
|
|
792
816
|
VariableSet,
|
|
793
817
|
VariableSetSecret,
|
|
794
818
|
VariableSetVariableMetadata,
|
|
819
|
+
Channel,
|
|
820
|
+
CreateChannelRequest,
|
|
821
|
+
UpdateChannelRequest,
|
|
822
|
+
UpdateSessionChannelRequest,
|
|
795
823
|
Rig,
|
|
796
824
|
RigVersion,
|
|
797
825
|
RigCheck,
|
|
@@ -811,30 +839,31 @@ export type {
|
|
|
811
839
|
PreviewSkillImportRequest,
|
|
812
840
|
ApiIntegrationAuthPreview,
|
|
813
841
|
ApiIntegrationInstallationSummary,
|
|
814
|
-
|
|
842
|
+
IntegrationDefinitionSummary,
|
|
815
843
|
ApiIntegrationPreview,
|
|
816
844
|
ApiIntegrationOAuthStartRequest,
|
|
817
845
|
ApiIntegrationProtocol,
|
|
818
|
-
|
|
846
|
+
IntegrationSource,
|
|
819
847
|
ApiIntegrationToolPreview,
|
|
820
848
|
ApiIntegrationUninstallPreview,
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
849
|
+
IntegrationFacetBindingSummary,
|
|
850
|
+
IntegrationFacetDefinitionSummary,
|
|
851
|
+
IntegrationFacetKind,
|
|
852
|
+
IntegrationFacetMutationResult,
|
|
853
|
+
IntegrationFacetRemovalResult,
|
|
854
|
+
IntegrationFacetStatus,
|
|
855
|
+
IntegrationInstanceFacetsResponse,
|
|
828
856
|
InstallApiIntegrationRequest,
|
|
829
857
|
InstalledApiIntegration,
|
|
830
|
-
|
|
858
|
+
ListIntegrationDefinitionsResponse,
|
|
831
859
|
ListApiIntegrationsResponse,
|
|
832
860
|
PreviewApiIntegrationRequest,
|
|
833
|
-
|
|
834
|
-
|
|
861
|
+
MutateIntegrationFacetRequest,
|
|
862
|
+
UpsertIntegrationFacetRequest,
|
|
835
863
|
SkillImportFileSummary,
|
|
836
864
|
SkillImportPreview,
|
|
837
865
|
SkillImportSource,
|
|
866
|
+
SkillInstallationSource,
|
|
838
867
|
SkillUninstallPreview,
|
|
839
868
|
UninstallSkillRequest,
|
|
840
869
|
UninstallSkillResult,
|