@tanstack/ai-gemini 0.20.1 → 0.22.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 +15 -1
- package/dist/esm/adapters/audio.js +113 -61
- package/dist/esm/adapters/audio.js.map +1 -1
- package/dist/esm/adapters/embedding.d.ts +77 -0
- package/dist/esm/adapters/embedding.js +119 -0
- package/dist/esm/adapters/embedding.js.map +1 -0
- package/dist/esm/adapters/image.js +224 -225
- package/dist/esm/adapters/image.js.map +1 -1
- package/dist/esm/adapters/summarize.js +33 -12
- package/dist/esm/adapters/summarize.js.map +1 -1
- package/dist/esm/adapters/text.js +574 -650
- package/dist/esm/adapters/text.js.map +1 -1
- package/dist/esm/adapters/tts.js +197 -178
- package/dist/esm/adapters/tts.js.map +1 -1
- package/dist/esm/adapters/video.js +456 -409
- package/dist/esm/adapters/video.js.map +1 -1
- package/dist/esm/embedding/embedding-provider-options.d.ts +20 -0
- package/dist/esm/experimental/index.js +1 -6
- package/dist/esm/experimental/text-interactions/adapter.js +877 -1014
- package/dist/esm/experimental/text-interactions/adapter.js.map +1 -1
- package/dist/esm/image/image-provider-options.js +74 -54
- package/dist/esm/image/image-provider-options.js.map +1 -1
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.js +5 -36
- package/dist/esm/model-meta.d.ts +72 -5
- package/dist/esm/model-meta.js +737 -129
- package/dist/esm/model-meta.js.map +1 -1
- package/dist/esm/realtime/adapter.js +242 -228
- package/dist/esm/realtime/adapter.js.map +1 -1
- package/dist/esm/realtime/client.js +314 -381
- package/dist/esm/realtime/client.js.map +1 -1
- package/dist/esm/realtime/index.js +3 -0
- package/dist/esm/realtime/token.js +50 -36
- package/dist/esm/realtime/token.js.map +1 -1
- package/dist/esm/realtime/utils.js +202 -245
- package/dist/esm/realtime/utils.js.map +1 -1
- package/dist/esm/tools/code-execution-tool.js +11 -13
- package/dist/esm/tools/code-execution-tool.js.map +1 -1
- package/dist/esm/tools/computer-use-tool.js +18 -28
- package/dist/esm/tools/computer-use-tool.js.map +1 -1
- package/dist/esm/tools/file-search-tool.js +11 -14
- package/dist/esm/tools/file-search-tool.js.map +1 -1
- package/dist/esm/tools/function-declaration-tool.js +11 -25
- package/dist/esm/tools/function-declaration-tool.js.map +1 -1
- package/dist/esm/tools/google-maps-tool.js +11 -14
- package/dist/esm/tools/google-maps-tool.js.map +1 -1
- package/dist/esm/tools/google-search-retriveal-tool.js +11 -14
- package/dist/esm/tools/google-search-retriveal-tool.js.map +1 -1
- package/dist/esm/tools/google-search-tool.js +11 -14
- package/dist/esm/tools/google-search-tool.js.map +1 -1
- package/dist/esm/tools/index.js +2 -13
- package/dist/esm/tools/tool-converter.js +64 -57
- package/dist/esm/tools/tool-converter.js.map +1 -1
- package/dist/esm/tools/url-context-tool.js +11 -13
- package/dist/esm/tools/url-context-tool.js.map +1 -1
- package/dist/esm/usage.js +81 -87
- package/dist/esm/usage.js.map +1 -1
- package/dist/esm/utils/client.js +31 -24
- package/dist/esm/utils/client.js.map +1 -1
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/video/video-provider-options.js +73 -20
- package/dist/esm/video/video-provider-options.js.map +1 -1
- package/package.json +7 -7
- package/src/adapters/embedding.ts +173 -0
- package/src/embedding/embedding-provider-options.ts +29 -0
- package/src/index.ts +13 -0
- package/src/model-meta.ts +143 -10
- package/dist/esm/experimental/index.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/tools/index.js.map +0 -1
|
@@ -1,233 +1,247 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AudioPlayer, base64ToArrayBuffer, AudioStreamer } from "./utils.js";
|
|
1
|
+
import { AudioPlayer, AudioStreamer, base64ToArrayBuffer } from "./utils.js";
|
|
3
2
|
import { GeminiLiveClient } from "./client.js";
|
|
3
|
+
import { createRealtimeEventEmitter } from "@tanstack/ai";
|
|
4
|
+
//#region src/realtime/adapter.ts
|
|
5
|
+
/**
|
|
6
|
+
* Creates a Gemini realtime adapter for client-side use.
|
|
7
|
+
*
|
|
8
|
+
* @param options - Optional configuration
|
|
9
|
+
* @returns A RealtimeAdapter for use with RealtimeClient
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { RealtimeClient } from '@tanstack/ai-client'
|
|
14
|
+
* import { geminiRealtime } from '@tanstack/ai-gemini'
|
|
15
|
+
*
|
|
16
|
+
* const client = new RealtimeClient({
|
|
17
|
+
* getToken: () => fetch('/api/realtime-token').then(r => r.json()),
|
|
18
|
+
* adapter: geminiRealtime(),
|
|
19
|
+
* onGoAway: () => client.updateSession({ ... }) // Resume session with new config (available only for Gemini Live adapter)
|
|
20
|
+
* })
|
|
21
|
+
*
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
4
24
|
function geminiRealtime(options = {}) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
25
|
+
return {
|
|
26
|
+
provider: "gemini",
|
|
27
|
+
connect(token, clientTools) {
|
|
28
|
+
return createWebSocketConnection(token, options.model, clientTools);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
11
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a WebSocket connection to Gemini's realtime API
|
|
34
|
+
*/
|
|
12
35
|
async function createWebSocketConnection(token, model = "gemini-3.1-flash-live-preview", tools) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return audioStreamer.inputSampleRate;
|
|
221
|
-
},
|
|
222
|
-
get outputSampleRate() {
|
|
223
|
-
return audioPlayer.outputSampleRate;
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
return connection;
|
|
36
|
+
const { emit, on: realtimeEventEmitterOn } = createRealtimeEventEmitter();
|
|
37
|
+
let currentMode = "idle";
|
|
38
|
+
let currentMessageId = null;
|
|
39
|
+
let messageIdCounter = 0;
|
|
40
|
+
function generateMessageId() {
|
|
41
|
+
return `gemini-msg-${Date.now()}-${++messageIdCounter}`;
|
|
42
|
+
}
|
|
43
|
+
const client = new GeminiLiveClient(token.token, model, tools);
|
|
44
|
+
let message = {
|
|
45
|
+
id: "",
|
|
46
|
+
role: "assistant",
|
|
47
|
+
timestamp: 0,
|
|
48
|
+
parts: []
|
|
49
|
+
};
|
|
50
|
+
let pendingAssistantResponse = "";
|
|
51
|
+
client.onClose = () => {
|
|
52
|
+
emit("status_change", { status: "idle" });
|
|
53
|
+
emit("mode_change", { mode: "idle" });
|
|
54
|
+
};
|
|
55
|
+
client.onError = (error) => {
|
|
56
|
+
emit("error", { error });
|
|
57
|
+
emit("status_change", { status: "error" });
|
|
58
|
+
emit("mode_change", { mode: "idle" });
|
|
59
|
+
};
|
|
60
|
+
client.onReceiveResponse = (response) => {
|
|
61
|
+
switch (response.type) {
|
|
62
|
+
case "text":
|
|
63
|
+
message.parts.push({
|
|
64
|
+
type: "text",
|
|
65
|
+
content: response.data
|
|
66
|
+
});
|
|
67
|
+
break;
|
|
68
|
+
case "audio": {
|
|
69
|
+
const pcm = base64ToArrayBuffer(response.data.audioData);
|
|
70
|
+
message.parts.push({
|
|
71
|
+
type: "audio",
|
|
72
|
+
transcript: response.data.transcript,
|
|
73
|
+
audioData: pcm
|
|
74
|
+
});
|
|
75
|
+
if (currentMode !== "speaking") {
|
|
76
|
+
currentMode = "speaking";
|
|
77
|
+
emit("mode_change", { mode: "speaking" });
|
|
78
|
+
}
|
|
79
|
+
audioPlayer.play(pcm).catch((error) => emit("error", { error }));
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
case "go_away":
|
|
83
|
+
emit("go_away", { timeLeft: response.data.timeLeft });
|
|
84
|
+
break;
|
|
85
|
+
case "usage_metadata":
|
|
86
|
+
emit("usage", {
|
|
87
|
+
completionTokens: response.data.responseTokenCount ?? 0,
|
|
88
|
+
promptTokens: response.data.promptTokenCount ?? 0,
|
|
89
|
+
totalTokens: response.data.totalTokenCount ?? 0
|
|
90
|
+
});
|
|
91
|
+
break;
|
|
92
|
+
case "input_transcription":
|
|
93
|
+
if (response.data.finished && currentMode !== "thinking") {
|
|
94
|
+
currentMode = "thinking";
|
|
95
|
+
emit("mode_change", { mode: "thinking" });
|
|
96
|
+
}
|
|
97
|
+
emit("transcript", {
|
|
98
|
+
isFinal: response.data.finished,
|
|
99
|
+
transcript: response.data.text,
|
|
100
|
+
role: "user"
|
|
101
|
+
});
|
|
102
|
+
break;
|
|
103
|
+
case "output_transcription":
|
|
104
|
+
pendingAssistantResponse += response.data.text;
|
|
105
|
+
emit("transcript", {
|
|
106
|
+
isFinal: response.data.finished,
|
|
107
|
+
transcript: pendingAssistantResponse,
|
|
108
|
+
role: "assistant"
|
|
109
|
+
});
|
|
110
|
+
break;
|
|
111
|
+
case "interrupted":
|
|
112
|
+
audioPlayer.interrupt();
|
|
113
|
+
currentMode = "listening";
|
|
114
|
+
emit("mode_change", { mode: "listening" });
|
|
115
|
+
emit("interrupted", { messageId: currentMessageId ?? void 0 });
|
|
116
|
+
break;
|
|
117
|
+
case "tool_call":
|
|
118
|
+
for (const tool of response.data.functionCalls || []) if (tool.id && tool.name) emit("tool_call", {
|
|
119
|
+
toolCallId: tool.id,
|
|
120
|
+
input: tool.args,
|
|
121
|
+
toolName: tool.name
|
|
122
|
+
});
|
|
123
|
+
break;
|
|
124
|
+
case "turn_complete":
|
|
125
|
+
currentMessageId = generateMessageId();
|
|
126
|
+
message.id = currentMessageId;
|
|
127
|
+
message.timestamp = Date.now();
|
|
128
|
+
message.parts.push({
|
|
129
|
+
type: "text",
|
|
130
|
+
content: pendingAssistantResponse
|
|
131
|
+
});
|
|
132
|
+
emit("message_complete", { message });
|
|
133
|
+
pendingAssistantResponse = "";
|
|
134
|
+
message = {
|
|
135
|
+
id: "",
|
|
136
|
+
role: "assistant",
|
|
137
|
+
timestamp: 0,
|
|
138
|
+
parts: []
|
|
139
|
+
};
|
|
140
|
+
currentMode = "listening";
|
|
141
|
+
emit("mode_change", { mode: "listening" });
|
|
142
|
+
break;
|
|
143
|
+
case "setup_complete":
|
|
144
|
+
emit("status_change", { status: "connected" });
|
|
145
|
+
break;
|
|
146
|
+
case "error":
|
|
147
|
+
emit("error", { error: new Error(response.data) });
|
|
148
|
+
break;
|
|
149
|
+
case "thought":
|
|
150
|
+
case "session_resumption_update": break;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
await client.connect();
|
|
154
|
+
const audioStreamer = new AudioStreamer(client);
|
|
155
|
+
const audioPlayer = new AudioPlayer();
|
|
156
|
+
try {
|
|
157
|
+
await audioPlayer.init();
|
|
158
|
+
await audioStreamer.start();
|
|
159
|
+
} catch (error) {
|
|
160
|
+
audioStreamer.stop();
|
|
161
|
+
audioPlayer.destroy();
|
|
162
|
+
client.disconnect();
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
async disconnect() {
|
|
167
|
+
audioStreamer.stop();
|
|
168
|
+
audioPlayer.destroy();
|
|
169
|
+
client.disconnect();
|
|
170
|
+
currentMode = "idle";
|
|
171
|
+
emit("status_change", { status: "idle" });
|
|
172
|
+
},
|
|
173
|
+
async startAudioCapture() {
|
|
174
|
+
audioStreamer.startAudioCapture();
|
|
175
|
+
currentMode = "listening";
|
|
176
|
+
emit("mode_change", { mode: "listening" });
|
|
177
|
+
},
|
|
178
|
+
stopAudioCapture() {
|
|
179
|
+
audioStreamer.stopAudioCapture();
|
|
180
|
+
currentMode = "idle";
|
|
181
|
+
emit("mode_change", { mode: "idle" });
|
|
182
|
+
},
|
|
183
|
+
sendText(text) {
|
|
184
|
+
client.sendTextMessage(text);
|
|
185
|
+
currentMode = "thinking";
|
|
186
|
+
emit("mode_change", { mode: "thinking" });
|
|
187
|
+
},
|
|
188
|
+
sendImage(imageData, mimeType) {
|
|
189
|
+
client.sendImageMessage(imageData, mimeType);
|
|
190
|
+
currentMode = "thinking";
|
|
191
|
+
emit("mode_change", { mode: "thinking" });
|
|
192
|
+
},
|
|
193
|
+
sendToolResult(callId, result) {
|
|
194
|
+
client.sendToolResponse([{
|
|
195
|
+
id: callId,
|
|
196
|
+
response: { result }
|
|
197
|
+
}]);
|
|
198
|
+
},
|
|
199
|
+
updateSession(config) {
|
|
200
|
+
client.updateSession(config).catch((error) => emit("error", { error }));
|
|
201
|
+
emit("status_change", { status: "reconnecting" });
|
|
202
|
+
},
|
|
203
|
+
updateToken(newToken) {
|
|
204
|
+
client.updateToken(newToken);
|
|
205
|
+
emit("status_change", { status: "reconnecting" });
|
|
206
|
+
},
|
|
207
|
+
interrupt() {
|
|
208
|
+
audioPlayer.interrupt();
|
|
209
|
+
currentMode = "listening";
|
|
210
|
+
emit("mode_change", { mode: "listening" });
|
|
211
|
+
emit("interrupted", { messageId: currentMessageId ?? void 0 });
|
|
212
|
+
},
|
|
213
|
+
on: realtimeEventEmitterOn,
|
|
214
|
+
getAudioVisualization() {
|
|
215
|
+
return {
|
|
216
|
+
get inputLevel() {
|
|
217
|
+
return audioStreamer.inputLevel;
|
|
218
|
+
},
|
|
219
|
+
get outputLevel() {
|
|
220
|
+
return audioPlayer.outputLevel;
|
|
221
|
+
},
|
|
222
|
+
getInputFrequencyData() {
|
|
223
|
+
return audioStreamer.inputFrequencyData;
|
|
224
|
+
},
|
|
225
|
+
getOutputFrequencyData() {
|
|
226
|
+
return audioPlayer.outputFrequencyData;
|
|
227
|
+
},
|
|
228
|
+
getInputTimeDomainData() {
|
|
229
|
+
return audioStreamer.inputTimeDomainData;
|
|
230
|
+
},
|
|
231
|
+
getOutputTimeDomainData() {
|
|
232
|
+
return audioPlayer.outputTimeDomainData;
|
|
233
|
+
},
|
|
234
|
+
get inputSampleRate() {
|
|
235
|
+
return audioStreamer.inputSampleRate;
|
|
236
|
+
},
|
|
237
|
+
get outputSampleRate() {
|
|
238
|
+
return audioPlayer.outputSampleRate;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
};
|
|
229
243
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
//# sourceMappingURL=adapter.js.map
|
|
244
|
+
//#endregion
|
|
245
|
+
export { geminiRealtime };
|
|
246
|
+
|
|
247
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sources":["../../../src/realtime/adapter.ts"],"sourcesContent":["import { createRealtimeEventEmitter } from '@tanstack/ai'\nimport { AudioPlayer, AudioStreamer, base64ToArrayBuffer } from './utils'\nimport { GeminiLiveClient } from './client'\nimport type { LiveResponse } from './client'\nimport type {\n AnyClientTool,\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeMessage,\n RealtimeMode,\n RealtimeToken,\n} from '@tanstack/ai'\nimport type { GeminiRealtimeModel, GeminiRealtimeOptions } from './types'\n\n/**\n * Creates a Gemini realtime adapter for client-side use.\n *\n * @param options - Optional configuration\n * @returns A RealtimeAdapter for use with RealtimeClient\n *\n * @example\n * ```typescript\n * import { RealtimeClient } from '@tanstack/ai-client'\n * import { geminiRealtime } from '@tanstack/ai-gemini'\n *\n * const client = new RealtimeClient({\n * getToken: () => fetch('/api/realtime-token').then(r => r.json()),\n * adapter: geminiRealtime(),\n * onGoAway: () => client.updateSession({ ... }) // Resume session with new config (available only for Gemini Live adapter)\n * })\n *\n * ```\n */\nexport function geminiRealtime(\n options: GeminiRealtimeOptions = {},\n): RealtimeAdapter {\n return {\n provider: 'gemini',\n\n connect(\n token: RealtimeToken,\n clientTools?: ReadonlyArray<AnyClientTool>,\n ): Promise<RealtimeConnection> {\n return createWebSocketConnection(token, options.model, clientTools)\n },\n }\n}\n\n/**\n * Creates a WebSocket connection to Gemini's realtime API\n */\nasync function createWebSocketConnection(\n token: RealtimeToken,\n model: GeminiRealtimeModel = 'gemini-3.1-flash-live-preview',\n tools?: ReadonlyArray<AnyClientTool>,\n): Promise<RealtimeConnection> {\n const { emit, on: realtimeEventEmitterOn } = createRealtimeEventEmitter()\n\n // Current state\n let currentMode: RealtimeMode = 'idle'\n let currentMessageId: string | null = null\n let messageIdCounter = 0\n\n function generateMessageId(): string {\n return `gemini-msg-${Date.now()}-${++messageIdCounter}`\n }\n\n const client = new GeminiLiveClient(token.token, model, tools)\n\n let message: RealtimeMessage = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n\n let pendingAssistantResponse = ''\n\n client.onClose = () => {\n emit('status_change', { status: 'idle' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onError = (error) => {\n emit('error', { error })\n emit('status_change', { status: 'error' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onReceiveResponse = (response: LiveResponse) => {\n switch (response.type) {\n case 'text':\n message.parts.push({\n type: 'text',\n content: response.data,\n })\n break\n case 'audio': {\n // Decode once, then reuse for both the stored message part and playback.\n const pcm = base64ToArrayBuffer(response.data.audioData)\n message.parts.push({\n type: 'audio',\n transcript: response.data.transcript,\n audioData: pcm,\n })\n if (currentMode !== 'speaking') {\n currentMode = 'speaking'\n emit('mode_change', { mode: 'speaking' })\n }\n audioPlayer.play(pcm).catch((error) => emit('error', { error }))\n break\n }\n case 'go_away':\n emit('go_away', { timeLeft: response.data.timeLeft })\n break\n case 'usage_metadata':\n emit('usage', {\n completionTokens: response.data.responseTokenCount ?? 0,\n promptTokens: response.data.promptTokenCount ?? 0,\n totalTokens: response.data.totalTokenCount ?? 0,\n })\n break\n case 'input_transcription':\n if (response.data.finished && currentMode !== 'thinking') {\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n }\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: response.data.text,\n role: 'user',\n })\n break\n case 'output_transcription':\n pendingAssistantResponse += response.data.text\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: pendingAssistantResponse,\n role: 'assistant',\n })\n break\n case 'interrupted':\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n break\n case 'tool_call':\n for (const tool of response.data.functionCalls || []) {\n if (tool.id && tool.name) {\n emit('tool_call', {\n toolCallId: tool.id,\n input: tool.args,\n toolName: tool.name,\n })\n }\n }\n break\n case 'turn_complete':\n currentMessageId = generateMessageId()\n message.id = currentMessageId\n message.timestamp = Date.now()\n message.parts.push({\n type: 'text',\n content: pendingAssistantResponse,\n })\n emit('message_complete', { message })\n\n pendingAssistantResponse = ''\n message = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n break\n case 'setup_complete':\n emit('status_change', { status: 'connected' })\n break\n case 'error':\n emit('error', {\n error: new Error(response.data),\n })\n break\n case 'thought':\n case 'session_resumption_update':\n // Handled internally by GeminiLiveClient; not surfaced to the client.\n break\n }\n }\n\n await client.connect()\n\n const audioStreamer = new AudioStreamer(client)\n const audioPlayer = new AudioPlayer()\n try {\n await audioPlayer.init()\n await audioStreamer.start()\n } catch (error) {\n // Tear down the socket + audio graph if mic/worklet setup fails (e.g. the\n // user denied microphone access) rather than leaking an open connection.\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n throw error\n }\n\n const connection: RealtimeConnection = {\n async disconnect() {\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n currentMode = 'idle'\n emit('status_change', { status: 'idle' })\n },\n\n async startAudioCapture() {\n // Audio capture is established during connection setup\n audioStreamer.startAudioCapture()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n },\n\n stopAudioCapture() {\n audioStreamer.stopAudioCapture()\n currentMode = 'idle'\n emit('mode_change', { mode: 'idle' })\n },\n\n sendText(text: string) {\n client.sendTextMessage(text)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendImage(imageData: string, mimeType: string) {\n client.sendImageMessage(imageData, mimeType)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendToolResult(callId: string, result: string) {\n client.sendToolResponse([\n {\n id: callId,\n response: {\n result,\n },\n },\n ])\n },\n\n updateSession(config) {\n client.updateSession(config).catch((error) => emit('error', { error }))\n emit('status_change', { status: 'reconnecting' })\n },\n\n updateToken(newToken) {\n client.updateToken(newToken)\n emit('status_change', { status: 'reconnecting' })\n },\n\n interrupt() {\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n },\n on: realtimeEventEmitterOn,\n getAudioVisualization(): AudioVisualization {\n return {\n get inputLevel() {\n return audioStreamer.inputLevel\n },\n\n get outputLevel() {\n return audioPlayer.outputLevel\n },\n\n getInputFrequencyData() {\n return audioStreamer.inputFrequencyData\n },\n\n getOutputFrequencyData() {\n return audioPlayer.outputFrequencyData\n },\n\n getInputTimeDomainData() {\n return audioStreamer.inputTimeDomainData\n },\n\n getOutputTimeDomainData() {\n return audioPlayer.outputTimeDomainData\n },\n\n get inputSampleRate() {\n return audioStreamer.inputSampleRate\n },\n\n get outputSampleRate() {\n return audioPlayer.outputSampleRate\n },\n }\n },\n }\n\n return connection\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../src/realtime/adapter.ts"],"sourcesContent":["import { createRealtimeEventEmitter } from '@tanstack/ai'\nimport { AudioPlayer, AudioStreamer, base64ToArrayBuffer } from './utils'\nimport { GeminiLiveClient } from './client'\nimport type { LiveResponse } from './client'\nimport type {\n AnyClientTool,\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeMessage,\n RealtimeMode,\n RealtimeToken,\n} from '@tanstack/ai'\nimport type { GeminiRealtimeModel, GeminiRealtimeOptions } from './types'\n\n/**\n * Creates a Gemini realtime adapter for client-side use.\n *\n * @param options - Optional configuration\n * @returns A RealtimeAdapter for use with RealtimeClient\n *\n * @example\n * ```typescript\n * import { RealtimeClient } from '@tanstack/ai-client'\n * import { geminiRealtime } from '@tanstack/ai-gemini'\n *\n * const client = new RealtimeClient({\n * getToken: () => fetch('/api/realtime-token').then(r => r.json()),\n * adapter: geminiRealtime(),\n * onGoAway: () => client.updateSession({ ... }) // Resume session with new config (available only for Gemini Live adapter)\n * })\n *\n * ```\n */\nexport function geminiRealtime(\n options: GeminiRealtimeOptions = {},\n): RealtimeAdapter {\n return {\n provider: 'gemini',\n\n connect(\n token: RealtimeToken,\n clientTools?: ReadonlyArray<AnyClientTool>,\n ): Promise<RealtimeConnection> {\n return createWebSocketConnection(token, options.model, clientTools)\n },\n }\n}\n\n/**\n * Creates a WebSocket connection to Gemini's realtime API\n */\nasync function createWebSocketConnection(\n token: RealtimeToken,\n model: GeminiRealtimeModel = 'gemini-3.1-flash-live-preview',\n tools?: ReadonlyArray<AnyClientTool>,\n): Promise<RealtimeConnection> {\n const { emit, on: realtimeEventEmitterOn } = createRealtimeEventEmitter()\n\n // Current state\n let currentMode: RealtimeMode = 'idle'\n let currentMessageId: string | null = null\n let messageIdCounter = 0\n\n function generateMessageId(): string {\n return `gemini-msg-${Date.now()}-${++messageIdCounter}`\n }\n\n const client = new GeminiLiveClient(token.token, model, tools)\n\n let message: RealtimeMessage = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n\n let pendingAssistantResponse = ''\n\n client.onClose = () => {\n emit('status_change', { status: 'idle' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onError = (error) => {\n emit('error', { error })\n emit('status_change', { status: 'error' })\n emit('mode_change', { mode: 'idle' })\n }\n\n client.onReceiveResponse = (response: LiveResponse) => {\n switch (response.type) {\n case 'text':\n message.parts.push({\n type: 'text',\n content: response.data,\n })\n break\n case 'audio': {\n // Decode once, then reuse for both the stored message part and playback.\n const pcm = base64ToArrayBuffer(response.data.audioData)\n message.parts.push({\n type: 'audio',\n transcript: response.data.transcript,\n audioData: pcm,\n })\n if (currentMode !== 'speaking') {\n currentMode = 'speaking'\n emit('mode_change', { mode: 'speaking' })\n }\n audioPlayer.play(pcm).catch((error) => emit('error', { error }))\n break\n }\n case 'go_away':\n emit('go_away', { timeLeft: response.data.timeLeft })\n break\n case 'usage_metadata':\n emit('usage', {\n completionTokens: response.data.responseTokenCount ?? 0,\n promptTokens: response.data.promptTokenCount ?? 0,\n totalTokens: response.data.totalTokenCount ?? 0,\n })\n break\n case 'input_transcription':\n if (response.data.finished && currentMode !== 'thinking') {\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n }\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: response.data.text,\n role: 'user',\n })\n break\n case 'output_transcription':\n pendingAssistantResponse += response.data.text\n emit('transcript', {\n isFinal: response.data.finished,\n transcript: pendingAssistantResponse,\n role: 'assistant',\n })\n break\n case 'interrupted':\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n break\n case 'tool_call':\n for (const tool of response.data.functionCalls || []) {\n if (tool.id && tool.name) {\n emit('tool_call', {\n toolCallId: tool.id,\n input: tool.args,\n toolName: tool.name,\n })\n }\n }\n break\n case 'turn_complete':\n currentMessageId = generateMessageId()\n message.id = currentMessageId\n message.timestamp = Date.now()\n message.parts.push({\n type: 'text',\n content: pendingAssistantResponse,\n })\n emit('message_complete', { message })\n\n pendingAssistantResponse = ''\n message = {\n id: '',\n role: 'assistant',\n timestamp: 0,\n parts: [],\n }\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n break\n case 'setup_complete':\n emit('status_change', { status: 'connected' })\n break\n case 'error':\n emit('error', {\n error: new Error(response.data),\n })\n break\n case 'thought':\n case 'session_resumption_update':\n // Handled internally by GeminiLiveClient; not surfaced to the client.\n break\n }\n }\n\n await client.connect()\n\n const audioStreamer = new AudioStreamer(client)\n const audioPlayer = new AudioPlayer()\n try {\n await audioPlayer.init()\n await audioStreamer.start()\n } catch (error) {\n // Tear down the socket + audio graph if mic/worklet setup fails (e.g. the\n // user denied microphone access) rather than leaking an open connection.\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n throw error\n }\n\n const connection: RealtimeConnection = {\n async disconnect() {\n audioStreamer.stop()\n audioPlayer.destroy()\n client.disconnect()\n currentMode = 'idle'\n emit('status_change', { status: 'idle' })\n },\n\n async startAudioCapture() {\n // Audio capture is established during connection setup\n audioStreamer.startAudioCapture()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n },\n\n stopAudioCapture() {\n audioStreamer.stopAudioCapture()\n currentMode = 'idle'\n emit('mode_change', { mode: 'idle' })\n },\n\n sendText(text: string) {\n client.sendTextMessage(text)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendImage(imageData: string, mimeType: string) {\n client.sendImageMessage(imageData, mimeType)\n currentMode = 'thinking'\n emit('mode_change', { mode: 'thinking' })\n },\n\n sendToolResult(callId: string, result: string) {\n client.sendToolResponse([\n {\n id: callId,\n response: {\n result,\n },\n },\n ])\n },\n\n updateSession(config) {\n client.updateSession(config).catch((error) => emit('error', { error }))\n emit('status_change', { status: 'reconnecting' })\n },\n\n updateToken(newToken) {\n client.updateToken(newToken)\n emit('status_change', { status: 'reconnecting' })\n },\n\n interrupt() {\n audioPlayer.interrupt()\n currentMode = 'listening'\n emit('mode_change', { mode: 'listening' })\n emit('interrupted', { messageId: currentMessageId ?? undefined })\n },\n on: realtimeEventEmitterOn,\n getAudioVisualization(): AudioVisualization {\n return {\n get inputLevel() {\n return audioStreamer.inputLevel\n },\n\n get outputLevel() {\n return audioPlayer.outputLevel\n },\n\n getInputFrequencyData() {\n return audioStreamer.inputFrequencyData\n },\n\n getOutputFrequencyData() {\n return audioPlayer.outputFrequencyData\n },\n\n getInputTimeDomainData() {\n return audioStreamer.inputTimeDomainData\n },\n\n getOutputTimeDomainData() {\n return audioPlayer.outputTimeDomainData\n },\n\n get inputSampleRate() {\n return audioStreamer.inputSampleRate\n },\n\n get outputSampleRate() {\n return audioPlayer.outputSampleRate\n },\n }\n },\n }\n\n return connection\n}\n"],"mappings":"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"}
|