@tanstack/ai-gemini 0.20.0 → 0.21.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.
Files changed (62) hide show
  1. package/README.md +15 -1
  2. package/dist/esm/adapters/audio.js +113 -61
  3. package/dist/esm/adapters/audio.js.map +1 -1
  4. package/dist/esm/adapters/image.js +224 -225
  5. package/dist/esm/adapters/image.js.map +1 -1
  6. package/dist/esm/adapters/summarize.js +33 -12
  7. package/dist/esm/adapters/summarize.js.map +1 -1
  8. package/dist/esm/adapters/text.js +574 -650
  9. package/dist/esm/adapters/text.js.map +1 -1
  10. package/dist/esm/adapters/tts.js +197 -178
  11. package/dist/esm/adapters/tts.js.map +1 -1
  12. package/dist/esm/adapters/video.js +456 -409
  13. package/dist/esm/adapters/video.js.map +1 -1
  14. package/dist/esm/experimental/index.js +1 -6
  15. package/dist/esm/experimental/text-interactions/adapter.js +877 -1014
  16. package/dist/esm/experimental/text-interactions/adapter.js.map +1 -1
  17. package/dist/esm/image/image-provider-options.js +74 -54
  18. package/dist/esm/image/image-provider-options.js.map +1 -1
  19. package/dist/esm/index.js +4 -36
  20. package/dist/esm/model-meta.d.ts +53 -5
  21. package/dist/esm/model-meta.js +733 -129
  22. package/dist/esm/model-meta.js.map +1 -1
  23. package/dist/esm/realtime/adapter.js +242 -228
  24. package/dist/esm/realtime/adapter.js.map +1 -1
  25. package/dist/esm/realtime/client.js +314 -381
  26. package/dist/esm/realtime/client.js.map +1 -1
  27. package/dist/esm/realtime/index.js +3 -0
  28. package/dist/esm/realtime/token.js +50 -36
  29. package/dist/esm/realtime/token.js.map +1 -1
  30. package/dist/esm/realtime/utils.js +202 -245
  31. package/dist/esm/realtime/utils.js.map +1 -1
  32. package/dist/esm/tools/code-execution-tool.js +11 -13
  33. package/dist/esm/tools/code-execution-tool.js.map +1 -1
  34. package/dist/esm/tools/computer-use-tool.js +18 -28
  35. package/dist/esm/tools/computer-use-tool.js.map +1 -1
  36. package/dist/esm/tools/file-search-tool.js +11 -14
  37. package/dist/esm/tools/file-search-tool.js.map +1 -1
  38. package/dist/esm/tools/function-declaration-tool.js +11 -25
  39. package/dist/esm/tools/function-declaration-tool.js.map +1 -1
  40. package/dist/esm/tools/google-maps-tool.js +11 -14
  41. package/dist/esm/tools/google-maps-tool.js.map +1 -1
  42. package/dist/esm/tools/google-search-retriveal-tool.js +11 -14
  43. package/dist/esm/tools/google-search-retriveal-tool.js.map +1 -1
  44. package/dist/esm/tools/google-search-tool.js +11 -14
  45. package/dist/esm/tools/google-search-tool.js.map +1 -1
  46. package/dist/esm/tools/index.js +2 -13
  47. package/dist/esm/tools/tool-converter.js +64 -57
  48. package/dist/esm/tools/tool-converter.js.map +1 -1
  49. package/dist/esm/tools/url-context-tool.js +11 -13
  50. package/dist/esm/tools/url-context-tool.js.map +1 -1
  51. package/dist/esm/usage.js +81 -87
  52. package/dist/esm/usage.js.map +1 -1
  53. package/dist/esm/utils/client.js +31 -24
  54. package/dist/esm/utils/client.js.map +1 -1
  55. package/dist/esm/utils/index.js +2 -0
  56. package/dist/esm/video/video-provider-options.js +73 -20
  57. package/dist/esm/video/video-provider-options.js.map +1 -1
  58. package/package.json +7 -7
  59. package/src/model-meta.ts +120 -10
  60. package/dist/esm/experimental/index.js.map +0 -1
  61. package/dist/esm/index.js.map +0 -1
  62. package/dist/esm/tools/index.js.map +0 -1
