From d4874c6b97de36e858427df2e2d4e10344b1acdd Mon Sep 17 00:00:00 2001 From: Nikas Belogolov Date: Sun, 29 Mar 2026 13:16:57 +0300 Subject: [PATCH 1/7] Added gemini ephemeral realtime token --- .changeset/huge-lizards-admire.md | 5 + packages/typescript/ai-gemini/package.json | 6 +- .../ai-gemini/src/realtime/index.ts | 12 + .../ai-gemini/src/realtime/token.ts | 79 +++ .../ai-gemini/src/realtime/types.ts | 30 + pnpm-lock.yaml | 614 +++++++++++++----- 6 files changed, 570 insertions(+), 176 deletions(-) create mode 100644 .changeset/huge-lizards-admire.md create mode 100644 packages/typescript/ai-gemini/src/realtime/index.ts create mode 100644 packages/typescript/ai-gemini/src/realtime/token.ts create mode 100644 packages/typescript/ai-gemini/src/realtime/types.ts diff --git a/.changeset/huge-lizards-admire.md b/.changeset/huge-lizards-admire.md new file mode 100644 index 000000000..cc17b39d0 --- /dev/null +++ b/.changeset/huge-lizards-admire.md @@ -0,0 +1,5 @@ +--- +'@tanstack/ai-gemini': minor +--- + +Added Gemini Realtime Adapter diff --git a/packages/typescript/ai-gemini/package.json b/packages/typescript/ai-gemini/package.json index 17fa4705c..e616b5b17 100644 --- a/packages/typescript/ai-gemini/package.json +++ b/packages/typescript/ai-gemini/package.json @@ -40,13 +40,15 @@ "adapter" ], "dependencies": { - "@google/genai": "^1.43.0" + "@google/genai": "^1.46.0" }, "peerDependencies": { - "@tanstack/ai": "workspace:^" + "@tanstack/ai": "workspace:^", + "@tanstack/ai-client": "workspace:^" }, "devDependencies": { "@tanstack/ai": "workspace:*", + "@tanstack/ai-client": "workspace:*", "@vitest/coverage-v8": "4.0.14", "vite": "^7.2.7" } diff --git a/packages/typescript/ai-gemini/src/realtime/index.ts b/packages/typescript/ai-gemini/src/realtime/index.ts new file mode 100644 index 000000000..be743cb47 --- /dev/null +++ b/packages/typescript/ai-gemini/src/realtime/index.ts @@ -0,0 +1,12 @@ +// Token adapter for server-side use +export { geminiRealtimeToken } from './token' + +// Client adapter for browser use +export { geminiRealtime } from './adapter' + +// Types +export type { + GeminiRealtimeModel, + GeminiRealtimeTokenOptions, + GeminiRealtimeOptions, +} from './types' diff --git a/packages/typescript/ai-gemini/src/realtime/token.ts b/packages/typescript/ai-gemini/src/realtime/token.ts new file mode 100644 index 000000000..ed6ebd3fb --- /dev/null +++ b/packages/typescript/ai-gemini/src/realtime/token.ts @@ -0,0 +1,79 @@ +import { GoogleGenAI, Modality } from "@google/genai"; +import { getGeminiApiKeyFromEnv } from "../utils"; +import type { RealtimeToken, RealtimeTokenAdapter } from "@tanstack/ai"; +import type { GeminiRealtimeModel, GeminiRealtimeTokenOptions } from "./types"; + +/** + * Creates a Google Gemini realtime token adapter. + * + * This adapter generates ephemeral tokens for client-side WebSocket connections. + * + * @param options - Configuration options for the realtime session + * @returns A RealtimeTokenAdapter for use with realtimeToken() + * + * @example + * ```typescript + * import { realtimeToken } from '@tanstack/ai' + * import { geminiRealtimeToken } from '@tanstack/ai-gemini' + * + * const token = await realtimeToken({ + * adapter: geminiRealtimeToken({ + * model: 'gemini-live-2.5-flash-native-audio', + * }), + * }) + * ``` + */ +export function geminiRealtimeToken( + options: GeminiRealtimeTokenOptions = {}, +): RealtimeTokenAdapter { + const apiKey = getGeminiApiKeyFromEnv() + + const client = new GoogleGenAI({ + apiKey, + }); + + // Defaults to 30 minutes + const expireTime = options.expiresAt ?? Date.now() + 30 * 60 * 1000; + + return { + provider: 'gemini', + async generateToken(): Promise { + const model: GeminiRealtimeModel = + options.model ?? "gemini-live-2.5-flash-native-audio" + + const token = await client.authTokens.create({ + config: { + uses: 1, // The default + expireTime: new Date(expireTime).toISOString(), + liveConnectConstraints: { + model, + config: { + sessionResumption: {}, + maxOutputTokens: options.maxOutputTokens, + responseModalities: [Modality.AUDIO] + } + }, + httpOptions: { + apiVersion: 'v1alpha' + } + } + }); + + if (!token.name) { + throw new Error('Gemini realtime token creation failed') + } + + return { + provider: 'gemini', + token: token.name, + expiresAt: expireTime, + config: { + model, + maxOutputTokens: options.maxOutputTokens, + outputModalities: ["audio"], + } + } + } + } +} + diff --git a/packages/typescript/ai-gemini/src/realtime/types.ts b/packages/typescript/ai-gemini/src/realtime/types.ts new file mode 100644 index 000000000..3eb89f661 --- /dev/null +++ b/packages/typescript/ai-gemini/src/realtime/types.ts @@ -0,0 +1,30 @@ +/** + * Gemini realtime model options + */ +export type GeminiRealtimeModel = + | 'gemini-live-2.5-flash-native-audio' + +/** + * Options for the Gemini realtime client adapter + */ +export interface GeminiRealtimeOptions { + /** Connection mode (default: 'websocket' in browser) */ + connectionMode?: 'websocket' +} + +/** + * Options for the Gemini realtime token adapter + */ +export interface GeminiRealtimeTokenOptions { + /** Model to use (default: 'gemini-live-2.5-flash-native-audio') */ + model?: GeminiRealtimeModel + expiresAt?: number + maxOutputTokens?: number +} + +/** + * Gemini Realtime session response from the API + */ +export interface GeminiRealtimeSessionResponse { + +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37caa9ab7..d8c40f0cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -673,7 +673,7 @@ importers: devDependencies: vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai: dependencies: @@ -689,7 +689,7 @@ importers: version: 1.1.0 '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) zod: specifier: ^4.2.0 version: 4.2.1 @@ -705,7 +705,7 @@ importers: version: link:../ai '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) zod: specifier: ^4.2.0 version: 4.2.1 @@ -721,10 +721,10 @@ importers: devDependencies: '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) zod: specifier: ^4.2.0 version: 4.2.1 @@ -752,22 +752,22 @@ importers: devDependencies: '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) jsdom: specifier: ^27.2.0 version: 27.3.0(postcss@8.5.6) tsup: specifier: ^8.5.1 - version: 8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + version: 8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.5.0))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) tsup-preset-solid: specifier: ^2.2.0 - version: 2.2.0(esbuild@0.27.3)(solid-js@1.9.10)(tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) + version: 2.2.0(esbuild@0.27.3)(solid-js@1.9.10)(tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.5.0))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vite-plugin-solid: specifier: ^2.11.10 - version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) packages/typescript/ai-elevenlabs: dependencies: @@ -783,7 +783,7 @@ importers: version: link:../ai-client '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) packages/typescript/ai-event-client: dependencies: @@ -796,7 +796,7 @@ importers: version: link:../ai '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) packages/typescript/ai-fal: dependencies: @@ -809,26 +809,29 @@ importers: version: link:../ai '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-gemini: dependencies: '@google/genai': - specifier: ^1.43.0 - version: 1.43.0 + specifier: ^1.46.0 + version: 1.46.0 devDependencies: '@tanstack/ai': specifier: workspace:* version: link:../ai + '@tanstack/ai-client': + specifier: workspace:* + version: link:../ai-client '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: - specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-grok: dependencies: @@ -837,17 +840,17 @@ importers: version: link:../ai openai: specifier: ^6.9.1 - version: 6.10.0(ws@8.18.3)(zod@4.2.1) + version: 6.10.0(ws@8.20.0)(zod@4.2.1) zod: specifier: ^4.0.0 version: 4.2.1 devDependencies: '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-groq: dependencies: @@ -863,10 +866,10 @@ importers: devDependencies: '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-ollama: dependencies: @@ -879,16 +882,16 @@ importers: version: link:../ai '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-openai: dependencies: openai: specifier: ^6.9.1 - version: 6.10.0(ws@8.18.3)(zod@4.2.1) + version: 6.10.0(ws@8.20.0)(zod@4.2.1) devDependencies: '@tanstack/ai': specifier: workspace:* @@ -898,10 +901,10 @@ importers: version: link:../ai-client '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) zod: specifier: ^4.2.0 version: 4.2.1 @@ -917,10 +920,10 @@ importers: devDependencies: '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-preact: dependencies: @@ -936,7 +939,7 @@ importers: version: 3.2.4(preact@10.28.2) '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) jsdom: specifier: ^27.2.0 version: 27.3.0(postcss@8.5.6) @@ -945,7 +948,7 @@ importers: version: 10.28.2 vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-react: dependencies: @@ -964,7 +967,7 @@ importers: version: 19.2.7 '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) jsdom: specifier: ^27.2.0 version: 27.3.0(postcss@8.5.6) @@ -973,7 +976,7 @@ importers: version: 19.2.3 vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-react-ui: dependencies: @@ -1004,7 +1007,7 @@ importers: version: 19.2.7 '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) react: specifier: ^19.2.3 version: 19.2.3 @@ -1013,7 +1016,7 @@ importers: version: 19.2.3(react@19.2.3) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-solid: dependencies: @@ -1075,13 +1078,13 @@ importers: version: link:../ai-solid '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) solid-js: specifier: ^1.9.10 version: 1.9.10 vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/ai-svelte: dependencies: @@ -1103,7 +1106,7 @@ importers: version: 24.10.3 '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) jsdom: specifier: ^27.2.0 version: 27.3.0(postcss@8.5.6) @@ -1177,13 +1180,13 @@ importers: devDependencies: '@vitejs/plugin-vue': specifier: ^6.0.2 - version: 6.0.3(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + version: 6.0.3(vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue: specifier: ^3.5.25 version: 3.5.25(typescript@5.9.3) @@ -1205,10 +1208,10 @@ importers: devDependencies: '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/react-ai-devtools: dependencies: @@ -1224,13 +1227,13 @@ importers: version: 19.2.7 '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) react: specifier: ^19.2.3 version: 19.2.3 vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages/typescript/smoke-tests: {} @@ -1364,16 +1367,16 @@ importers: devDependencies: '@vitest/coverage-v8': specifier: 4.0.14 - version: 4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) solid-js: specifier: ^1.9.10 version: 1.9.10 vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vite-plugin-solid: specifier: ^2.11.10 - version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) testing/panel: dependencies: @@ -1619,6 +1622,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-syntax-jsx@7.27.1': resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} engines: {node: '>=6.9.0'} @@ -2435,6 +2443,10 @@ packages: resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-helpers@0.4.2': resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2447,6 +2459,10 @@ packages: resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@9.39.1': resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2474,8 +2490,8 @@ packages: '@gerrit0/mini-shiki@3.19.0': resolution: {integrity: sha512-ZSlWfLvr8Nl0T4iA3FF/8VH8HivYF82xQts2DY0tJxZd4wtXJ8AA0nmdW9lmO4hlrh3f9xNwEPtOgqETPqKwDA==} - '@google/genai@1.43.0': - resolution: {integrity: sha512-hklCsJNdMlDM1IwcCVcGQFBg2izY0+t5BIGbRsxi2UnKi6AGKL7pqJqmBDNRbw0bYCs4y3NA7TB+fkKfP/Nrdw==} + '@google/genai@1.46.0': + resolution: {integrity: sha512-ewPMN5JkKfgU5/kdco9ZhXBHDPhVqZpMQqIFQhwsHLf8kyZfx1cNpw1pHo1eV6PGEW7EhIBFi3aYZraFndAXqg==} engines: {node: '>=20.0.0'} peerDependencies: '@modelcontextprotocol/sdk': ^1.25.2 @@ -2646,21 +2662,25 @@ packages: resolution: {integrity: sha512-K6l/qa1rUM1saFlcT/KnJfhRtLyPkpYCxWGNYaMQ3gEFozPCHYdAJUQ+sKS8kVyWt2anAWx2XkmXUaz04OB8BQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@nx/nx-linux-arm64-musl@22.1.2': resolution: {integrity: sha512-vZUAUsaop5fdcyWpYzED+hWTKOuDtwG9DNNYUlII0dZhSA8kZwmXoYmrCGeMe5nQX9tF4pNzF+oddC/E169Z6g==} cpu: [arm64] os: [linux] + libc: [musl] '@nx/nx-linux-x64-gnu@22.1.2': resolution: {integrity: sha512-+NiA5uNh1cdpk2k984NlfIxRXaO0Bu0S4qCvWWKmL/150f31qJ/eHN6rd78/Re2qKO1NDoyDZLW6jqRXIm/GgA==} cpu: [x64] os: [linux] + libc: [glibc] '@nx/nx-linux-x64-musl@22.1.2': resolution: {integrity: sha512-8O7dXems/Of/biCKeuGMh3nmbS2PNvaL8R4xQzaBl94XitzFMxVFjjoTST7y3Ksmsa5Wrbzwyh+kHOMoIMlVpA==} cpu: [x64] os: [linux] + libc: [musl] '@nx/nx-win32-arm64-msvc@22.1.2': resolution: {integrity: sha512-/Wt3kdj5BksswSWL4N8tef6B+d5r0LbdEPqZimx3AqDMC9H1YkVuwwdBWFGOh+ldj/N8adRuZKjEMQfa/oqPGg==} @@ -2757,48 +2777,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-arm64-musl@0.110.0': resolution: {integrity: sha512-53GjCVY8kvymk9P6qNDh6zyblcehF5QHstq9QgCjv13ONGRnSHjeds0PxIwiihD7h295bxsWs84DN39syLPH4Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-minify/binding-linux-ppc64-gnu@0.110.0': resolution: {integrity: sha512-li8XcN81dxbJDMBESnTgGhoiAQ+CNIdM0QGscZ4duVPjCry1RpX+5FJySFbGqG3pk4s9ZzlL/vtQtbRzZIZOzg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-riscv64-gnu@0.110.0': resolution: {integrity: sha512-SweKfsnLKShu6UFV8mwuj1d1wmlNoL/FlAxPUzwjEBgwiT2HQkY24KnjBH+TIA+//1O83kzmWKvvs4OuEhdIEQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-riscv64-musl@0.110.0': resolution: {integrity: sha512-oH8G4aFMP8XyTsEpdANC5PQyHgSeGlopHZuW1rpyYcaErg5YaK0vXjQ4EM5HVvPm+feBV24JjxgakTnZoF3aOQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-minify/binding-linux-s390x-gnu@0.110.0': resolution: {integrity: sha512-W9na+Vza7XVUlpf8wMt4QBfH35KeTENEmnpPUq3NSlbQHz8lSlSvhAafvo43NcKvHAXV3ckD/mUf2VkqSdbklg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-x64-gnu@0.110.0': resolution: {integrity: sha512-XJdA4mmmXOjJxSRgNJXsDP7Xe8h3gQhmb56hUcCrvq5d+h5UcEi2pR8rxsdIrS8QmkLuBA3eHkGK8E27D7DTgQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-x64-musl@0.110.0': resolution: {integrity: sha512-QqzvALuOTtSckI8x467R4GNArzYDb/yEh6aNzLoeaY1O7vfT7SPDwlOEcchaTznutpeS9Dy8gUS/AfqtUHaufw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-minify/binding-openharmony-arm64@0.110.0': resolution: {integrity: sha512-gAMssLs2Q3+uhLZxanh1DF+27Kaug3cf4PXb9AB7XK81DR+LVcKySXaoGYoOs20Co0fFSphd6rRzKge2qDK3dA==} @@ -2871,41 +2899,49 @@ packages: resolution: {integrity: sha512-SVjjjtMW66Mza76PBGJLqB0KKyFTBnxmtDXLJPbL6ZPGSctcXVmujz7/WAc0rb9m2oV0cHQTtVjnq6orQnI/jg==} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-arm64-musl@11.15.0': resolution: {integrity: sha512-JDv2/AycPF2qgzEiDeMJCcSzKNDm3KxNg0KKWipoKEMDFqfM7LxNwwSVyAOGmrYlE4l3dg290hOMsr9xG7jv9g==} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-ppc64-gnu@11.15.0': resolution: {integrity: sha512-zbu9FhvBLW4KJxo7ElFvZWbSt4vP685Qc/Gyk/Ns3g2gR9qh2qWXouH8PWySy+Ko/qJ42+HJCLg+ZNcxikERfg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-gnu@11.15.0': resolution: {integrity: sha512-Kfleehe6B09C2qCnyIU01xLFqFXCHI4ylzkicfX/89j+gNHh9xyNdpEvit88Kq6i5tTGdavVnM6DQfOE2qNtlg==} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-musl@11.15.0': resolution: {integrity: sha512-J7LPiEt27Tpm8P+qURDwNc8q45+n+mWgyys4/V6r5A8v5gDentHRGUx3iVk5NxdKhgoGulrzQocPTZVosq25Eg==} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-s390x-gnu@11.15.0': resolution: {integrity: sha512-+8/d2tAScPjVJNyqa7GPGnqleTB/XW9dZJQ2D/oIM3wpH3TG+DaFEXBbk4QFJ9K9AUGBhvQvWU2mQyhK/yYn3Q==} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-gnu@11.15.0': resolution: {integrity: sha512-xtvSzH7Nr5MCZI2FKImmOdTl9kzuQ51RPyLh451tvD2qnkg3BaqI9Ox78bTk57YJhlXPuxWSOL5aZhKAc9J6qg==} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-musl@11.15.0': resolution: {integrity: sha512-14YL1zuXj06+/tqsuUZuzL0T425WA/I4nSVN1kBXeC5WHxem6lQ+2HGvG+crjeJEqHgZUT62YIgj88W+8E7eyg==} cpu: [x64] os: [linux] + libc: [musl] '@oxc-resolver/binding-openharmony-arm64@11.15.0': resolution: {integrity: sha512-/7Qli+1Wk93coxnrQaU8ySlICYN8HsgyIrzqjgIkQEpI//9eUeaeIHZptNl2fMvBGeXa7k2QgLbRNaBRgpnvMw==} @@ -2979,48 +3015,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-arm64-musl@0.110.0': resolution: {integrity: sha512-e5JN94/oy+wevk76q+LMr+2klTTcO60uXa+Wkq558Ms7mdF2TvkKFI++d/JeiuIwJLTi/BxQ4qdT5FWcsHM/ug==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-transform/binding-linux-ppc64-gnu@0.110.0': resolution: {integrity: sha512-Y3/Tnnz1GvDpmv8FXBIKtdZPsdZklOEPdrL6NHrN5i2u54BOkybFaDSptgWF53wOrJlTrcmAVSE6fRKK9XCM2Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-riscv64-gnu@0.110.0': resolution: {integrity: sha512-Y0E35iA9/v9jlkNcP6tMJ+ZFOS0rLsWDqG6rU9z+X2R3fBFJBO9UARIK6ngx8upxk81y1TFR2CmBFhupfYdH6Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-riscv64-musl@0.110.0': resolution: {integrity: sha512-JOUSYFfHjBUs7xp2FHmZHb8eTYD/oEu0NklS6JgUauqnoXZHiTLPLVW2o2uVCqldnabYHcomuwI2iqVFYJNhTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-transform/binding-linux-s390x-gnu@0.110.0': resolution: {integrity: sha512-7blgoXF9D3Ngzb7eun23pNrHJpoV/TtE6LObwlZ3Nmb4oZ6Z+yMvBVaoW68NarbmvNGfZ95zrOjgm6cVETLYBA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-x64-gnu@0.110.0': resolution: {integrity: sha512-YQ2joGWCVDZVEU2cD/r/w49hVjDm/Qu1BvC/7zs8LvprzdLS/HyMXGF2oA0puw0b+AqgYaz3bhwKB2xexHyITQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-x64-musl@0.110.0': resolution: {integrity: sha512-fkjr5qE632ULmNgvFXWDR/8668WxERz3tU7TQFp6JebPBneColitjSkdx6VKNVXEoMmQnOvBIGeP5tUNT384oA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-transform/binding-openharmony-arm64@0.110.0': resolution: {integrity: sha512-HWH9Zj+lMrdSTqFRCZsvDWMz7OnMjbdGsm3xURXWfRZpuaz0bVvyuZNDQXc4FyyhRDsemICaJbU1bgeIpUJDGw==} @@ -3080,36 +3124,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-wasm@2.3.0': resolution: {integrity: sha512-ejBAX8H0ZGsD8lSICDNyMbSEtPMWgDL0WFCt/0z7hyf5v8Imz4rAM8xY379mBsECkq/Wdqa5WEDLqtjZ+6NxfA==} @@ -3238,24 +3288,28 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==} @@ -3443,121 +3497,145 @@ packages: resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-gnueabihf@4.57.1': resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.53.3': resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm-musleabihf@4.57.1': resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.53.3': resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.57.1': resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.53.3': resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-musl@4.57.1': resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.53.3': resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-gnu@4.57.1': resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.57.1': resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.53.3': resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.57.1': resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.57.1': resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.53.3': resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.57.1': resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.53.3': resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-musl@4.57.1': resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.53.3': resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.57.1': resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.53.3': resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.57.1': resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.53.3': resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-linux-x64-musl@4.57.1': resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.57.1': resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} @@ -3849,24 +3927,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -4556,8 +4638,8 @@ packages: '@types/node@24.10.3': resolution: {integrity: sha512-gqkrWUsS8hcm0r44yn7/xZeV1ERva/nLgrLxFRUGb7aoNMIJfZJ3AC261zDQuOAKC7MiXai1WCpYc48jAHoShQ==} - '@types/node@25.0.1': - resolution: {integrity: sha512-czWPzKIAXucn9PtsttxmumiQ9N0ok9FrBwgRWrwmVLlp86BrMExzvXRLFYRJ+Ex3g6yqj+KuaxfX1JTgV2lpfg==} + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} @@ -4686,41 +4768,49 @@ packages: resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} @@ -4784,12 +4874,26 @@ packages: '@vitest/browser': optional: true + '@vitest/expect@4.0.14': + resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} + '@vitest/expect@4.0.15': resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} '@vitest/expect@4.0.18': resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + '@vitest/mocker@4.0.14': + resolution: {integrity: sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/mocker@4.0.15': resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} peerDependencies: @@ -4821,18 +4925,27 @@ packages: '@vitest/pretty-format@4.0.18': resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/runner@4.0.14': + resolution: {integrity: sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==} + '@vitest/runner@4.0.15': resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} '@vitest/runner@4.0.18': resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@vitest/snapshot@4.0.14': + resolution: {integrity: sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==} + '@vitest/snapshot@4.0.15': resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} '@vitest/snapshot@4.0.18': resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/spy@4.0.14': + resolution: {integrity: sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==} + '@vitest/spy@4.0.15': resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} @@ -4985,6 +5098,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} @@ -5076,8 +5192,8 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} - ast-v8-to-istanbul@0.3.11: - resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==} + ast-v8-to-istanbul@0.3.12: + resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} async-sema@3.1.1: resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} @@ -6184,8 +6300,8 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - gaxios@7.1.3: - resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} + gaxios@7.1.4: + resolution: {integrity: sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==} engines: {node: '>=18'} gcp-metadata@8.1.2: @@ -6271,8 +6387,8 @@ packages: peerDependencies: csstype: ^3.0.10 - google-auth-library@10.5.0: - resolution: {integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==} + google-auth-library@10.6.2: + resolution: {integrity: sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==} engines: {node: '>=18'} google-logging-utils@1.1.3: @@ -6289,10 +6405,6 @@ packages: groq-sdk@0.37.0: resolution: {integrity: sha512-lT72pcT8b/X5XrzdKf+rWVzUGW1OQSKESmL8fFN5cTbsf02gq6oFam4SVeNtzELt9cYE2Pt3pdGgSImuTbHFDg==} - gtoken@8.0.0: - resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} - engines: {node: '>=18'} - gzip-size@7.0.0: resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6916,24 +7028,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -7311,6 +7427,9 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} @@ -8030,10 +8149,6 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} - hasBin: true - robot3@0.4.1: resolution: {integrity: sha512-hzjy826lrxzx8eRgv80idkf8ua1JAepRc9Efdtj03N3KNJuznQCPlyCJ7gnUmDFwZCLQjxy567mQVKmdv2BsXQ==} @@ -8576,6 +8691,10 @@ packages: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + tldts-core@7.0.19: resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} @@ -8802,6 +8921,9 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici@7.16.0: resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} engines: {node: '>=20.18.1'} @@ -9239,6 +9361,40 @@ packages: vite: optional: true + vitest@4.0.14: + resolution: {integrity: sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.14 + '@vitest/browser-preview': 4.0.14 + '@vitest/browser-webdriverio': 4.0.14 + '@vitest/ui': 4.0.14 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vitest@4.0.15: resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -9458,6 +9614,18 @@ packages: utf-8-validate: optional: true + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -9704,6 +9872,10 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 @@ -10328,6 +10500,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + '@eslint/config-helpers@0.4.2': dependencies: '@eslint/core': 0.17.0 @@ -10350,6 +10530,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.14.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + '@eslint/js@9.39.1': {} '@eslint/js@9.39.2': {} @@ -10377,12 +10571,12 @@ snapshots: '@shikijs/types': 3.20.0 '@shikijs/vscode-textmate': 10.0.2 - '@google/genai@1.43.0': + '@google/genai@1.46.0': dependencies: - google-auth-library: 10.5.0 + google-auth-library: 10.6.2 p-retry: 4.6.2 protobufjs: 7.5.4 - ws: 8.18.3 + ws: 8.20.0 transitivePeerDependencies: - bufferutil - supports-color @@ -10504,11 +10698,11 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor-model@7.29.6(@types/node@25.0.1)': + '@microsoft/api-extractor-model@7.29.6(@types/node@25.5.0)': dependencies: '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.7.0(@types/node@25.0.1) + '@rushstack/node-core-library': 5.7.0(@types/node@25.5.0) transitivePeerDependencies: - '@types/node' optional: true @@ -10531,15 +10725,15 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.47.7(@types/node@25.0.1)': + '@microsoft/api-extractor@7.47.7(@types/node@25.5.0)': dependencies: - '@microsoft/api-extractor-model': 7.29.6(@types/node@25.0.1) + '@microsoft/api-extractor-model': 7.29.6(@types/node@25.5.0) '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.7.0(@types/node@25.0.1) + '@rushstack/node-core-library': 5.7.0(@types/node@25.5.0) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.0(@types/node@25.0.1) - '@rushstack/ts-command-line': 4.22.6(@types/node@25.0.1) + '@rushstack/terminal': 0.14.0(@types/node@25.5.0) + '@rushstack/ts-command-line': 4.22.6(@types/node@25.5.0) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.11 @@ -11260,7 +11454,7 @@ snapshots: optionalDependencies: '@types/node': 24.10.3 - '@rushstack/node-core-library@5.7.0(@types/node@25.0.1)': + '@rushstack/node-core-library@5.7.0(@types/node@25.5.0)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -11271,7 +11465,7 @@ snapshots: resolve: 1.22.11 semver: 7.5.4 optionalDependencies: - '@types/node': 25.0.1 + '@types/node': 25.5.0 optional: true '@rushstack/rig-package@0.5.3': @@ -11286,12 +11480,12 @@ snapshots: optionalDependencies: '@types/node': 24.10.3 - '@rushstack/terminal@0.14.0(@types/node@25.0.1)': + '@rushstack/terminal@0.14.0(@types/node@25.5.0)': dependencies: - '@rushstack/node-core-library': 5.7.0(@types/node@25.0.1) + '@rushstack/node-core-library': 5.7.0(@types/node@25.5.0) supports-color: 8.1.1 optionalDependencies: - '@types/node': 25.0.1 + '@types/node': 25.5.0 optional: true '@rushstack/ts-command-line@4.22.6(@types/node@24.10.3)': @@ -11303,9 +11497,9 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@rushstack/ts-command-line@4.22.6(@types/node@25.0.1)': + '@rushstack/ts-command-line@4.22.6(@types/node@25.5.0)': dependencies: - '@rushstack/terminal': 0.14.0(@types/node@25.0.1) + '@rushstack/terminal': 0.14.0(@types/node@25.5.0) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -11616,7 +11810,7 @@ snapshots: '@tanstack/devtools-event-bus@0.3.3': dependencies: - ws: 8.18.3 + ws: 8.20.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -13051,10 +13245,9 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/node@25.0.1': + '@types/node@25.5.0': dependencies: - undici-types: 7.16.0 - optional: true + undici-types: 7.18.2 '@types/react-dom@19.2.3(@types/react@19.2.7)': dependencies: @@ -13341,17 +13534,17 @@ snapshots: vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue: 3.5.25(typescript@5.9.3) - '@vitejs/plugin-vue@6.0.3(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.3(vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue: 3.5.25(typescript@5.9.3) - '@vitest/coverage-v8@4.0.14(vitest@4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@4.0.14(vitest@4.0.14(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.14 - ast-v8-to-istanbul: 0.3.11 + ast-v8-to-istanbul: 0.3.12 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -13359,16 +13552,16 @@ snapshots: magicast: 0.5.2 obug: 2.1.1 std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + tinyrainbow: 3.1.0 + vitest: 4.0.14(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.14(vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@4.0.14(vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.14 - ast-v8-to-istanbul: 0.3.11 + ast-v8-to-istanbul: 0.3.12 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -13376,16 +13569,16 @@ snapshots: magicast: 0.5.2 obug: 2.1.1 std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + tinyrainbow: 3.1.0 + vitest: 4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.14(vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@4.0.14(vitest@4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.14 - ast-v8-to-istanbul: 0.3.11 + ast-v8-to-istanbul: 0.3.12 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -13393,11 +13586,20 @@ snapshots: magicast: 0.5.2 obug: 2.1.1 std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + tinyrainbow: 3.1.0 + vitest: 4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color + '@vitest/expect@4.0.14': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 + chai: 6.2.2 + tinyrainbow: 3.1.0 + '@vitest/expect@4.0.15': dependencies: '@standard-schema/spec': 1.0.0 @@ -13416,33 +13618,41 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.15(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.14(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@vitest/spy': 4.0.15 + '@vitest/spy': 4.0.14 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.14(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.0.14 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@vitest/spy': 4.0.15 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@4.0.14': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 '@vitest/pretty-format@4.0.15': dependencies: @@ -13452,6 +13662,11 @@ snapshots: dependencies: tinyrainbow: 3.0.3 + '@vitest/runner@4.0.14': + dependencies: + '@vitest/utils': 4.0.14 + pathe: 2.0.3 + '@vitest/runner@4.0.15': dependencies: '@vitest/utils': 4.0.15 @@ -13462,6 +13677,12 @@ snapshots: '@vitest/utils': 4.0.18 pathe: 2.0.3 + '@vitest/snapshot@4.0.14': + dependencies: + '@vitest/pretty-format': 4.0.14 + magic-string: 0.30.21 + pathe: 2.0.3 + '@vitest/snapshot@4.0.15': dependencies: '@vitest/pretty-format': 4.0.15 @@ -13474,6 +13695,8 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 + '@vitest/spy@4.0.14': {} + '@vitest/spy@4.0.15': {} '@vitest/spy@4.0.18': {} @@ -13481,7 +13704,7 @@ snapshots: '@vitest/utils@4.0.14': dependencies: '@vitest/pretty-format': 4.0.14 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 '@vitest/utils@4.0.15': dependencies: @@ -13662,6 +13885,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ajv@8.12.0: dependencies: fast-deep-equal: 3.1.3 @@ -13762,7 +13992,7 @@ snapshots: dependencies: tslib: 2.8.1 - ast-v8-to-istanbul@0.3.11: + ast-v8-to-istanbul@0.3.12: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -14728,17 +14958,17 @@ snapshots: dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 + '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 + '@eslint/eslintrc': 3.3.5 '@eslint/js': 9.39.2 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -14757,7 +14987,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -15027,18 +15257,17 @@ snapshots: functions-have-names@1.2.3: {} - gaxios@7.1.3: + gaxios@7.1.4: dependencies: extend: 3.0.2 https-proxy-agent: 7.0.6 node-fetch: 3.3.2 - rimraf: 5.0.10 transitivePeerDependencies: - supports-color gcp-metadata@8.1.2: dependencies: - gaxios: 7.1.3 + gaxios: 7.1.4 google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: @@ -15145,14 +15374,13 @@ snapshots: dependencies: csstype: 3.2.3 - google-auth-library@10.5.0: + google-auth-library@10.6.2: dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.3 + gaxios: 7.1.4 gcp-metadata: 8.1.2 google-logging-utils: 1.1.3 - gtoken: 8.0.0 jws: 4.0.1 transitivePeerDependencies: - supports-color @@ -15175,13 +15403,6 @@ snapshots: transitivePeerDependencies: - encoding - gtoken@8.0.0: - dependencies: - gaxios: 7.1.3 - jws: 4.0.1 - transitivePeerDependencies: - - supports-color - gzip-size@7.0.0: dependencies: duplexer: 0.1.2 @@ -16029,7 +16250,7 @@ snapshots: magicast@0.5.2: dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 source-map-js: 1.2.1 @@ -16462,6 +16683,10 @@ snapshots: dependencies: brace-expansion: 1.1.12 + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + minimatch@5.1.6: dependencies: brace-expansion: 2.0.2 @@ -16941,9 +17166,9 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openai@6.10.0(ws@8.18.3)(zod@4.2.1): + openai@6.10.0(ws@8.20.0)(zod@4.2.1): optionalDependencies: - ws: 8.18.3 + ws: 8.20.0 zod: 4.2.1 optionator@0.9.4: @@ -17245,7 +17470,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 24.10.3 + '@types/node': 25.5.0 long: 5.3.2 proxy-addr@2.0.7: @@ -17477,10 +17702,6 @@ snapshots: reusify@1.1.0: {} - rimraf@5.0.10: - dependencies: - glob: 10.5.0 - robot3@0.4.1: {} rolldown-plugin-dts@0.18.3(oxc-resolver@11.15.0)(rolldown@1.0.0-beta.53)(typescript@5.9.3): @@ -18125,6 +18346,8 @@ snapshots: tinyrainbow@3.0.3: {} + tinyrainbow@3.1.0: {} + tldts-core@7.0.19: {} tldts@7.0.19: @@ -18211,16 +18434,16 @@ snapshots: tslib@2.8.1: {} - tsup-preset-solid@2.2.0(esbuild@0.27.3)(solid-js@1.9.10)(tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)): + tsup-preset-solid@2.2.0(esbuild@0.27.3)(solid-js@1.9.10)(tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.5.0))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)): dependencies: esbuild-plugin-solid: 0.5.0(esbuild@0.27.3)(solid-js@1.9.10) - tsup: 8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + tsup: 8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.5.0))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) transitivePeerDependencies: - esbuild - solid-js - supports-color - tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.0.1))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): + tsup@8.5.1(@microsoft/api-extractor@7.47.7(@types/node@25.5.0))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): dependencies: bundle-require: 5.1.0(esbuild@0.27.3) cac: 6.7.14 @@ -18240,7 +18463,7 @@ snapshots: tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: - '@microsoft/api-extractor': 7.47.7(@types/node@25.0.1) + '@microsoft/api-extractor': 7.47.7(@types/node@25.5.0) postcss: 8.5.6 typescript: 5.9.3 transitivePeerDependencies: @@ -18346,6 +18569,8 @@ snapshots: undici-types@7.16.0: {} + undici-types@7.18.2: {} + undici@7.16.0: {} undici@7.21.0: {} @@ -18717,7 +18942,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@babel/core': 7.28.5 '@types/babel__core': 7.20.5 @@ -18725,8 +18950,8 @@ snapshots: merge-anything: 5.1.7 solid-js: 1.9.10 solid-refresh: 0.6.3(solid-js@1.9.10) - vite: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vitefu: 1.1.1(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + vite: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.1(vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - supports-color @@ -18800,7 +19025,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -18809,7 +19034,7 @@ snapshots: rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.1 + '@types/node': 25.5.0 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 @@ -18834,7 +19059,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -18843,7 +19068,7 @@ snapshots: rollup: 4.57.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.1 + '@types/node': 25.5.0 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 @@ -18855,23 +19080,23 @@ snapshots: optionalDependencies: vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vitefu@1.1.1(vite@7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vitefu@1.1.1(vite@7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): optionalDependencies: - vite: 7.2.7(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.2.7(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitefu@1.1.1(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): optionalDependencies: vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vitest@4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.14(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.15 - '@vitest/runner': 4.0.15 - '@vitest/snapshot': 4.0.15 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 + '@vitest/expect': 4.0.14 + '@vitest/mocker': 4.0.14(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.14 + '@vitest/runner': 4.0.14 + '@vitest/snapshot': 4.0.14 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 es-module-lexer: 1.7.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -18880,9 +19105,9 @@ snapshots: picomatch: 4.0.3 std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 0.3.2 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: @@ -18902,15 +19127,54 @@ snapshots: - tsx - yaml - vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.14(@types/node@25.5.0)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 + '@vitest/expect': 4.0.14 + '@vitest/mocker': 4.0.14(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.14 + '@vitest/runner': 4.0.14 + '@vitest/snapshot': 4.0.14 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.5.0 + happy-dom: 20.0.11 + jsdom: 27.3.0(postcss@8.5.6) + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + vitest@4.0.15(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + '@vitest/expect': 4.0.15 + '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.15 + '@vitest/runner': 4.0.15 + '@vitest/snapshot': 4.0.15 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 es-module-lexer: 1.7.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -18922,7 +19186,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.2.7(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.10.3 @@ -18941,10 +19205,10 @@ snapshots: - tsx - yaml - vitest@4.0.18(@types/node@25.0.1)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.18(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -18961,10 +19225,10 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.0.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.0.1 + '@types/node': 24.10.3 happy-dom: 20.0.11 jsdom: 27.3.0(postcss@8.5.6) transitivePeerDependencies: @@ -19125,6 +19389,8 @@ snapshots: ws@8.18.3: {} + ws@8.20.0: {} + xml-name-validator@5.0.0: {} xmlbuilder2@3.1.1: From bb7d7b2c3b61f8450d11a2c70a6cf9627e6a4e80 Mon Sep 17 00:00:00 2001 From: Nikas Belogolov Date: Sun, 29 Mar 2026 13:22:12 +0300 Subject: [PATCH 2/7] added initial realtime adapter --- packages/typescript/ai-gemini/package.json | 2 +- .../ai-gemini/src/realtime/adapter.ts | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 packages/typescript/ai-gemini/src/realtime/adapter.ts diff --git a/packages/typescript/ai-gemini/package.json b/packages/typescript/ai-gemini/package.json index e616b5b17..02fdc3830 100644 --- a/packages/typescript/ai-gemini/package.json +++ b/packages/typescript/ai-gemini/package.json @@ -50,6 +50,6 @@ "@tanstack/ai": "workspace:*", "@tanstack/ai-client": "workspace:*", "@vitest/coverage-v8": "4.0.14", - "vite": "^7.2.7" + "vite": "^7.3.1" } } diff --git a/packages/typescript/ai-gemini/src/realtime/adapter.ts b/packages/typescript/ai-gemini/src/realtime/adapter.ts new file mode 100644 index 000000000..fdbf1e68e --- /dev/null +++ b/packages/typescript/ai-gemini/src/realtime/adapter.ts @@ -0,0 +1,49 @@ +import type { AnyClientTool, RealtimeEvent, RealtimeEventHandler, RealtimeToken } from "@tanstack/ai" +import type { RealtimeAdapter, RealtimeConnection } from "@tanstack/ai-client" +import type { GeminiRealtimeOptions } from "./types" + +/** + * Creates a Gemini realtime adapter for client-side use. + * + * @param options - Optional configuration + * @returns A RealtimeAdapter for use with RealtimeClient + * + * @example + * ```typescript + * import { RealtimeClient } from '@tanstack/ai-client' + * import { geminiRealtime } from '@tanstack/ai-gemini' + * + * const client = new RealtimeClient({ + * getToken: () => fetch('/api/realtime-token').then(r => r.json()), + * adapter: geminiRealtime(), + * }) + * ``` + */ +export function geminiRealtime( + options: GeminiRealtimeOptions = {} +): RealtimeAdapter { + return { + provider: 'gemini', + + connect( + token: RealtimeToken, + _clientTools?: ReadonlyArray, + ): Promise { + return createWebSocketConnection(token) + } + } +} + +/** + * Creates a WebSocket connection to Gemini's realtime API + */ +function createWebSocketConnection( + token: RealtimeToken +): Promise { + const model = token.config.model ?? 'gemini-live-2.5-flash-native-audio' + const eventHandlers = new Map>>() + + return new Promise((resolve, reject) => { + + }) +} \ No newline at end of file From 69ae10ccbddeef1f3187347ee81748a263e3a7c7 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 10:23:39 +0000 Subject: [PATCH 3/7] ci: apply automated fixes --- .../ai-gemini/src/realtime/adapter.ts | 25 +++++++------- .../ai-gemini/src/realtime/token.ts | 33 +++++++++---------- .../ai-gemini/src/realtime/types.ts | 7 ++-- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/packages/typescript/ai-gemini/src/realtime/adapter.ts b/packages/typescript/ai-gemini/src/realtime/adapter.ts index fdbf1e68e..9be0b5507 100644 --- a/packages/typescript/ai-gemini/src/realtime/adapter.ts +++ b/packages/typescript/ai-gemini/src/realtime/adapter.ts @@ -1,6 +1,11 @@ -import type { AnyClientTool, RealtimeEvent, RealtimeEventHandler, RealtimeToken } from "@tanstack/ai" -import type { RealtimeAdapter, RealtimeConnection } from "@tanstack/ai-client" -import type { GeminiRealtimeOptions } from "./types" +import type { + AnyClientTool, + RealtimeEvent, + RealtimeEventHandler, + RealtimeToken, +} from '@tanstack/ai' +import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client' +import type { GeminiRealtimeOptions } from './types' /** * Creates a Gemini realtime adapter for client-side use. @@ -20,17 +25,17 @@ import type { GeminiRealtimeOptions } from "./types" * ``` */ export function geminiRealtime( - options: GeminiRealtimeOptions = {} + options: GeminiRealtimeOptions = {}, ): RealtimeAdapter { return { provider: 'gemini', - + connect( token: RealtimeToken, _clientTools?: ReadonlyArray, ): Promise { return createWebSocketConnection(token) - } + }, } } @@ -38,12 +43,10 @@ export function geminiRealtime( * Creates a WebSocket connection to Gemini's realtime API */ function createWebSocketConnection( - token: RealtimeToken + token: RealtimeToken, ): Promise { const model = token.config.model ?? 'gemini-live-2.5-flash-native-audio' const eventHandlers = new Map>>() - return new Promise((resolve, reject) => { - - }) -} \ No newline at end of file + return new Promise((resolve, reject) => {}) +} diff --git a/packages/typescript/ai-gemini/src/realtime/token.ts b/packages/typescript/ai-gemini/src/realtime/token.ts index ed6ebd3fb..edeb43f9c 100644 --- a/packages/typescript/ai-gemini/src/realtime/token.ts +++ b/packages/typescript/ai-gemini/src/realtime/token.ts @@ -1,7 +1,7 @@ -import { GoogleGenAI, Modality } from "@google/genai"; -import { getGeminiApiKeyFromEnv } from "../utils"; -import type { RealtimeToken, RealtimeTokenAdapter } from "@tanstack/ai"; -import type { GeminiRealtimeModel, GeminiRealtimeTokenOptions } from "./types"; +import { GoogleGenAI, Modality } from '@google/genai' +import { getGeminiApiKeyFromEnv } from '../utils' +import type { RealtimeToken, RealtimeTokenAdapter } from '@tanstack/ai' +import type { GeminiRealtimeModel, GeminiRealtimeTokenOptions } from './types' /** * Creates a Google Gemini realtime token adapter. @@ -30,16 +30,16 @@ export function geminiRealtimeToken( const client = new GoogleGenAI({ apiKey, - }); + }) // Defaults to 30 minutes - const expireTime = options.expiresAt ?? Date.now() + 30 * 60 * 1000; + const expireTime = options.expiresAt ?? Date.now() + 30 * 60 * 1000 return { provider: 'gemini', async generateToken(): Promise { const model: GeminiRealtimeModel = - options.model ?? "gemini-live-2.5-flash-native-audio" + options.model ?? 'gemini-live-2.5-flash-native-audio' const token = await client.authTokens.create({ config: { @@ -50,14 +50,14 @@ export function geminiRealtimeToken( config: { sessionResumption: {}, maxOutputTokens: options.maxOutputTokens, - responseModalities: [Modality.AUDIO] - } + responseModalities: [Modality.AUDIO], + }, }, httpOptions: { - apiVersion: 'v1alpha' - } - } - }); + apiVersion: 'v1alpha', + }, + }, + }) if (!token.name) { throw new Error('Gemini realtime token creation failed') @@ -70,10 +70,9 @@ export function geminiRealtimeToken( config: { model, maxOutputTokens: options.maxOutputTokens, - outputModalities: ["audio"], - } + outputModalities: ['audio'], + }, } - } + }, } } - diff --git a/packages/typescript/ai-gemini/src/realtime/types.ts b/packages/typescript/ai-gemini/src/realtime/types.ts index 3eb89f661..8cef9b310 100644 --- a/packages/typescript/ai-gemini/src/realtime/types.ts +++ b/packages/typescript/ai-gemini/src/realtime/types.ts @@ -1,8 +1,7 @@ /** * Gemini realtime model options */ -export type GeminiRealtimeModel = - | 'gemini-live-2.5-flash-native-audio' +export type GeminiRealtimeModel = 'gemini-live-2.5-flash-native-audio' /** * Options for the Gemini realtime client adapter @@ -25,6 +24,4 @@ export interface GeminiRealtimeTokenOptions { /** * Gemini Realtime session response from the API */ -export interface GeminiRealtimeSessionResponse { - -} \ No newline at end of file +export interface GeminiRealtimeSessionResponse {} From 8d4097f55da0bfb554acfbde0fa1bf8b4abb9ceb Mon Sep 17 00:00:00 2001 From: Nikas Belogolov Date: Mon, 13 Apr 2026 22:44:14 +0300 Subject: [PATCH 4/7] Added gemini adapter, refactored realtime client --- .../ai-client/src/realtime-client.ts | 47 +- .../ai-client/src/realtime-types.ts | 9 +- packages/typescript/ai-gemini/src/index.ts | 6 + .../ai-gemini/src/realtime/adapter.ts | 559 +++++++++++++++++- .../ai-gemini/src/realtime/types.ts | 40 +- .../ai-openai/src/realtime/adapter.ts | 5 +- packages/typescript/ai/src/realtime/types.ts | 1 + 7 files changed, 648 insertions(+), 19 deletions(-) diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts index 2683294c0..fc63c1109 100644 --- a/packages/typescript/ai-client/src/realtime-client.ts +++ b/packages/typescript/ai-client/src/realtime-client.ts @@ -96,14 +96,45 @@ export class RealtimeClient { this.scheduleTokenRefresh() // Connect via adapter (pass tools for providers like ElevenLabs that need them at connect time) - const toolsList = - this.clientTools.size > 0 - ? Array.from(this.clientTools.values()) - : undefined - this.connection = await this.options.adapter.connect( - this.token, - toolsList, - ) + // const toolsList = + // this.clientTools.size > 0 + // ? Array.from(this.clientTools.values()) + // : undefined + + const toolsConfig = this.clientTools.size > 0 + ? Array.from(this.clientTools.values()).map((t) => ({ + name: t.name, + description: t.description, + inputSchema: t.inputSchema + ? convertSchemaToJsonSchema(t.inputSchema) + : undefined, + outputSchema: t.outputSchema + ? convertSchemaToJsonSchema(t.outputSchema) + : undefined, + })) + : undefined + const { + instructions, + voice, + vadMode, + outputModalities, + temperature, + maxOutputTokens, + semanticEagerness, + providerOptions, + } = this.options + + this.connection = await this.options.adapter.connect(this.token, { + instructions, + voice, + vadMode, + outputModalities, + temperature, + maxOutputTokens, + semanticEagerness, + providerOptions, + tools: toolsConfig, + }) // Subscribe to connection events this.subscribeToConnectionEvents() diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts index bffd6df34..6b7880384 100644 --- a/packages/typescript/ai-client/src/realtime-types.ts +++ b/packages/typescript/ai-client/src/realtime-types.ts @@ -25,12 +25,12 @@ export interface RealtimeAdapter { /** * Create a connection using the provided token * @param token - The ephemeral token from the server - * @param clientTools - Optional client-side tools to register with the provider + * @param config - Initial session configuration (voice, instructions, etc.) * @returns A connection instance */ connect: ( token: RealtimeToken, - clientTools?: ReadonlyArray, + config: RealtimeSessionConfig, ) => Promise } @@ -148,6 +148,11 @@ export interface RealtimeClientOptions { */ semanticEagerness?: 'low' | 'medium' | 'high' + /** + * Provider-specific options + */ + providerOptions?: Record + // Callbacks onStatusChange?: (status: RealtimeStatus) => void onModeChange?: (mode: RealtimeMode) => void diff --git a/packages/typescript/ai-gemini/src/index.ts b/packages/typescript/ai-gemini/src/index.ts index 05c46547a..6181ba3c3 100644 --- a/packages/typescript/ai-gemini/src/index.ts +++ b/packages/typescript/ai-gemini/src/index.ts @@ -82,3 +82,9 @@ export type { GeminiDocumentMetadata, GeminiMessageMetadataByModality, } from './message-types' + +// Realtime adapter +export { + geminiRealtime, + geminiRealtimeToken, +} from './realtime/index' diff --git a/packages/typescript/ai-gemini/src/realtime/adapter.ts b/packages/typescript/ai-gemini/src/realtime/adapter.ts index 9be0b5507..1fec9979f 100644 --- a/packages/typescript/ai-gemini/src/realtime/adapter.ts +++ b/packages/typescript/ai-gemini/src/realtime/adapter.ts @@ -1,12 +1,54 @@ +import { GoogleGenAI } from '@google/genai' +import { + convertSchemaToJsonSchema, +} from '@tanstack/ai' +import { generateId } from '../utils' +import type { LiveConnectConfig, Modality } from '@google/genai' import type { AnyClientTool, + AudioVisualization, RealtimeEvent, RealtimeEventHandler, - RealtimeToken, -} from '@tanstack/ai' + RealtimeMessage, + RealtimeMode, + RealtimeSessionConfig, + RealtimeToken +} from "@tanstack/ai" import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client' import type { GeminiRealtimeOptions } from './types' +const textEncoder = new TextEncoder() +const workletCode = ` +class PCMProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.bufferSize = 4096; + this.buffer = new Float32Array(this.bufferSize); + this.bufferIndex = 0; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + if (!input || !input.length) return true; + + const channelData = input[0]; + + for (let i = 0; i < channelData.length; i++) { + this.buffer[this.bufferIndex++] = channelData[i]; + + if (this.bufferIndex >= this.bufferSize) { + this.port.postMessage(this.buffer); + this.bufferIndex = 0; + } + } + + return true; + } +} + +registerProcessor("pcm-processor", PCMProcessor); +` + /** * Creates a Gemini realtime adapter for client-side use. * @@ -32,9 +74,9 @@ export function geminiRealtime( connect( token: RealtimeToken, - _clientTools?: ReadonlyArray, + config: RealtimeSessionConfig ): Promise { - return createWebSocketConnection(token) + return createWebSocketConnection(token, config) }, } } @@ -42,11 +84,516 @@ export function geminiRealtime( /** * Creates a WebSocket connection to Gemini's realtime API */ -function createWebSocketConnection( +async function createWebSocketConnection( token: RealtimeToken, + config: RealtimeSessionConfig, ): Promise { const model = token.config.model ?? 'gemini-live-2.5-flash-native-audio' const eventHandlers = new Map>>() - return new Promise((resolve, reject) => {}) + const responseModalities = config.outputModalities?.map(modality => modality.toUpperCase()) as Array + + const liveConfig: LiveConnectConfig = { + responseModalities, + tools: [{ + functionDeclarations: config.tools + }], + speechConfig: { + voiceConfig: { + prebuiltVoiceConfig: { + voiceName: config.voice + } + } + }, + maxOutputTokens: config.maxOutputTokens !== 'inf' ? config.maxOutputTokens : undefined, + systemInstruction: config.instructions, + temperature: config.temperature, + ...config.providerOptions + }; + + // Audio context + let audioContext: AudioContext | null = null + let inputAnalyser: AnalyserNode | null = null + let outputAnalyser: AnalyserNode | null = null + let inputSource: MediaStreamAudioSourceNode | null = null + let localStream: MediaStream | null = null + + // Audio element for playback (more reliable than AudioContext.destination) + let nextPlayTime = 0 + let scheduledSources: Array = [] + // let audioElement: HTMLAudioElement | null = null + + // Current state + let currentMode: RealtimeMode = 'idle' + let currentMessageId: string | null = null + let messageIdCounter = 0 + + // Empty arrays for when visualization isn't available + // frequencyBinCount = fftSize / 2 = 1024 + const emptyFrequencyData = new Uint8Array(1024) + const emptyTimeDomainData = new Uint8Array(2048).fill(128) // 128 is silence + + // Helper to emit events (defined early so it can be used during setup) + function emit( + event: TEvent, + payload: Parameters>[0], + ) { + const handlers = eventHandlers.get(event) + if (handlers) { + for (const handler of handlers) { + handler(payload) + } + } + } + + function generateMessageId(): string { + return `gemini-msg-${Date.now()}-${++messageIdCounter}` + } + + function downsampleBuffer(buffer: Float32Array, sampleRate: number, outSampleRate: number) { + if (outSampleRate === sampleRate) return buffer; + const ratio = sampleRate / outSampleRate; + const newLength = Math.round(buffer.length / ratio); + const result = new Float32Array(newLength); + let offsetResult = 0; + let offsetBuffer = 0; + while (offsetResult < result.length) { + const nextOffsetBuffer = Math.round((offsetResult + 1) * ratio); + let accum = 0, + count = 0; + for ( + let i = offsetBuffer; + i < nextOffsetBuffer && i < buffer.length; + i++ + ) { + accum += buffer[i]!; + count++; + } + result[offsetResult] = accum / count; + offsetResult++; + offsetBuffer = nextOffsetBuffer; + } + return result; + } + + function convertFloat32ToInt16(buffer: Float32Array) { + let l = buffer.length; + const buf = new Int16Array(l); + while (l--) { + buf[l] = Math.min(1, Math.max(-1, buffer[l]!)) * 0x7fff; + } + return buf.toString(); + } + + const ai = new GoogleGenAI({ + apiKey: token.token + }); + + const session = await ai.live.connect({ + model: model, + config: liveConfig, + callbacks: { + onopen() { + emit("status_change", { status: "connected" }) + }, + onclose() { + emit("status_change", { status: "idle" }) + }, + onmessage(response) { + + const content = response.serverContent; + const inputTranscription = content?.inputTranscription; + const outputTranscription = content?.outputTranscription; + + if (response.data) { + // TODO: Decode chunk and play using an `AudioWorklet` or + // buffer them into an AudioContext + + playIncomingAudioChunk(textEncoder.encode(response.data).buffer) + + if (currentMode !== 'speaking') { + currentMode = 'speaking' + emit('mode_change', { mode: 'speaking' }) + } + } + + if ( + inputTranscription && + inputTranscription.text != undefined && + inputTranscription.finished != undefined + ) { + if (inputTranscription.finished && currentMode !== 'thinking') { + currentMode = 'thinking' + emit('mode_change', { mode: 'thinking' }) + } + + emit('transcript', { + isFinal: inputTranscription.finished, + transcript: inputTranscription.text, + role: 'user', + }) + } + + if ( + outputTranscription && + outputTranscription.text != undefined && + outputTranscription.finished != undefined + ) { + emit('transcript', { + isFinal: outputTranscription.finished, + transcript: outputTranscription.text, + role: 'assistant', + }) + } + + if (response.toolCall?.functionCalls) { + + for (const fc of response.toolCall.functionCalls) { + if (!fc.id || !fc.name) { + continue; + } + emit('tool_call', { + toolCallId: fc.id, + input: fc.args, + toolName: fc.name + }) + } + } + + if (response.serverContent?.turnComplete) { + currentMode = 'listening' + emit('mode_change', { mode: 'listening' }) + + if (response.serverContent.modelTurn?.role == 'model') { + currentMessageId = generateMessageId() + const message: RealtimeMessage = { + id: currentMessageId, + role: 'assistant', + timestamp: Date.now(), + parts: [] + } + + for (const item of response.serverContent.modelTurn.parts || []) { + if (item.text) { + message.parts.push({ + type: 'audio', + transcript: item.text + }) + } + } + + emit('message_complete', { message }) + } + + } + }, + onerror(event) { + emit("error", { + error: new Error(event.message) + }) + }, + } + }); + + // Request microphone access + try { + localStream = await navigator.mediaDevices.getUserMedia({ + audio: { + echoCancellation: true, + noiseSuppression: true, + sampleRate: 24000, + }, + }) + } catch (error) { + throw new Error( + `Microphone access required for realtime voice: ${error instanceof Error ? error.message : error}`, + ) + } + + // Set up audio analysis now that we have the stream + await setupAudioAnalysis(localStream) + + // Set up audio analysis for input + async function setupAudioAnalysis(stream: MediaStream) { + if (!audioContext) { + // Best to specify Gemini's 16kHz here if possible for the whole context + audioContext = new AudioContext() + + const blob = new Blob([workletCode], { type: 'application/javascript' }) + const workletUrl = URL.createObjectURL(blob) + + await audioContext.audioWorklet.addModule(workletUrl) + } + + // Resume AudioContext if suspended (browsers require user interaction) + if (audioContext.state === 'suspended') { + audioContext.resume().catch(() => { + // Ignore - visualization just won't work + }) + } + + // 1. Setup Input (Microphone) Analyser + inputAnalyser = audioContext.createAnalyser() + inputAnalyser.fftSize = 2048 // Larger size for more accurate level detection + inputAnalyser.smoothingTimeConstant = 0.3 + + inputSource = audioContext.createMediaStreamSource(stream) + inputSource.connect(inputAnalyser) + + // 2. Setup Output (Gemini) Analyser + outputAnalyser = audioContext.createAnalyser() + outputAnalyser.fftSize = 2048 + outputAnalyser.smoothingTimeConstant = 0.3 + + // Connect output analyser directly to speakers + outputAnalyser.connect(audioContext.destination) + + const source = audioContext.createMediaStreamSource( + stream + ); + const audioWorkletNode = new AudioWorkletNode( + audioContext, + "pcm-processor" + ); + + audioWorkletNode.port.onmessage = (event) => { + if (currentMode === 'listening') { + const downsampled = downsampleBuffer( + event.data, + audioContext!.sampleRate, + 16000 + ); + const pcm16 = convertFloat32ToInt16(downsampled); + session.sendRealtimeInput({ + audio: { + data: pcm16, + mimeType: 'audio/pcm;rate=16000' + } + }) + } + }; + + source.connect(audioWorkletNode); + } + + // Play incoming audio chunk from WebSocket connection + function playIncomingAudioChunk(arrayBuffer: ArrayBuffer) { + if (!audioContext) return + if (audioContext.state === 'suspended') { + audioContext.resume().catch(() => { + // Ignore - visualization just won't work + }) + } + + const pcmData = new Int16Array(arrayBuffer) + const float32Data = new Float32Array(pcmData.length) + for (let i = 0; i < pcmData.length; i++) { + float32Data[i] = pcmData[i]! / 32768.0; + } + + const buffer = audioContext.createBuffer(1, float32Data.length, 24000); + buffer.getChannelData(0).set(float32Data); + + const source = audioContext.createBufferSource(); + source.buffer = buffer; + if (outputAnalyser) { + source.connect(outputAnalyser) + } else { + source.connect(audioContext.destination); + } + + const now = audioContext.currentTime; + nextPlayTime = Math.max(now, nextPlayTime); + source.start(nextPlayTime); + nextPlayTime += buffer.duration; + + scheduledSources.push(source); + source.onended = () => { + const idx = scheduledSources.indexOf(source); + if (idx > -1) scheduledSources.splice(idx, 1); + }; + } + + const connection: RealtimeConnection = { + async disconnect() { + if (localStream) { + for (const track of localStream.getTracks()) { + track.stop() + } + localStream = null + } + + if (audioContext) { + await audioContext.close() + audioContext = null + } + + await session.close(); + + currentMode = 'idle' + emit('status_change', { status: 'idle' }) + }, + + async startAudioCapture() { + // Audio capture is established during connection setup + // This method enables the tracks and signals listening mode + if (localStream) { + for (const track of localStream.getAudioTracks()) { + track.enabled = true + } + } + currentMode = 'listening' + emit('mode_change', { mode: 'listening' }) + }, + + stopAudioCapture() { + // Disable tracks rather than stopping them to allow re-enabling + if (localStream) { + for (const track of localStream.getAudioTracks()) { + track.enabled = false + } + } + currentMode = 'idle' + emit('mode_change', { mode: 'idle' }) + }, + + sendText(text: string) { + session.sendRealtimeInput({ text }) + currentMode = 'thinking' + emit('mode_change', { mode: 'thinking' }) + }, + + sendImage(imageData: string, mimeType: string) { + // Only accepts raw image data, not URLs + session.sendRealtimeInput({ + media: { + data: imageData, + mimeType: mimeType, + } + }) + currentMode = 'thinking' + emit('mode_change', { mode: 'thinking' }) + }, + + sendToolResult(callId: string, result: string) { + session.sendToolResponse({ + functionResponses: { + id: callId, + response: { + result + } + } + }) + }, + + updateSession() { + // No equivalent of updateSession() exists dynamically as it does in OpenAI + // for updating system instructions, tools, etc mid-session. + }, + + interrupt() { + scheduledSources.forEach((s) => { + try { + s.stop(); + } catch (e) { } + }); + scheduledSources = []; + if (audioContext) { + nextPlayTime = audioContext.currentTime; + } + + currentMode = 'listening' + emit('mode_change', { mode: 'listening' }) + emit('interrupted', { messageId: currentMessageId ?? undefined }) + }, + + on( + event: TEvent, + handler: RealtimeEventHandler + ): () => void { + if (!eventHandlers.has(event)) { + eventHandlers.set(event, new Set()); + } + eventHandlers.get(event)!.add(handler) + + return () => { + eventHandlers.get(event)!.delete(handler) + } + }, + + getAudioVisualization(): AudioVisualization { + // Helper to calculate audio level from time domain data + // Uses peak amplitude which is more responsive for voice audio meters + function calculateLevel(analyser: AnalyserNode): number { + const data = new Uint8Array(analyser.fftSize) + analyser.getByteTimeDomainData(data) + + // Find peak deviation from center (128 is silence) + // This is more responsive than RMS for voice level meters + let maxDeviation = 0 + for (const sample of data) { + const deviation = Math.abs(sample - 128) + if (deviation > maxDeviation) { + maxDeviation = deviation + } + } + + // Normalize to 0-1 range (max deviation is 128) + // Scale by 1.5x so that ~66% amplitude reads as full scale + // This provides good visual feedback without pegging too early + const normalized = maxDeviation / 128 + return Math.min(1, normalized * 1.5) + } + + return { + get inputLevel() { + if (!inputAnalyser) return 0 + return calculateLevel(inputAnalyser) + }, + + get outputLevel() { + if (!outputAnalyser) return 0 + return calculateLevel(outputAnalyser) + }, + + getInputFrequencyData() { + if (!inputAnalyser) return emptyFrequencyData + const data = new Uint8Array(inputAnalyser.frequencyBinCount) + inputAnalyser.getByteFrequencyData(data) + return data + }, + + getOutputFrequencyData() { + if (!outputAnalyser) return emptyFrequencyData + const data = new Uint8Array(outputAnalyser.frequencyBinCount) + outputAnalyser.getByteFrequencyData(data) + return data + }, + + getInputTimeDomainData() { + if (!inputAnalyser) return emptyTimeDomainData + const data = new Uint8Array(inputAnalyser.fftSize) + inputAnalyser.getByteTimeDomainData(data) + return data + }, + + getOutputTimeDomainData() { + if (!outputAnalyser) return emptyTimeDomainData + const data = new Uint8Array(outputAnalyser.fftSize) + outputAnalyser.getByteTimeDomainData(data) + return data + }, + + get inputSampleRate() { + return 24000 + }, + + get outputSampleRate() { + return 24000 + }, + } + }, + } + + return connection; } diff --git a/packages/typescript/ai-gemini/src/realtime/types.ts b/packages/typescript/ai-gemini/src/realtime/types.ts index 8cef9b310..c9ea619db 100644 --- a/packages/typescript/ai-gemini/src/realtime/types.ts +++ b/packages/typescript/ai-gemini/src/realtime/types.ts @@ -1,7 +1,45 @@ + +/** + * Gemini realtime voice options + */ +export type GeminiRealtimeVoice = + | "Achernar" + | "Achird" + | "Algenib" + | "Algieba" + | "Alnilam" + | "Aoede" + | "Autonoe" + | "Callirrhoe" + | "Charon" + | "Despina" + | "Enceladus" + | "Erinome" + | "Fenrir" + | "Gacrux" + | "Iapetus" + | "Kore" + | "Laomedeia" + | "Leda" + | "Orus" + | "Pulcherrima" + | "Puck" + | "Rasalgethi" + | "Sadachbia" + | "Sadaltager" + | "Schedar" + | "Sulafat" + | "Umbriel" + | "Vindemiatrix" + | "Zephyr" + | "Zubenelgenubi"; + /** * Gemini realtime model options */ -export type GeminiRealtimeModel = 'gemini-live-2.5-flash-native-audio' +export type GeminiRealtimeModel = + | 'gemini-3.1-flash-live-preview' + | 'gemini-2.5-flash-native-audio-preview-12-2025' /** * Options for the Gemini realtime client adapter diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts index 35187a5d2..9ac6b82ec 100644 --- a/packages/typescript/ai-openai/src/realtime/adapter.ts +++ b/packages/typescript/ai-openai/src/realtime/adapter.ts @@ -43,10 +43,10 @@ export function openaiRealtime( async connect( token: RealtimeToken, - _clientTools?: ReadonlyArray, + config: RealtimeSessionConfig, ): Promise { if (connectionMode === 'webrtc') { - return createWebRTCConnection(token) + return createWebRTCConnection(token, config) } throw new Error('WebSocket connection mode not yet implemented') }, @@ -58,6 +58,7 @@ export function openaiRealtime( */ async function createWebRTCConnection( token: RealtimeToken, + config: RealtimeSessionConfig, ): Promise { const model = token.config.model ?? 'gpt-4o-realtime-preview' const eventHandlers = new Map>>() diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts index daaf6f57c..62c08b8f4 100644 --- a/packages/typescript/ai/src/realtime/types.ts +++ b/packages/typescript/ai/src/realtime/types.ts @@ -22,6 +22,7 @@ export interface RealtimeToolConfig { name: string description: string inputSchema?: Record + outputSchema?: Record } /** From dadfae943dac4b384d3ba0242788b44e7e94ab10 Mon Sep 17 00:00:00 2001 From: Nikas Belogolov Date: Mon, 13 Apr 2026 22:44:33 +0300 Subject: [PATCH 5/7] Added gemini live option to example --- examples/ts-react-chat/src/lib/use-realtime.ts | 15 +++++++++++++-- examples/ts-react-chat/src/routes/realtime.tsx | 5 +++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/ts-react-chat/src/lib/use-realtime.ts b/examples/ts-react-chat/src/lib/use-realtime.ts index 848c702ca..1970083c9 100644 --- a/examples/ts-react-chat/src/lib/use-realtime.ts +++ b/examples/ts-react-chat/src/lib/use-realtime.ts @@ -6,9 +6,10 @@ import { elevenlabsRealtime, elevenlabsRealtimeToken, } from '@tanstack/ai-elevenlabs' +import { geminiRealtime, geminiRealtimeToken } from '@tanstack/ai-gemini' import { realtimeClientTools } from '@/lib/realtime-tools' -type Provider = 'openai' | 'elevenlabs' +type Provider = 'openai' | 'elevenlabs' | 'gemini' const getRealtimeTokenFn = createServerFn({ method: 'POST' }) .inputValidator((data: { provider: Provider; agentId?: string }) => { @@ -24,6 +25,12 @@ const getRealtimeTokenFn = createServerFn({ method: 'POST' }) }) } + if (data.provider === 'gemini') { + return realtimeToken({ + adapter: geminiRealtimeToken(), + }) + } + if (data.provider === 'elevenlabs') { const agentId = data.agentId || process.env.ELEVENLABS_AGENT_ID if (!agentId) { @@ -55,7 +62,11 @@ export function useRealtime({ semanticEagerness?: 'low' | 'medium' | 'high' }) { const adapter = - provider === 'openai' ? openaiRealtime() : elevenlabsRealtime() + provider === 'openai' + ? openaiRealtime() + : provider === 'gemini' + ? geminiRealtime() + : elevenlabsRealtime() return useRealtimeChat({ getToken: () => diff --git a/examples/ts-react-chat/src/routes/realtime.tsx b/examples/ts-react-chat/src/routes/realtime.tsx index 3225249e2..9b95cec80 100644 --- a/examples/ts-react-chat/src/routes/realtime.tsx +++ b/examples/ts-react-chat/src/routes/realtime.tsx @@ -13,11 +13,12 @@ import { import { AudioSparkline } from '@/components/AudioSparkline' import { useRealtime } from '@/lib/use-realtime' -type Provider = 'openai' | 'elevenlabs' +type Provider = 'openai' | 'elevenlabs' | 'gemini' type OutputMode = 'audio+text' | 'text-only' | 'audio-only' const PROVIDER_OPTIONS: Array<{ value: Provider; label: string }> = [ { value: 'openai', label: 'OpenAI Realtime' }, + { value: 'gemini', label: 'Google Gemini' }, { value: 'elevenlabs', label: 'ElevenLabs' }, ] @@ -275,7 +276,7 @@ function RealtimePage() { {/* Tools indicator */} - {provider === 'openai' && ( + {(provider === 'openai' || provider === 'gemini') && (
From 07114415808715272d1432e70d91afe804950a5f Mon Sep 17 00:00:00 2001 From: Nikas Belogolov Date: Mon, 13 Apr 2026 23:11:22 +0300 Subject: [PATCH 6/7] Fixed refactoring of realtime client --- .../ai-client/src/realtime-client.ts | 59 ++++++++----------- .../ai-client/src/realtime-types.ts | 1 + .../ai-elevenlabs/src/realtime/adapter.ts | 4 +- .../ai-gemini/src/realtime/adapter.ts | 37 ++++++++---- .../ai-openai/src/realtime/adapter.ts | 14 ++--- 5 files changed, 60 insertions(+), 55 deletions(-) diff --git a/packages/typescript/ai-client/src/realtime-client.ts b/packages/typescript/ai-client/src/realtime-client.ts index fc63c1109..861c88e52 100644 --- a/packages/typescript/ai-client/src/realtime-client.ts +++ b/packages/typescript/ai-client/src/realtime-client.ts @@ -96,23 +96,11 @@ export class RealtimeClient { this.scheduleTokenRefresh() // Connect via adapter (pass tools for providers like ElevenLabs that need them at connect time) - // const toolsList = - // this.clientTools.size > 0 - // ? Array.from(this.clientTools.values()) - // : undefined - - const toolsConfig = this.clientTools.size > 0 - ? Array.from(this.clientTools.values()).map((t) => ({ - name: t.name, - description: t.description, - inputSchema: t.inputSchema - ? convertSchemaToJsonSchema(t.inputSchema) - : undefined, - outputSchema: t.outputSchema - ? convertSchemaToJsonSchema(t.outputSchema) - : undefined, - })) - : undefined + const toolsList = + this.clientTools.size > 0 + ? Array.from(this.clientTools.values()) + : undefined + const { instructions, voice, @@ -124,17 +112,20 @@ export class RealtimeClient { providerOptions, } = this.options - this.connection = await this.options.adapter.connect(this.token, { - instructions, - voice, - vadMode, - outputModalities, - temperature, - maxOutputTokens, - semanticEagerness, - providerOptions, - tools: toolsConfig, - }) + this.connection = await this.options.adapter.connect( + this.token, + { + instructions, + voice, + vadMode, + outputModalities, + temperature, + maxOutputTokens, + semanticEagerness, + providerOptions, + }, + toolsList, + ) // Subscribe to connection events this.subscribeToConnectionEvents() @@ -531,12 +522,12 @@ export class RealtimeClient { const toolsConfig = tools ? Array.from(this.clientTools.values()).map((t) => ({ - name: t.name, - description: t.description, - inputSchema: t.inputSchema - ? convertSchemaToJsonSchema(t.inputSchema) - : undefined, - })) + name: t.name, + description: t.description, + inputSchema: t.inputSchema + ? convertSchemaToJsonSchema(t.inputSchema) + : undefined, + })) : undefined this.connection.updateSession({ diff --git a/packages/typescript/ai-client/src/realtime-types.ts b/packages/typescript/ai-client/src/realtime-types.ts index 6b7880384..c33dd8b14 100644 --- a/packages/typescript/ai-client/src/realtime-types.ts +++ b/packages/typescript/ai-client/src/realtime-types.ts @@ -31,6 +31,7 @@ export interface RealtimeAdapter { connect: ( token: RealtimeToken, config: RealtimeSessionConfig, + clientTools?: ReadonlyArray, ) => Promise } diff --git a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts index 33bc5344e..4a341a4ad 100644 --- a/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts +++ b/packages/typescript/ai-elevenlabs/src/realtime/adapter.ts @@ -40,9 +40,10 @@ export function elevenlabsRealtime( async connect( token: RealtimeToken, + _config: RealtimeSessionConfig, clientToolDefs?: ReadonlyArray, ): Promise { - return createElevenLabsConnection(token, options, clientToolDefs) + return createElevenLabsConnection(token, clientToolDefs) }, } } @@ -52,7 +53,6 @@ export function elevenlabsRealtime( */ async function createElevenLabsConnection( token: RealtimeToken, - _options: ElevenLabsRealtimeOptions, clientToolDefs?: ReadonlyArray, ): Promise { const eventHandlers = new Map>>() diff --git a/packages/typescript/ai-gemini/src/realtime/adapter.ts b/packages/typescript/ai-gemini/src/realtime/adapter.ts index 1fec9979f..45b3270dd 100644 --- a/packages/typescript/ai-gemini/src/realtime/adapter.ts +++ b/packages/typescript/ai-gemini/src/realtime/adapter.ts @@ -1,11 +1,8 @@ import { GoogleGenAI } from '@google/genai' import { convertSchemaToJsonSchema, -} from '@tanstack/ai' -import { generateId } from '../utils' -import type { LiveConnectConfig, Modality } from '@google/genai' +} from "@tanstack/ai" import type { - AnyClientTool, AudioVisualization, RealtimeEvent, RealtimeEventHandler, @@ -13,8 +10,9 @@ import type { RealtimeMode, RealtimeSessionConfig, RealtimeToken -} from "@tanstack/ai" -import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client' +} from '@tanstack/ai' +import type { LiveConnectConfig, Modality } from '@google/genai' +import type { AnyClientTool, RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client' import type { GeminiRealtimeOptions } from './types' const textEncoder = new TextEncoder() @@ -74,9 +72,10 @@ export function geminiRealtime( connect( token: RealtimeToken, - config: RealtimeSessionConfig + config: RealtimeSessionConfig, + clientTools?: ReadonlyArray, ): Promise { - return createWebSocketConnection(token, config) + return createWebSocketConnection(token, config, clientTools) }, } } @@ -87,17 +86,31 @@ export function geminiRealtime( async function createWebSocketConnection( token: RealtimeToken, config: RealtimeSessionConfig, + tools?: ReadonlyArray, ): Promise { const model = token.config.model ?? 'gemini-live-2.5-flash-native-audio' const eventHandlers = new Map>>() const responseModalities = config.outputModalities?.map(modality => modality.toUpperCase()) as Array + const toolsConfig = tools + ? tools.map((t) => ({ + name: t.name, + description: t.description, + inputSchema: t.inputSchema + ? convertSchemaToJsonSchema(t.inputSchema) + : undefined, + outputSchema: t.outputSchema + ? convertSchemaToJsonSchema(t.outputSchema) + : undefined, + })) + : undefined + const liveConfig: LiveConnectConfig = { responseModalities, - tools: [{ - functionDeclarations: config.tools - }], + tools: toolsConfig ? [{ + functionDeclarations: toolsConfig + }] : undefined, speechConfig: { voiceConfig: { prebuiltVoiceConfig: { @@ -587,7 +600,7 @@ async function createWebSocketConnection( get inputSampleRate() { return 24000 }, - + get outputSampleRate() { return 24000 }, diff --git a/packages/typescript/ai-openai/src/realtime/adapter.ts b/packages/typescript/ai-openai/src/realtime/adapter.ts index 9ac6b82ec..d10128e70 100644 --- a/packages/typescript/ai-openai/src/realtime/adapter.ts +++ b/packages/typescript/ai-openai/src/realtime/adapter.ts @@ -7,7 +7,7 @@ import type { RealtimeMode, RealtimeSessionConfig, RealtimeStatus, - RealtimeToken, + RealtimeToken } from '@tanstack/ai' import type { RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client' import type { OpenAIRealtimeOptions } from './types' @@ -43,10 +43,11 @@ export function openaiRealtime( async connect( token: RealtimeToken, - config: RealtimeSessionConfig, + _config: RealtimeSessionConfig, + _clientTools?: ReadonlyArray, ): Promise { if (connectionMode === 'webrtc') { - return createWebRTCConnection(token, config) + return createWebRTCConnection(token) } throw new Error('WebSocket connection mode not yet implemented') }, @@ -58,7 +59,6 @@ export function openaiRealtime( */ async function createWebRTCConnection( token: RealtimeToken, - config: RealtimeSessionConfig, ): Promise { const model = token.config.model ?? 'gpt-4o-realtime-preview' const eventHandlers = new Map>>() @@ -490,9 +490,9 @@ async function createWebRTCConnection( const imageContent = isUrl ? { type: 'input_image', image_url: imageData } : { - type: 'input_image', - image_url: `data:${mimeType};base64,${imageData}`, - } + type: 'input_image', + image_url: `data:${mimeType};base64,${imageData}`, + } sendEvent({ type: 'conversation.item.create', From 5bd8d46d6f7b91d83b0110ab30bb315d1bf3159d Mon Sep 17 00:00:00 2001 From: Nikas Belogolov Date: Wed, 15 Apr 2026 11:45:18 +0300 Subject: [PATCH 7/7] Bug fixes, added go_away event, more gemini live provider config options --- .../ts-react-chat/src/lib/use-realtime.ts | 8 +++- packages/typescript/ai-gemini/src/index.ts | 18 +++++--- .../ai-gemini/src/realtime/adapter.ts | 41 ++++++++++++++----- .../ai-gemini/src/realtime/index.ts | 1 + .../ai-gemini/src/realtime/token.ts | 2 +- .../ai-gemini/src/realtime/types.ts | 12 +++++- packages/typescript/ai/src/realtime/types.ts | 2 + 7 files changed, 64 insertions(+), 20 deletions(-) diff --git a/examples/ts-react-chat/src/lib/use-realtime.ts b/examples/ts-react-chat/src/lib/use-realtime.ts index 1970083c9..2ac96c6b5 100644 --- a/examples/ts-react-chat/src/lib/use-realtime.ts +++ b/examples/ts-react-chat/src/lib/use-realtime.ts @@ -7,12 +7,14 @@ import { elevenlabsRealtimeToken, } from '@tanstack/ai-elevenlabs' import { geminiRealtime, geminiRealtimeToken } from '@tanstack/ai-gemini' +import type { GeminiRealtimeVoice } from "@tanstack/ai-gemini" +import type { OpenAIRealtimeVoice } from "@tanstack/ai-openai" import { realtimeClientTools } from '@/lib/realtime-tools' type Provider = 'openai' | 'elevenlabs' | 'gemini' const getRealtimeTokenFn = createServerFn({ method: 'POST' }) - .inputValidator((data: { provider: Provider; agentId?: string }) => { + .inputValidator((data: { provider?: Provider; agentId?: string }) => { if (!data.provider) throw new Error('Provider is required') return data }) @@ -53,6 +55,7 @@ export function useRealtime({ temperature, maxOutputTokens, semanticEagerness, + voice }: { provider: Provider agentId: string @@ -60,6 +63,7 @@ export function useRealtime({ temperature?: number maxOutputTokens?: number | 'inf' semanticEagerness?: 'low' | 'medium' | 'high' + voice?: OpenAIRealtimeVoice | GeminiRealtimeVoice }) { const adapter = provider === 'openai' @@ -89,7 +93,7 @@ Keep your responses concise and conversational since this is a voice interface. When using tools, briefly explain what you're doing and then share the results naturally. If the user sends an image, describe what you see and answer any questions about it. Be friendly and engaging!`, - voice: 'alloy', + voice: voice || provider === 'gemini' ? 'Puck' : 'alloy', tools: realtimeClientTools, outputModalities, temperature, diff --git a/packages/typescript/ai-gemini/src/index.ts b/packages/typescript/ai-gemini/src/index.ts index 6181ba3c3..75ae77e54 100644 --- a/packages/typescript/ai-gemini/src/index.ts +++ b/packages/typescript/ai-gemini/src/index.ts @@ -83,8 +83,16 @@ export type { GeminiMessageMetadataByModality, } from './message-types' -// Realtime adapter -export { - geminiRealtime, - geminiRealtimeToken, -} from './realtime/index' +// ============================================================================ +// Realtime (Voice) Adapters +// ============================================================================ + +export { geminiRealtime, geminiRealtimeToken } from './realtime/index' + +export type { + GeminiRealtimeModel, + GeminiRealtimeOptions, + GeminiRealtimeTokenOptions, + GeminiRealtimeVoice, + GeminiRealtimeEvent +} from './realtime/index' \ No newline at end of file diff --git a/packages/typescript/ai-gemini/src/realtime/adapter.ts b/packages/typescript/ai-gemini/src/realtime/adapter.ts index 45b3270dd..eb9ac3032 100644 --- a/packages/typescript/ai-gemini/src/realtime/adapter.ts +++ b/packages/typescript/ai-gemini/src/realtime/adapter.ts @@ -1,4 +1,4 @@ -import { GoogleGenAI } from '@google/genai' +import { GoogleGenAI, Modality } from '@google/genai' import { convertSchemaToJsonSchema, } from "@tanstack/ai" @@ -11,9 +11,9 @@ import type { RealtimeSessionConfig, RealtimeToken } from '@tanstack/ai' -import type { LiveConnectConfig, Modality } from '@google/genai' +import type { LiveConnectConfig } from '@google/genai' import type { AnyClientTool, RealtimeAdapter, RealtimeConnection } from '@tanstack/ai-client' -import type { GeminiRealtimeOptions } from './types' +import type { GeminiRealtimeOptions, GeminiRealtimeProviderOptions } from './types' const textEncoder = new TextEncoder() const workletCode = ` @@ -91,8 +91,6 @@ async function createWebSocketConnection( const model = token.config.model ?? 'gemini-live-2.5-flash-native-audio' const eventHandlers = new Map>>() - const responseModalities = config.outputModalities?.map(modality => modality.toUpperCase()) as Array - const toolsConfig = tools ? tools.map((t) => ({ name: t.name, @@ -106,8 +104,18 @@ async function createWebSocketConnection( })) : undefined + const { + languageCode, + contextWindowCompression, + proactivity, + enableAffectiveDialog, + thinkingConfig + } = config.providerOptions as GeminiRealtimeProviderOptions + + config.outputModalities + const liveConfig: LiveConnectConfig = { - responseModalities, + responseModalities: [Modality.AUDIO], tools: toolsConfig ? [{ functionDeclarations: toolsConfig }] : undefined, @@ -116,14 +124,23 @@ async function createWebSocketConnection( prebuiltVoiceConfig: { voiceName: config.voice } - } + }, + languageCode }, maxOutputTokens: config.maxOutputTokens !== 'inf' ? config.maxOutputTokens : undefined, systemInstruction: config.instructions, temperature: config.temperature, - ...config.providerOptions + contextWindowCompression, + proactivity, + enableAffectiveDialog, + thinkingConfig, }; + if (config.outputModalities?.includes("text")) { + liveConfig.inputAudioTranscription = {} + liveConfig.outputAudioTranscription = {} + } + // Audio context let audioContext: AudioContext | null = null let inputAnalyser: AnalyserNode | null = null @@ -218,6 +235,10 @@ async function createWebSocketConnection( const inputTranscription = content?.inputTranscription; const outputTranscription = content?.outputTranscription; + if (response.goAway) { + emit("go_away", { timeLeft: response.goAway.timeLeft }) + } + if (response.data) { // TODO: Decode chunk and play using an `AudioWorklet` or // buffer them into an AudioContext @@ -479,9 +500,9 @@ async function createWebSocketConnection( sendImage(imageData: string, mimeType: string) { // Only accepts raw image data, not URLs session.sendRealtimeInput({ - media: { + video: { data: imageData, - mimeType: mimeType, + mimeType: mimeType } }) currentMode = 'thinking' diff --git a/packages/typescript/ai-gemini/src/realtime/index.ts b/packages/typescript/ai-gemini/src/realtime/index.ts index be743cb47..1291c083c 100644 --- a/packages/typescript/ai-gemini/src/realtime/index.ts +++ b/packages/typescript/ai-gemini/src/realtime/index.ts @@ -7,6 +7,7 @@ export { geminiRealtime } from './adapter' // Types export type { GeminiRealtimeModel, + GeminiRealtimeVoice, GeminiRealtimeTokenOptions, GeminiRealtimeOptions, } from './types' diff --git a/packages/typescript/ai-gemini/src/realtime/token.ts b/packages/typescript/ai-gemini/src/realtime/token.ts index edeb43f9c..5d6ac18f7 100644 --- a/packages/typescript/ai-gemini/src/realtime/token.ts +++ b/packages/typescript/ai-gemini/src/realtime/token.ts @@ -39,7 +39,7 @@ export function geminiRealtimeToken( provider: 'gemini', async generateToken(): Promise { const model: GeminiRealtimeModel = - options.model ?? 'gemini-live-2.5-flash-native-audio' + options.model ?? 'gemini-3.1-flash-live-preview' const token = await client.authTokens.create({ config: { diff --git a/packages/typescript/ai-gemini/src/realtime/types.ts b/packages/typescript/ai-gemini/src/realtime/types.ts index c9ea619db..cb89d29d1 100644 --- a/packages/typescript/ai-gemini/src/realtime/types.ts +++ b/packages/typescript/ai-gemini/src/realtime/types.ts @@ -1,3 +1,4 @@ +import type { ContextWindowCompressionConfig, ProactivityConfig, ThinkingConfig } from "@google/genai"; /** * Gemini realtime voice options @@ -60,6 +61,13 @@ export interface GeminiRealtimeTokenOptions { } /** - * Gemini Realtime session response from the API + * Gemini Realtime provider options */ -export interface GeminiRealtimeSessionResponse {} + +export interface GeminiRealtimeProviderOptions { + languageCode?: string + contextWindowCompression?: ContextWindowCompressionConfig + proactivity?: ProactivityConfig + enableAffectiveDialog?: boolean, + thinkingConfig?: ThinkingConfig +} \ No newline at end of file diff --git a/packages/typescript/ai/src/realtime/types.ts b/packages/typescript/ai/src/realtime/types.ts index 62c08b8f4..9310fb660 100644 --- a/packages/typescript/ai/src/realtime/types.ts +++ b/packages/typescript/ai/src/realtime/types.ts @@ -245,6 +245,7 @@ export type RealtimeEvent = | 'message_complete' | 'interrupted' | 'error' + | 'go_away' // Event that signals that the current connection will soon be terminated /** * Event payloads for realtime events @@ -262,6 +263,7 @@ export interface RealtimeEventPayloads { message_complete: { message: RealtimeMessage } interrupted: { messageId?: string } error: { error: Error } + go_away: { timeLeft: string } } /**