@@ -1,4 +1,8 @@
1
- const captureWorkletCode = `
1
+ //#region src/realtime/utils.ts
2
+ /**
3
+ * Audio Worklet Processor for capturing and processing audio
4
+ */
5
+ var captureWorkletCode = `
2
6
  class AudioCaptureProcessor extends AudioWorkletProcessor {
3
7
  constructor() {
4
8
  super();
@@ -38,7 +42,12 @@ class AudioCaptureProcessor extends AudioWorkletProcessor {
38
42
 
39
43
  // Register the processor
40
44
  registerProcessor("audio-capture-processor", AudioCaptureProcessor);`;
41
- const playbackWorkletCode = `
45
+ /**
46
+ * Audio Playback Worklet Processor for playing PCM audio.
47
+ * Uses an offset tracker instead of slice() to avoid allocations
48
+ * on the real-time audio thread.
49
+ */
50
+ var playbackWorkletCode = `
42
51
  class PCMProcessor extends AudioWorkletProcessor {
43
52
  constructor() {
44
53
  super();
@@ -101,250 +110,198 @@ class PCMProcessor extends AudioWorkletProcessor {
101
110
 
102
111
  registerProcessor("pcm-processor", PCMProcessor);`;
103
112
  function calculateLevel(analyser) {
104
- const data = new Uint8Array(analyser.fftSize);
105
- analyser.getByteTimeDomainData(data);
106
- let maxDeviation = 0;
107
- for (const sample of data) {
108
- const deviation = Math.abs(sample - 128);
109
- if (deviation > maxDeviation) {
110
- maxDeviation = deviation;
111
- }
112
- }
113
- const normalized = maxDeviation / 128;
114
- return Math.min(1, normalized * 1.5);
113
+ const data = new Uint8Array(analyser.fftSize);
114
+ analyser.getByteTimeDomainData(data);
115
+ let maxDeviation = 0;
116
+ for (const sample of data) {
117
+ const deviation = Math.abs(sample - 128);
118
+ if (deviation > maxDeviation) maxDeviation = deviation;
119
+ }
120
+ const normalized = maxDeviation / 128;
121
+ return Math.min(1, normalized * 1.5);
115
122
  }
116
123
  function base64ToArrayBuffer(base64) {
117
- const binary = atob(base64);
118
- const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
119
- return bytes.buffer;
124
+ const binary = atob(base64);
125
+ return Uint8Array.from(binary, (char) => char.charCodeAt(0)).buffer;
120
126
  }
121
- const emptyFrequencyData = new Uint8Array(1024);
122
- const emptyTimeDomainData = new Uint8Array(2048).fill(128);
123
- class AudioStreamer {
124
- audioContext = null;
125
- audioWorklet = null;
126
- mediaStream = null;
127
- analyser = null;
128
- isStreaming = false;
129
- sampleRate = 16e3;
130
- client = null;
131
- constructor(client) {
132
- this.client = client;
133
- }
134
- get inputLevel() {
135
- if (!this.analyser) return 0;
136
- return calculateLevel(this.analyser);
137
- }
138
- get inputFrequencyData() {
139
- if (!this.analyser) return emptyFrequencyData;
140
- const data = new Uint8Array(this.analyser.frequencyBinCount);
141
- this.analyser.getByteFrequencyData(data);
142
- return data;
143
- }
144
- get inputTimeDomainData() {
145
- if (!this.analyser) return emptyTimeDomainData;
146
- const data = new Uint8Array(this.analyser.fftSize);
147
- this.analyser.getByteTimeDomainData(data);
148
- return data;
149
- }
150
- get inputSampleRate() {
151
- return this.sampleRate;
152
- }
153
- async start() {
154
- try {
155
- const audioConstraints = {
156
- sampleRate: this.sampleRate,
157
- echoCancellation: true,
158
- noiseSuppression: true,
159
- autoGainControl: true
160
- };
161
- this.mediaStream = await navigator.mediaDevices.getUserMedia({
162
- audio: audioConstraints
163
- });
164
- const track = this.mediaStream.getAudioTracks()[0];
165
- const settings = track?.getSettings();
166
- if (settings?.autoGainControl) {
167
- console.warn("Native AGC not supported.");
168
- }
169
- this.audioContext = new AudioContext({
170
- sampleRate: this.sampleRate
171
- });
172
- if (this.audioContext.state === "suspended") {
173
- await this.audioContext.resume();
174
- }
175
- const workletBlob = new Blob([captureWorkletCode], {
176
- type: "application/javascript"
177
- });
178
- const workletUrl = URL.createObjectURL(workletBlob);
179
- await this.audioContext.audioWorklet.addModule(workletUrl);
180
- URL.revokeObjectURL(workletUrl);
181
- this.audioWorklet = new AudioWorkletNode(
182
- this.audioContext,
183
- "audio-capture-processor"
184
- );
185
- this.audioWorklet.port.onmessage = (event) => {
186
- if (!this.isStreaming) return;
187
- if (event.data.type === "audio") {
188
- const inputData = event.data.data;
189
- const pcmData = this.convertToPCM16(inputData);
190
- const base64Audio = this.arrayBufferToBase64(pcmData);
191
- if (this.client?.isSetupComplete) {
192
- this.client.sendAudioMessage(base64Audio);
193
- }
194
- }
195
- };
196
- this.analyser = this.audioContext.createAnalyser();
197
- this.analyser.fftSize = 2048;
198
- this.analyser.smoothingTimeConstant = 0.3;
199
- const source = this.audioContext.createMediaStreamSource(this.mediaStream);
200
- source.connect(this.analyser);
201
- this.analyser.connect(this.audioWorklet);
202
- this.isStreaming = true;
203
- } catch (error) {
204
- this.stop();
205
- throw error;
206
- }
207
- }
208
- stop() {
209
- this.isStreaming = false;
210
- if (this.audioWorklet) {
211
- this.audioWorklet.disconnect();
212
- this.audioWorklet.port.close();
213
- this.audioWorklet = null;
214
- }
215
- if (this.audioContext) {
216
- void this.audioContext.close();
217
- this.audioContext = null;
218
- }
219
- if (this.mediaStream) {
220
- this.mediaStream.getTracks().forEach((track) => track.stop());
221
- this.mediaStream = null;
222
- }
223
- }
224
- startAudioCapture() {
225
- if (this.mediaStream) {
226
- for (const track of this.mediaStream.getAudioTracks()) {
227
- track.enabled = true;
228
- }
229
- }
230
- this.isStreaming = true;
231
- }
232
- stopAudioCapture() {
233
- if (this.mediaStream) {
234
- for (const track of this.mediaStream.getAudioTracks()) {
235
- track.enabled = false;
236
- }
237
- }
238
- this.isStreaming = false;
239
- }
240
- convertToPCM16(float32Array) {
241
- const int16Array = new Int16Array(float32Array.length);
242
- for (let i = 0; i < float32Array.length; i++) {
243
- const sample = Math.max(-1, Math.min(1, float32Array[i] ?? 0));
244
- int16Array[i] = sample * 32767;
245
- }
246
- return int16Array.buffer;
247
- }
248
- arrayBufferToBase64(buffer) {
249
- const bytes = new Uint8Array(buffer);
250
- const binary = String.fromCharCode(...bytes);
251
- return btoa(binary);
252
- }
253
- }
254
- class AudioPlayer {
255
- audioContext = null;
256
- workletNode = null;
257
- gainNode = null;
258
- analyser = null;
259
- isInitialized = false;
260
- volume = 1;
261
- sampleRate = 24e3;
262
- get outputLevel() {
263
- if (!this.analyser) return 0;
264
- return calculateLevel(this.analyser);
265
- }
266
- get outputFrequencyData() {
267
- if (!this.analyser) return emptyFrequencyData;
268
- const data = new Uint8Array(this.analyser.frequencyBinCount);
269
- this.analyser.getByteFrequencyData(data);
270
- return data;
271
- }
272
- get outputTimeDomainData() {
273
- if (!this.analyser) return emptyTimeDomainData;
274
- const data = new Uint8Array(this.analyser.fftSize);
275
- this.analyser.getByteTimeDomainData(data);
276
- return data;
277
- }
278
- get outputSampleRate() {
279
- return this.sampleRate;
280
- }
281
- async init() {
282
- if (this.isInitialized) return;
283
- try {
284
- this.audioContext = new AudioContext({
285
- sampleRate: this.sampleRate
286
- });
287
- const workletBlob = new Blob([playbackWorkletCode], {
288
- type: "application/javascript"
289
- });
290
- const workletUrl = URL.createObjectURL(workletBlob);
291
- await this.audioContext.audioWorklet.addModule(workletUrl);
292
- URL.revokeObjectURL(workletUrl);
293
- this.workletNode = new AudioWorkletNode(
294
- this.audioContext,
295
- "pcm-processor"
296
- );
297
- this.gainNode = this.audioContext.createGain();
298
- this.gainNode.gain.value = this.volume;
299
- this.analyser = this.audioContext.createAnalyser();
300
- this.analyser.fftSize = 2048;
301
- this.analyser.smoothingTimeConstant = 0.3;
302
- this.workletNode.connect(this.gainNode);
303
- this.gainNode.connect(this.analyser);
304
- this.analyser.connect(this.audioContext.destination);
305
- this.isInitialized = true;
306
- } catch (error) {
307
- this.destroy();
308
- throw error;
309
- }
310
- }
311
- async play(pcmData) {
312
- if (!this.isInitialized) {
313
- await this.init();
314
- }
315
- if (this.audioContext?.state === "suspended") {
316
- await this.audioContext.resume();
317
- }
318
- const inputArray = new Int16Array(pcmData);
319
- const float32Data = new Float32Array(inputArray.length);
320
- for (let i = 0; i < inputArray.length; i++) {
321
- float32Data[i] = (inputArray[i] ?? 0) / 32768;
322
- }
323
- this.workletNode?.port.postMessage(float32Data);
324
- }
325
- /* Interrupt playback */
326
- interrupt() {
327
- if (this.workletNode) {
328
- this.workletNode.port.postMessage("interrupt");
329
- }
330
- }
331
- setVolume(volume) {
332
- this.volume = Math.max(0, Math.min(1, volume));
333
- if (this.gainNode) {
334
- this.gainNode.gain.value = this.volume;
335
- }
336
- }
337
- destroy() {
338
- if (this.audioContext) {
339
- void this.audioContext.close();
340
- this.audioContext = null;
341
- }
342
- this.isInitialized = false;
343
- }
344
- }
345
- export {
346
- AudioPlayer,
347
- AudioStreamer,
348
- base64ToArrayBuffer
127
+ var emptyFrequencyData = /* @__PURE__ */ new Uint8Array(1024);
128
+ var emptyTimeDomainData = (/* @__PURE__ */ new Uint8Array(2048)).fill(128);
129
+ var AudioStreamer = class {
130
+ audioContext = null;
131
+ audioWorklet = null;
132
+ mediaStream = null;
133
+ analyser = null;
134
+ isStreaming = false;
135
+ sampleRate = 16e3;
136
+ client = null;
137
+ constructor(client) {
138
+ this.client = client;
139
+ }
140
+ get inputLevel() {
141
+ if (!this.analyser) return 0;
142
+ return calculateLevel(this.analyser);
143
+ }
144
+ get inputFrequencyData() {
145
+ if (!this.analyser) return emptyFrequencyData;
146
+ const data = new Uint8Array(this.analyser.frequencyBinCount);
147
+ this.analyser.getByteFrequencyData(data);
148
+ return data;
149
+ }
150
+ get inputTimeDomainData() {
151
+ if (!this.analyser) return emptyTimeDomainData;
152
+ const data = new Uint8Array(this.analyser.fftSize);
153
+ this.analyser.getByteTimeDomainData(data);
154
+ return data;
155
+ }
156
+ get inputSampleRate() {
157
+ return this.sampleRate;
158
+ }
159
+ async start() {
160
+ try {
161
+ const audioConstraints = {
162
+ sampleRate: this.sampleRate,
163
+ echoCancellation: true,
164
+ noiseSuppression: true,
165
+ autoGainControl: true
166
+ };
167
+ this.mediaStream = await navigator.mediaDevices.getUserMedia({ audio: audioConstraints });
168
+ if ((this.mediaStream.getAudioTracks()[0]?.getSettings())?.autoGainControl) console.warn("Native AGC not supported.");
169
+ this.audioContext = new AudioContext({ sampleRate: this.sampleRate });
170
+ if (this.audioContext.state === "suspended") await this.audioContext.resume();
171
+ const workletBlob = new Blob([captureWorkletCode], { type: "application/javascript" });
172
+ const workletUrl = URL.createObjectURL(workletBlob);
173
+ await this.audioContext.audioWorklet.addModule(workletUrl);
174
+ URL.revokeObjectURL(workletUrl);
175
+ this.audioWorklet = new AudioWorkletNode(this.audioContext, "audio-capture-processor");
176
+ this.audioWorklet.port.onmessage = (event) => {
177
+ if (!this.isStreaming) return;
178
+ if (event.data.type === "audio") {
179
+ const inputData = event.data.data;
180
+ const pcmData = this.convertToPCM16(inputData);
181
+ const base64Audio = this.arrayBufferToBase64(pcmData);
182
+ if (this.client?.isSetupComplete) this.client.sendAudioMessage(base64Audio);
183
+ }
184
+ };
185
+ this.analyser = this.audioContext.createAnalyser();
186
+ this.analyser.fftSize = 2048;
187
+ this.analyser.smoothingTimeConstant = .3;
188
+ this.audioContext.createMediaStreamSource(this.mediaStream).connect(this.analyser);
189
+ this.analyser.connect(this.audioWorklet);
190
+ this.isStreaming = true;
191
+ } catch (error) {
192
+ this.stop();
193
+ throw error;
194
+ }
195
+ }
196
+ stop() {
197
+ this.isStreaming = false;
198
+ if (this.audioWorklet) {
199
+ this.audioWorklet.disconnect();
200
+ this.audioWorklet.port.close();
201
+ this.audioWorklet = null;
202
+ }
203
+ if (this.audioContext) {
204
+ this.audioContext.close();
205
+ this.audioContext = null;
206
+ }
207
+ if (this.mediaStream) {
208
+ this.mediaStream.getTracks().forEach((track) => track.stop());
209
+ this.mediaStream = null;
210
+ }
211
+ }
212
+ startAudioCapture() {
213
+ if (this.mediaStream) for (const track of this.mediaStream.getAudioTracks()) track.enabled = true;
214
+ this.isStreaming = true;
215
+ }
216
+ stopAudioCapture() {
217
+ if (this.mediaStream) for (const track of this.mediaStream.getAudioTracks()) track.enabled = false;
218
+ this.isStreaming = false;
219
+ }
220
+ convertToPCM16(float32Array) {
221
+ const int16Array = new Int16Array(float32Array.length);
222
+ for (let i = 0; i < float32Array.length; i++) int16Array[i] = Math.max(-1, Math.min(1, float32Array[i] ?? 0)) * 32767;
223
+ return int16Array.buffer;
224
+ }
225
+ arrayBufferToBase64(buffer) {
226
+ const bytes = new Uint8Array(buffer);
227
+ const binary = String.fromCharCode(...bytes);
228
+ return btoa(binary);
229
+ }
349
230
  };
350
- //# sourceMappingURL=utils.js.map
231
+ var AudioPlayer = class {
232
+ audioContext = null;
233
+ workletNode = null;
234
+ gainNode = null;
235
+ analyser = null;
236
+ isInitialized = false;
237
+ volume = 1;
238
+ sampleRate = 24e3;
239
+ get outputLevel() {
240
+ if (!this.analyser) return 0;
241
+ return calculateLevel(this.analyser);
242
+ }
243
+ get outputFrequencyData() {
244
+ if (!this.analyser) return emptyFrequencyData;
245
+ const data = new Uint8Array(this.analyser.frequencyBinCount);
246
+ this.analyser.getByteFrequencyData(data);
247
+ return data;
248
+ }
249
+ get outputTimeDomainData() {
250
+ if (!this.analyser) return emptyTimeDomainData;
251
+ const data = new Uint8Array(this.analyser.fftSize);
252
+ this.analyser.getByteTimeDomainData(data);
253
+ return data;
254
+ }
255
+ get outputSampleRate() {
256
+ return this.sampleRate;
257
+ }
258
+ async init() {
259
+ if (this.isInitialized) return;
260
+ try {
261
+ this.audioContext = new AudioContext({ sampleRate: this.sampleRate });
262
+ const workletBlob = new Blob([playbackWorkletCode], { type: "application/javascript" });
263
+ const workletUrl = URL.createObjectURL(workletBlob);
264
+ await this.audioContext.audioWorklet.addModule(workletUrl);
265
+ URL.revokeObjectURL(workletUrl);
266
+ this.workletNode = new AudioWorkletNode(this.audioContext, "pcm-processor");
267
+ this.gainNode = this.audioContext.createGain();
268
+ this.gainNode.gain.value = this.volume;
269
+ this.analyser = this.audioContext.createAnalyser();
270
+ this.analyser.fftSize = 2048;
271
+ this.analyser.smoothingTimeConstant = .3;
272
+ this.workletNode.connect(this.gainNode);
273
+ this.gainNode.connect(this.analyser);
274
+ this.analyser.connect(this.audioContext.destination);
275
+ this.isInitialized = true;
276
+ } catch (error) {
277
+ this.destroy();
278
+ throw error;
279
+ }
280
+ }
281
+ async play(pcmData) {
282
+ if (!this.isInitialized) await this.init();
283
+ if (this.audioContext?.state === "suspended") await this.audioContext.resume();
284
+ const inputArray = new Int16Array(pcmData);
285
+ const float32Data = new Float32Array(inputArray.length);
286
+ for (let i = 0; i < inputArray.length; i++) float32Data[i] = (inputArray[i] ?? 0) / 32768;
287
+ this.workletNode?.port.postMessage(float32Data);
288
+ }
289
+ interrupt() {
290
+ if (this.workletNode) this.workletNode.port.postMessage("interrupt");
291
+ }
292
+ setVolume(volume) {
293
+ this.volume = Math.max(0, Math.min(1, volume));
294
+ if (this.gainNode) this.gainNode.gain.value = this.volume;
295
+ }
296
+ destroy() {
297
+ if (this.audioContext) {
298
+ this.audioContext.close();
299
+ this.audioContext = null;
300
+ }
301
+ this.isInitialized = false;
302
+ }
303
+ };
304
+ //#endregion
305
+ export { AudioPlayer, AudioStreamer, base64ToArrayBuffer };
306
+
307
+ //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../src/realtime/utils.ts"],"sourcesContent":["import type { GeminiLiveClient } from './client'\n\n/**\n * Audio Worklet Processor for capturing and processing audio\n */\nconst captureWorkletCode = `\nclass AudioCaptureProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.bufferSize = 512; // 32ms at 16kHz — per Gemini best practices (20-40ms chunks)\n this.buffer = new Float32Array(this.bufferSize);\n this.bufferIndex = 0;\n }\n\n process(inputs, outputs, parameters) {\n const input = inputs[0];\n\n if (input && input.length > 0) {\n const inputChannel = input[0];\n\n // Buffer the incoming audio\n for (let i = 0; i < inputChannel.length; i++) {\n this.buffer[this.bufferIndex++] = inputChannel[i];\n\n // When buffer is full, send it to main thread\n if (this.bufferIndex >= this.bufferSize) {\n // Send the buffered audio to the main thread\n this.port.postMessage({\n type: \"audio\",\n data: this.buffer.slice(),\n });\n\n // Reset buffer\n this.bufferIndex = 0;\n }\n }\n }\n\n // Return true to keep the processor alive\n return true;\n }\n}\n\n// Register the processor\nregisterProcessor(\"audio-capture-processor\", AudioCaptureProcessor);`\n\n/**\n * Audio Playback Worklet Processor for playing PCM audio.\n * Uses an offset tracker instead of slice() to avoid allocations\n * on the real-time audio thread.\n */\nconst playbackWorkletCode = `\nclass PCMProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.audioQueue = [];\n this.currentOffset = 0; // Track position in current buffer (avoids slice())\n\n this.port.onmessage = (event) => {\n if (event.data === \"interrupt\") {\n // Clear the queue on interrupt\n this.audioQueue = [];\n this.currentOffset = 0;\n } else if (event.data instanceof Float32Array) {\n // Add audio data to the queue\n this.audioQueue.push(event.data);\n }\n };\n }\n\n process(inputs, outputs, parameters) {\n const output = outputs[0];\n if (output.length === 0) return true;\n\n const channel = output[0];\n let outputIndex = 0;\n\n // Fill the output buffer from the queue\n while (outputIndex < channel.length && this.audioQueue.length > 0) {\n const currentBuffer = this.audioQueue[0];\n\n if (!currentBuffer || currentBuffer.length === 0) {\n this.audioQueue.shift();\n this.currentOffset = 0;\n continue;\n }\n\n const remainingOutput = channel.length - outputIndex;\n const remainingBuffer = currentBuffer.length - this.currentOffset;\n const copyLength = Math.min(remainingOutput, remainingBuffer);\n\n // Copy audio data to output using offset (no slice allocation)\n for (let i = 0; i < copyLength; i++) {\n channel[outputIndex++] = currentBuffer[this.currentOffset++];\n }\n\n // If we've consumed the entire buffer, move to the next one\n if (this.currentOffset >= currentBuffer.length) {\n this.audioQueue.shift();\n this.currentOffset = 0;\n }\n }\n\n // Fill remaining output with silence\n while (outputIndex < channel.length) {\n channel[outputIndex++] = 0;\n }\n\n return true;\n }\n}\n\nregisterProcessor(\"pcm-processor\", PCMProcessor);`\n\nfunction calculateLevel(analyser: AnalyserNode): number {\n const data = new Uint8Array(analyser.fftSize)\n analyser.getByteTimeDomainData(data)\n\n // Find peak deviation from center (128 is silence)\n // This is more responsive than RMS for voice level meters\n let maxDeviation = 0\n for (const sample of data) {\n const deviation = Math.abs(sample - 128)\n if (deviation > maxDeviation) {\n maxDeviation = deviation\n }\n }\n\n // Normalize to 0-1 range (max deviation is 128)\n // Scale by 1.5x so that ~66% amplitude reads as full scale\n // This provides good visual feedback without pegging too early\n const normalized = maxDeviation / 128\n return Math.min(1, normalized * 1.5)\n}\n\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64)\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0))\n return bytes.buffer\n}\n\n// Empty arrays for when visualization isn't available\n// frequencyBinCount = fftSize / 2 = 1024\nconst emptyFrequencyData = new Uint8Array(1024)\nconst emptyTimeDomainData = new Uint8Array(2048).fill(128) // 128 is silence\n\nexport class AudioStreamer {\n private audioContext: AudioContext | null = null\n private audioWorklet: AudioWorkletNode | null = null\n private mediaStream: MediaStream | null = null\n private analyser: AnalyserNode | null = null\n private isStreaming = false\n private readonly sampleRate = 16000\n private readonly client: GeminiLiveClient | null = null\n\n constructor(client: GeminiLiveClient) {\n this.client = client\n }\n\n get inputLevel() {\n if (!this.analyser) return 0\n return calculateLevel(this.analyser)\n }\n\n get inputFrequencyData() {\n if (!this.analyser) return emptyFrequencyData\n const data = new Uint8Array(this.analyser.frequencyBinCount)\n this.analyser.getByteFrequencyData(data)\n return data\n }\n\n get inputTimeDomainData() {\n if (!this.analyser) return emptyTimeDomainData\n const data = new Uint8Array(this.analyser.fftSize)\n this.analyser.getByteTimeDomainData(data)\n return data\n }\n\n get inputSampleRate() {\n return this.sampleRate\n }\n\n async start() {\n try {\n const audioConstraints: MediaTrackConstraints = {\n sampleRate: this.sampleRate,\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n }\n\n // Get microphone access\n this.mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: audioConstraints,\n })\n\n // Check if native AGC is active\n const track = this.mediaStream.getAudioTracks()[0]\n const settings = track?.getSettings()\n\n if (settings?.autoGainControl) {\n console.warn('Native AGC not supported.')\n }\n\n // Create audio context\n this.audioContext = new AudioContext({\n sampleRate: this.sampleRate,\n })\n\n if (this.audioContext.state === 'suspended') {\n await this.audioContext.resume()\n }\n\n const workletBlob = new Blob([captureWorkletCode], {\n type: 'application/javascript',\n })\n const workletUrl = URL.createObjectURL(workletBlob)\n\n // Load the audio worklet module, then release the blob URL.\n await this.audioContext.audioWorklet.addModule(workletUrl)\n URL.revokeObjectURL(workletUrl)\n\n // Create the audio worklet node\n this.audioWorklet = new AudioWorkletNode(\n this.audioContext,\n 'audio-capture-processor',\n )\n\n // Set up message handling from the worklet\n this.audioWorklet.port.onmessage = (event) => {\n if (!this.isStreaming) return\n\n if (event.data.type === 'audio') {\n const inputData = event.data.data\n const pcmData = this.convertToPCM16(inputData)\n const base64Audio = this.arrayBufferToBase64(pcmData)\n\n // Send to Gemini only if after setup complete\n if (this.client?.isSetupComplete) {\n this.client.sendAudioMessage(base64Audio)\n }\n }\n }\n\n // Create analyser for volume detection\n this.analyser = this.audioContext.createAnalyser()\n this.analyser.fftSize = 2048 // Larger size for more accurate level detection\n this.analyser.smoothingTimeConstant = 0.3\n\n // Connect the audio graph\n const source = this.audioContext.createMediaStreamSource(this.mediaStream)\n source.connect(this.analyser)\n this.analyser.connect(this.audioWorklet)\n\n // Start streaming\n this.isStreaming = true\n } catch (error) {\n // Clean up the mic + audio context if setup failed partway through.\n this.stop()\n throw error\n }\n }\n\n stop() {\n this.isStreaming = false\n\n if (this.audioWorklet) {\n this.audioWorklet.disconnect()\n this.audioWorklet.port.close()\n this.audioWorklet = null\n }\n\n if (this.audioContext) {\n void this.audioContext.close()\n this.audioContext = null\n }\n\n if (this.mediaStream) {\n this.mediaStream.getTracks().forEach((track) => track.stop())\n this.mediaStream = null\n }\n }\n\n startAudioCapture() {\n if (this.mediaStream) {\n for (const track of this.mediaStream.getAudioTracks()) {\n track.enabled = true\n }\n }\n this.isStreaming = true\n }\n\n stopAudioCapture() {\n if (this.mediaStream) {\n // Disable tracks rather than stopping them to allow re-enabling\n for (const track of this.mediaStream.getAudioTracks()) {\n track.enabled = false\n }\n }\n this.isStreaming = false\n }\n\n private convertToPCM16(float32Array: Float32Array): ArrayBuffer {\n const int16Array = new Int16Array(float32Array.length)\n for (let i = 0; i < float32Array.length; i++) {\n const sample = Math.max(-1, Math.min(1, float32Array[i] ?? 0))\n int16Array[i] = sample * 0x7fff\n }\n return int16Array.buffer\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n const binary = String.fromCharCode(...bytes)\n return btoa(binary)\n }\n}\n\nexport class AudioPlayer {\n private audioContext: AudioContext | null = null\n private workletNode: AudioWorkletNode | null = null\n private gainNode: GainNode | null = null\n private analyser: AnalyserNode | null = null\n private isInitialized = false\n private volume = 1.0\n private readonly sampleRate = 24000\n\n get outputLevel() {\n if (!this.analyser) return 0\n return calculateLevel(this.analyser)\n }\n\n get outputFrequencyData() {\n if (!this.analyser) return emptyFrequencyData\n const data = new Uint8Array(this.analyser.frequencyBinCount)\n this.analyser.getByteFrequencyData(data)\n return data\n }\n\n get outputTimeDomainData() {\n if (!this.analyser) return emptyTimeDomainData\n const data = new Uint8Array(this.analyser.fftSize)\n this.analyser.getByteTimeDomainData(data)\n return data\n }\n\n get outputSampleRate() {\n return this.sampleRate\n }\n\n async init() {\n if (this.isInitialized) return\n\n try {\n // Create audio context at 24kHz to match Gemini\n this.audioContext = new AudioContext({\n sampleRate: this.sampleRate,\n })\n\n const workletBlob = new Blob([playbackWorkletCode], {\n type: 'application/javascript',\n })\n const workletUrl = URL.createObjectURL(workletBlob)\n\n // Load the audio worklet module, then release the blob URL.\n await this.audioContext.audioWorklet.addModule(workletUrl)\n URL.revokeObjectURL(workletUrl)\n\n // Create worklet node\n this.workletNode = new AudioWorkletNode(\n this.audioContext,\n 'pcm-processor',\n )\n\n // Create gain node for volume control\n this.gainNode = this.audioContext.createGain()\n this.gainNode.gain.value = this.volume\n\n // Create analyser for volume detection\n this.analyser = this.audioContext.createAnalyser()\n this.analyser.fftSize = 2048 // Larger size for more accurate level detection\n this.analyser.smoothingTimeConstant = 0.3\n\n // Connect nodes\n this.workletNode.connect(this.gainNode)\n this.gainNode.connect(this.analyser)\n this.analyser.connect(this.audioContext.destination)\n\n this.isInitialized = true\n } catch (error) {\n // Release the audio context if initialization failed partway through.\n this.destroy()\n throw error\n }\n }\n\n async play(pcmData: ArrayBuffer) {\n if (!this.isInitialized) {\n await this.init()\n }\n\n // Resume audio context if suspended\n if (this.audioContext?.state === 'suspended') {\n await this.audioContext.resume()\n }\n\n // Convert PCM16 LE to Float32\n const inputArray = new Int16Array(pcmData)\n const float32Data = new Float32Array(inputArray.length)\n for (let i = 0; i < inputArray.length; i++) {\n float32Data[i] = (inputArray[i] ?? 0) / 32768\n }\n\n // Send to worklet for playback\n this.workletNode?.port.postMessage(float32Data)\n }\n\n /* Interrupt playback */\n interrupt() {\n if (this.workletNode) {\n this.workletNode.port.postMessage('interrupt')\n }\n }\n\n setVolume(volume: number) {\n this.volume = Math.max(0, Math.min(1, volume))\n if (this.gainNode) {\n this.gainNode.gain.value = this.volume\n }\n }\n\n destroy() {\n if (this.audioContext) {\n void this.audioContext.close()\n this.audioContext = null\n }\n this.isInitialized = false\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../src/realtime/utils.ts"],"sourcesContent":["import type { GeminiLiveClient } from './client'\n\n/**\n * Audio Worklet Processor for capturing and processing audio\n */\nconst captureWorkletCode = `\nclass AudioCaptureProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.bufferSize = 512; // 32ms at 16kHz — per Gemini best practices (20-40ms chunks)\n this.buffer = new Float32Array(this.bufferSize);\n this.bufferIndex = 0;\n }\n\n process(inputs, outputs, parameters) {\n const input = inputs[0];\n\n if (input && input.length > 0) {\n const inputChannel = input[0];\n\n // Buffer the incoming audio\n for (let i = 0; i < inputChannel.length; i++) {\n this.buffer[this.bufferIndex++] = inputChannel[i];\n\n // When buffer is full, send it to main thread\n if (this.bufferIndex >= this.bufferSize) {\n // Send the buffered audio to the main thread\n this.port.postMessage({\n type: \"audio\",\n data: this.buffer.slice(),\n });\n\n // Reset buffer\n this.bufferIndex = 0;\n }\n }\n }\n\n // Return true to keep the processor alive\n return true;\n }\n}\n\n// Register the processor\nregisterProcessor(\"audio-capture-processor\", AudioCaptureProcessor);`\n\n/**\n * Audio Playback Worklet Processor for playing PCM audio.\n * Uses an offset tracker instead of slice() to avoid allocations\n * on the real-time audio thread.\n */\nconst playbackWorkletCode = `\nclass PCMProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.audioQueue = [];\n this.currentOffset = 0; // Track position in current buffer (avoids slice())\n\n this.port.onmessage = (event) => {\n if (event.data === \"interrupt\") {\n // Clear the queue on interrupt\n this.audioQueue = [];\n this.currentOffset = 0;\n } else if (event.data instanceof Float32Array) {\n // Add audio data to the queue\n this.audioQueue.push(event.data);\n }\n };\n }\n\n process(inputs, outputs, parameters) {\n const output = outputs[0];\n if (output.length === 0) return true;\n\n const channel = output[0];\n let outputIndex = 0;\n\n // Fill the output buffer from the queue\n while (outputIndex < channel.length && this.audioQueue.length > 0) {\n const currentBuffer = this.audioQueue[0];\n\n if (!currentBuffer || currentBuffer.length === 0) {\n this.audioQueue.shift();\n this.currentOffset = 0;\n continue;\n }\n\n const remainingOutput = channel.length - outputIndex;\n const remainingBuffer = currentBuffer.length - this.currentOffset;\n const copyLength = Math.min(remainingOutput, remainingBuffer);\n\n // Copy audio data to output using offset (no slice allocation)\n for (let i = 0; i < copyLength; i++) {\n channel[outputIndex++] = currentBuffer[this.currentOffset++];\n }\n\n // If we've consumed the entire buffer, move to the next one\n if (this.currentOffset >= currentBuffer.length) {\n this.audioQueue.shift();\n this.currentOffset = 0;\n }\n }\n\n // Fill remaining output with silence\n while (outputIndex < channel.length) {\n channel[outputIndex++] = 0;\n }\n\n return true;\n }\n}\n\nregisterProcessor(\"pcm-processor\", PCMProcessor);`\n\nfunction calculateLevel(analyser: AnalyserNode): number {\n const data = new Uint8Array(analyser.fftSize)\n analyser.getByteTimeDomainData(data)\n\n // Find peak deviation from center (128 is silence)\n // This is more responsive than RMS for voice level meters\n let maxDeviation = 0\n for (const sample of data) {\n const deviation = Math.abs(sample - 128)\n if (deviation > maxDeviation) {\n maxDeviation = deviation\n }\n }\n\n // Normalize to 0-1 range (max deviation is 128)\n // Scale by 1.5x so that ~66% amplitude reads as full scale\n // This provides good visual feedback without pegging too early\n const normalized = maxDeviation / 128\n return Math.min(1, normalized * 1.5)\n}\n\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64)\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0))\n return bytes.buffer\n}\n\n// Empty arrays for when visualization isn't available\n// frequencyBinCount = fftSize / 2 = 1024\nconst emptyFrequencyData = new Uint8Array(1024)\nconst emptyTimeDomainData = new Uint8Array(2048).fill(128) // 128 is silence\n\nexport class AudioStreamer {\n private audioContext: AudioContext | null = null\n private audioWorklet: AudioWorkletNode | null = null\n private mediaStream: MediaStream | null = null\n private analyser: AnalyserNode | null = null\n private isStreaming = false\n private readonly sampleRate = 16000\n private readonly client: GeminiLiveClient | null = null\n\n constructor(client: GeminiLiveClient) {\n this.client = client\n }\n\n get inputLevel() {\n if (!this.analyser) return 0\n return calculateLevel(this.analyser)\n }\n\n get inputFrequencyData() {\n if (!this.analyser) return emptyFrequencyData\n const data = new Uint8Array(this.analyser.frequencyBinCount)\n this.analyser.getByteFrequencyData(data)\n return data\n }\n\n get inputTimeDomainData() {\n if (!this.analyser) return emptyTimeDomainData\n const data = new Uint8Array(this.analyser.fftSize)\n this.analyser.getByteTimeDomainData(data)\n return data\n }\n\n get inputSampleRate() {\n return this.sampleRate\n }\n\n async start() {\n try {\n const audioConstraints: MediaTrackConstraints = {\n sampleRate: this.sampleRate,\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n }\n\n // Get microphone access\n this.mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: audioConstraints,\n })\n\n // Check if native AGC is active\n const track = this.mediaStream.getAudioTracks()[0]\n const settings = track?.getSettings()\n\n if (settings?.autoGainControl) {\n console.warn('Native AGC not supported.')\n }\n\n // Create audio context\n this.audioContext = new AudioContext({\n sampleRate: this.sampleRate,\n })\n\n if (this.audioContext.state === 'suspended') {\n await this.audioContext.resume()\n }\n\n const workletBlob = new Blob([captureWorkletCode], {\n type: 'application/javascript',\n })\n const workletUrl = URL.createObjectURL(workletBlob)\n\n // Load the audio worklet module, then release the blob URL.\n await this.audioContext.audioWorklet.addModule(workletUrl)\n URL.revokeObjectURL(workletUrl)\n\n // Create the audio worklet node\n this.audioWorklet = new AudioWorkletNode(\n this.audioContext,\n 'audio-capture-processor',\n )\n\n // Set up message handling from the worklet\n this.audioWorklet.port.onmessage = (event) => {\n if (!this.isStreaming) return\n\n if (event.data.type === 'audio') {\n const inputData = event.data.data\n const pcmData = this.convertToPCM16(inputData)\n const base64Audio = this.arrayBufferToBase64(pcmData)\n\n // Send to Gemini only if after setup complete\n if (this.client?.isSetupComplete) {\n this.client.sendAudioMessage(base64Audio)\n }\n }\n }\n\n // Create analyser for volume detection\n this.analyser = this.audioContext.createAnalyser()\n this.analyser.fftSize = 2048 // Larger size for more accurate level detection\n this.analyser.smoothingTimeConstant = 0.3\n\n // Connect the audio graph\n const source = this.audioContext.createMediaStreamSource(this.mediaStream)\n source.connect(this.analyser)\n this.analyser.connect(this.audioWorklet)\n\n // Start streaming\n this.isStreaming = true\n } catch (error) {\n // Clean up the mic + audio context if setup failed partway through.\n this.stop()\n throw error\n }\n }\n\n stop() {\n this.isStreaming = false\n\n if (this.audioWorklet) {\n this.audioWorklet.disconnect()\n this.audioWorklet.port.close()\n this.audioWorklet = null\n }\n\n if (this.audioContext) {\n void this.audioContext.close()\n this.audioContext = null\n }\n\n if (this.mediaStream) {\n this.mediaStream.getTracks().forEach((track) => track.stop())\n this.mediaStream = null\n }\n }\n\n startAudioCapture() {\n if (this.mediaStream) {\n for (const track of this.mediaStream.getAudioTracks()) {\n track.enabled = true\n }\n }\n this.isStreaming = true\n }\n\n stopAudioCapture() {\n if (this.mediaStream) {\n // Disable tracks rather than stopping them to allow re-enabling\n for (const track of this.mediaStream.getAudioTracks()) {\n track.enabled = false\n }\n }\n this.isStreaming = false\n }\n\n private convertToPCM16(float32Array: Float32Array): ArrayBuffer {\n const int16Array = new Int16Array(float32Array.length)\n for (let i = 0; i < float32Array.length; i++) {\n const sample = Math.max(-1, Math.min(1, float32Array[i] ?? 0))\n int16Array[i] = sample * 0x7fff\n }\n return int16Array.buffer\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n const binary = String.fromCharCode(...bytes)\n return btoa(binary)\n }\n}\n\nexport class AudioPlayer {\n private audioContext: AudioContext | null = null\n private workletNode: AudioWorkletNode | null = null\n private gainNode: GainNode | null = null\n private analyser: AnalyserNode | null = null\n private isInitialized = false\n private volume = 1.0\n private readonly sampleRate = 24000\n\n get outputLevel() {\n if (!this.analyser) return 0\n return calculateLevel(this.analyser)\n }\n\n get outputFrequencyData() {\n if (!this.analyser) return emptyFrequencyData\n const data = new Uint8Array(this.analyser.frequencyBinCount)\n this.analyser.getByteFrequencyData(data)\n return data\n }\n\n get outputTimeDomainData() {\n if (!this.analyser) return emptyTimeDomainData\n const data = new Uint8Array(this.analyser.fftSize)\n this.analyser.getByteTimeDomainData(data)\n return data\n }\n\n get outputSampleRate() {\n return this.sampleRate\n }\n\n async init() {\n if (this.isInitialized) return\n\n try {\n // Create audio context at 24kHz to match Gemini\n this.audioContext = new AudioContext({\n sampleRate: this.sampleRate,\n })\n\n const workletBlob = new Blob([playbackWorkletCode], {\n type: 'application/javascript',\n })\n const workletUrl = URL.createObjectURL(workletBlob)\n\n // Load the audio worklet module, then release the blob URL.\n await this.audioContext.audioWorklet.addModule(workletUrl)\n URL.revokeObjectURL(workletUrl)\n\n // Create worklet node\n this.workletNode = new AudioWorkletNode(\n this.audioContext,\n 'pcm-processor',\n )\n\n // Create gain node for volume control\n this.gainNode = this.audioContext.createGain()\n this.gainNode.gain.value = this.volume\n\n // Create analyser for volume detection\n this.analyser = this.audioContext.createAnalyser()\n this.analyser.fftSize = 2048 // Larger size for more accurate level detection\n this.analyser.smoothingTimeConstant = 0.3\n\n // Connect nodes\n this.workletNode.connect(this.gainNode)\n this.gainNode.connect(this.analyser)\n this.analyser.connect(this.audioContext.destination)\n\n this.isInitialized = true\n } catch (error) {\n // Release the audio context if initialization failed partway through.\n this.destroy()\n throw error\n }\n }\n\n async play(pcmData: ArrayBuffer) {\n if (!this.isInitialized) {\n await this.init()\n }\n\n // Resume audio context if suspended\n if (this.audioContext?.state === 'suspended') {\n await this.audioContext.resume()\n }\n\n // Convert PCM16 LE to Float32\n const inputArray = new Int16Array(pcmData)\n const float32Data = new Float32Array(inputArray.length)\n for (let i = 0; i < inputArray.length; i++) {\n float32Data[i] = (inputArray[i] ?? 0) / 32768\n }\n\n // Send to worklet for playback\n this.workletNode?.port.postMessage(float32Data)\n }\n\n /* Interrupt playback */\n interrupt() {\n if (this.workletNode) {\n this.workletNode.port.postMessage('interrupt')\n }\n }\n\n setVolume(volume: number) {\n this.volume = Math.max(0, Math.min(1, volume))\n if (this.gainNode) {\n this.gainNode.gain.value = this.volume\n }\n }\n\n destroy() {\n if (this.audioContext) {\n void this.audioContext.close()\n this.audioContext = null\n }\n this.isInitialized = false\n }\n}\n"],"mappings":"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"}
@@ -1,18 +1,16 @@
1
1
  import { brandProviderTool } from "@tanstack/ai";
2
+ //#region src/tools/code-execution-tool.ts
2
3
  function convertCodeExecutionToolToAdapterFormat(_tool) {
3
- return {
4
- codeExecution: {}
5
- };
4
+ return { codeExecution: {} };
6
5
  }
7
6
  function codeExecutionTool() {
8
- return brandProviderTool({
9
- name: "code_execution",
10
- description: "",
11
- metadata: {}
12
- });
7
+ return brandProviderTool({
8
+ name: "code_execution",
9
+ description: "",
10
+ metadata: {}
11
+ });
13
12
  }
14
- export {
15
- codeExecutionTool,
16
- convertCodeExecutionToolToAdapterFormat
17
- };
18
- //# sourceMappingURL=code-execution-tool.js.map
13
+ //#endregion
14
+ export { codeExecutionTool, convertCodeExecutionToolToAdapterFormat };
15
+
16
+ //# sourceMappingURL=code-execution-tool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"code-execution-tool.js","sources":["../../../src/tools/code-execution-tool.ts"],"sourcesContent":["import { brandProviderTool } from '@tanstack/ai'\nimport type { ProviderTool, Tool } from '@tanstack/ai'\n\nexport interface CodeExecutionToolConfig {}\n\n/** @deprecated Renamed to `CodeExecutionToolConfig`. Will be removed in a future release. */\nexport type CodeExecutionTool = CodeExecutionToolConfig\n\nexport type GeminiCodeExecutionTool = ProviderTool<'gemini', 'code_execution'>\n\nexport function convertCodeExecutionToolToAdapterFormat(_tool: Tool) {\n return {\n codeExecution: {},\n }\n}\n\nexport function codeExecutionTool(): GeminiCodeExecutionTool {\n return brandProviderTool<GeminiCodeExecutionTool>({\n name: 'code_execution',\n description: '',\n metadata: {},\n })\n}\n"],"names":[],"mappings":";AAUO,SAAS,wCAAwC,OAAa;AACnE,SAAO;AAAA,IACL,eAAe,CAAA;AAAA,EAAC;AAEpB;AAEO,SAAS,oBAA6C;AAC3D,SAAO,kBAA2C;AAAA,IAChD,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU,CAAA;AAAA,EAAC,CACZ;AACH;"}
1
+ {"version":3,"file":"code-execution-tool.js","names":[],"sources":["../../../src/tools/code-execution-tool.ts"],"sourcesContent":["import { brandProviderTool } from '@tanstack/ai'\nimport type { ProviderTool, Tool } from '@tanstack/ai'\n\nexport interface CodeExecutionToolConfig {}\n\n/** @deprecated Renamed to `CodeExecutionToolConfig`. Will be removed in a future release. */\nexport type CodeExecutionTool = CodeExecutionToolConfig\n\nexport type GeminiCodeExecutionTool = ProviderTool<'gemini', 'code_execution'>\n\nexport function convertCodeExecutionToolToAdapterFormat(_tool: Tool) {\n return {\n codeExecution: {},\n }\n}\n\nexport function codeExecutionTool(): GeminiCodeExecutionTool {\n return brandProviderTool<GeminiCodeExecutionTool>({\n name: 'code_execution',\n description: '',\n metadata: {},\n })\n}\n"],"mappings":";;AAUA,SAAgB,wCAAwC,OAAa;CACnE,OAAO,EACL,eAAe,CAAC,EAClB;AACF;AAEA,SAAgB,oBAA6C;CAC3D,OAAO,kBAA2C;EAChD,MAAM;EACN,aAAa;EACb,UAAU,CAAC;CACb,CAAC;AACH"}
@@ -1,33 +1,23 @@
1
1
  import { brandProviderTool } from "@tanstack/ai";
2
+ //#region src/tools/computer-use-tool.ts
2
3
  function convertComputerUseToolToAdapterFormat(tool) {
3
- const metadata = tool.metadata;
4
- return {
5
- computerUse: {
6
- ...metadata.environment !== void 0 && {
7
- environment: metadata.environment
8
- },
9
- ...metadata.excludedPredefinedFunctions !== void 0 && {
10
- excludedPredefinedFunctions: metadata.excludedPredefinedFunctions
11
- }
12
- }
13
- };
4
+ const metadata = tool.metadata;
5
+ return { computerUse: {
6
+ ...metadata.environment !== void 0 && { environment: metadata.environment },
7
+ ...metadata.excludedPredefinedFunctions !== void 0 && { excludedPredefinedFunctions: metadata.excludedPredefinedFunctions }
8
+ } };
14
9
  }
15
10
  function computerUseTool(config) {
16
- return brandProviderTool({
17
- name: "computer_use",
18
- description: "",
19
- metadata: {
20
- ...config.environment !== void 0 && {
21
- environment: config.environment
22
- },
23
- ...config.excludedPredefinedFunctions !== void 0 && {
24
- excludedPredefinedFunctions: config.excludedPredefinedFunctions
25
- }
26
- }
27
- });
11
+ return brandProviderTool({
12
+ name: "computer_use",
13
+ description: "",
14
+ metadata: {
15
+ ...config.environment !== void 0 && { environment: config.environment },
16
+ ...config.excludedPredefinedFunctions !== void 0 && { excludedPredefinedFunctions: config.excludedPredefinedFunctions }
17
+ }
18
+ });
28
19
  }
29
- export {
30
- computerUseTool,
31
- convertComputerUseToolToAdapterFormat
32
- };
33
- //# sourceMappingURL=computer-use-tool.js.map
20
+ //#endregion
21
+ export { computerUseTool, convertComputerUseToolToAdapterFormat };
22
+
23
+ //# sourceMappingURL=computer-use-tool.js.map