@tanstack/ai-gemini 0.17.3 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/package.json +5 -4
  2. package/src/experimental/text-interactions/adapter.ts +304 -100
  3. package/src/experimental/text-interactions/events.ts +29 -23
  4. package/src/experimental/text-interactions/provider-options.ts +0 -1
  5. package/dist/esm/adapters/audio.d.ts +0 -92
  6. package/dist/esm/adapters/audio.js +0 -66
  7. package/dist/esm/adapters/audio.js.map +0 -1
  8. package/dist/esm/adapters/image.d.ts +0 -101
  9. package/dist/esm/adapters/image.js +0 -253
  10. package/dist/esm/adapters/image.js.map +0 -1
  11. package/dist/esm/adapters/summarize.d.ts +0 -33
  12. package/dist/esm/adapters/summarize.js +0 -18
  13. package/dist/esm/adapters/summarize.js.map +0 -1
  14. package/dist/esm/adapters/text.d.ts +0 -85
  15. package/dist/esm/adapters/text.js +0 -658
  16. package/dist/esm/adapters/text.js.map +0 -1
  17. package/dist/esm/adapters/tts.d.ts +0 -165
  18. package/dist/esm/adapters/tts.js +0 -192
  19. package/dist/esm/adapters/tts.js.map +0 -1
  20. package/dist/esm/adapters/video.d.ts +0 -108
  21. package/dist/esm/adapters/video.js +0 -227
  22. package/dist/esm/adapters/video.js.map +0 -1
  23. package/dist/esm/experimental/index.d.ts +0 -6
  24. package/dist/esm/experimental/index.js +0 -7
  25. package/dist/esm/experimental/index.js.map +0 -1
  26. package/dist/esm/experimental/text-interactions/adapter.d.ts +0 -75
  27. package/dist/esm/experimental/text-interactions/adapter.js +0 -899
  28. package/dist/esm/experimental/text-interactions/adapter.js.map +0 -1
  29. package/dist/esm/experimental/text-interactions/events.d.ts +0 -141
  30. package/dist/esm/experimental/text-interactions/provider-options.d.ts +0 -15
  31. package/dist/esm/image/image-provider-options.d.ts +0 -181
  32. package/dist/esm/image/image-provider-options.js +0 -67
  33. package/dist/esm/image/image-provider-options.js.map +0 -1
  34. package/dist/esm/index.d.ts +0 -33
  35. package/dist/esm/index.js +0 -38
  36. package/dist/esm/index.js.map +0 -1
  37. package/dist/esm/message-types.d.ts +0 -104
  38. package/dist/esm/model-meta.d.ts +0 -242
  39. package/dist/esm/model-meta.js +0 -159
  40. package/dist/esm/model-meta.js.map +0 -1
  41. package/dist/esm/text/text-provider-options.d.ts +0 -196
  42. package/dist/esm/tools/code-execution-tool.d.ts +0 -10
  43. package/dist/esm/tools/code-execution-tool.js +0 -18
  44. package/dist/esm/tools/code-execution-tool.js.map +0 -1
  45. package/dist/esm/tools/computer-use-tool.d.ts +0 -13
  46. package/dist/esm/tools/computer-use-tool.js +0 -33
  47. package/dist/esm/tools/computer-use-tool.js.map +0 -1
  48. package/dist/esm/tools/file-search-tool.d.ts +0 -10
  49. package/dist/esm/tools/file-search-tool.js +0 -19
  50. package/dist/esm/tools/file-search-tool.js.map +0 -1
  51. package/dist/esm/tools/function-declaration-tool.d.ts +0 -5
  52. package/dist/esm/tools/function-declaration-tool.js +0 -28
  53. package/dist/esm/tools/function-declaration-tool.js.map +0 -1
  54. package/dist/esm/tools/google-maps-tool.d.ts +0 -10
  55. package/dist/esm/tools/google-maps-tool.js +0 -19
  56. package/dist/esm/tools/google-maps-tool.js.map +0 -1
  57. package/dist/esm/tools/google-search-retriveal-tool.d.ts +0 -10
  58. package/dist/esm/tools/google-search-retriveal-tool.js +0 -19
  59. package/dist/esm/tools/google-search-retriveal-tool.js.map +0 -1
  60. package/dist/esm/tools/google-search-tool.d.ts +0 -10
  61. package/dist/esm/tools/google-search-tool.js +0 -19
  62. package/dist/esm/tools/google-search-tool.js.map +0 -1
  63. package/dist/esm/tools/index.d.ts +0 -18
  64. package/dist/esm/tools/index.js +0 -21
  65. package/dist/esm/tools/index.js.map +0 -1
  66. package/dist/esm/tools/tool-converter.d.ts +0 -22
  67. package/dist/esm/tools/tool-converter.js +0 -66
  68. package/dist/esm/tools/tool-converter.js.map +0 -1
  69. package/dist/esm/tools/url-context-tool.d.ts +0 -10
  70. package/dist/esm/tools/url-context-tool.js +0 -18
  71. package/dist/esm/tools/url-context-tool.js.map +0 -1
  72. package/dist/esm/usage.d.ts +0 -67
  73. package/dist/esm/usage.js +0 -94
  74. package/dist/esm/usage.js.map +0 -1
  75. package/dist/esm/utils/client.d.ts +0 -17
  76. package/dist/esm/utils/client.js +0 -30
  77. package/dist/esm/utils/client.js.map +0 -1
  78. package/dist/esm/utils/index.d.ts +0 -1
  79. package/dist/esm/video/video-provider-options.d.ts +0 -90
  80. package/dist/esm/video/video-provider-options.js +0 -15
  81. package/dist/esm/video/video-provider-options.js.map +0 -1
@@ -1,227 +0,0 @@
1
- import { VideoGenerationReferenceType, GenerateVideosOperation } from "@google/genai";
2
- import { resolveMediaPrompt } from "@tanstack/ai";
3
- import { BaseVideoAdapter, snapToDurationOption } from "@tanstack/ai/adapters";
4
- import { arrayBufferToBase64 } from "@tanstack/ai-utils";
5
- import { createGeminiClient, getGeminiApiKeyFromEnv } from "../utils/client.js";
6
- import { getGeminiVideoDurationOptions } from "../video/video-provider-options.js";
7
- function operationErrorMessage(error) {
8
- if (typeof error.message === "string" && error.message.length > 0) {
9
- return error.message;
10
- }
11
- return JSON.stringify(error);
12
- }
13
- async function imagePartToVeoImage(part) {
14
- if (part.source.type === "data") {
15
- return {
16
- imageBytes: part.source.value,
17
- mimeType: part.source.mimeType || "image/png"
18
- };
19
- }
20
- const url = part.source.value;
21
- if (url.startsWith("gs://")) {
22
- return {
23
- gcsUri: url,
24
- ...part.source.mimeType && { mimeType: part.source.mimeType }
25
- };
26
- }
27
- if (url.startsWith("data:")) {
28
- const match = url.match(/^data:([^;,]+)?(;base64)?,(.*)$/);
29
- if (!match || !match[2]) {
30
- throw new Error(
31
- "gemini: only base64 data: URIs are supported for video image inputs."
32
- );
33
- }
34
- return {
35
- imageBytes: match[3] ?? "",
36
- mimeType: match[1] || part.source.mimeType || "image/png"
37
- };
38
- }
39
- const response = await fetch(url);
40
- if (!response.ok) {
41
- throw new Error(
42
- `Failed to fetch image input (${response.status} ${response.statusText}): ${url}`
43
- );
44
- }
45
- const blob = await response.blob();
46
- const buffer = await blob.arrayBuffer();
47
- return {
48
- imageBytes: arrayBufferToBase64(buffer),
49
- mimeType: part.source.mimeType || blob.type || "image/png"
50
- };
51
- }
52
- class GeminiVideoAdapter extends BaseVideoAdapter {
53
- name = "gemini";
54
- client;
55
- constructor(config, model) {
56
- super({}, model);
57
- this.client = createGeminiClient(config);
58
- }
59
- async createVideoJob(options) {
60
- const { prompt, size, duration, modelOptions, logger } = options;
61
- logger.request(
62
- `activity=video.create provider=${this.name} model=${this.model} size=${size ?? "default"} duration=${duration ?? "default"}`,
63
- { provider: this.name, model: this.model }
64
- );
65
- try {
66
- const resolved = resolveMediaPrompt(prompt);
67
- if (resolved.videos.length > 0) {
68
- throw new Error(
69
- `${this.name}.createVideoJob does not support video prompt parts (model: ${this.model}).`
70
- );
71
- }
72
- if (resolved.audios.length > 0) {
73
- throw new Error(
74
- `${this.name}.createVideoJob does not support audio prompt parts (model: ${this.model}).`
75
- );
76
- }
77
- const { image, lastFrame, referenceImages } = await this.routeImageParts(
78
- resolved.images
79
- );
80
- const config = {
81
- ...modelOptions,
82
- ...size !== void 0 && { aspectRatio: size },
83
- ...duration !== void 0 && { durationSeconds: duration },
84
- ...lastFrame && { lastFrame },
85
- ...referenceImages.length > 0 && { referenceImages }
86
- };
87
- const operation = await this.client.models.generateVideos({
88
- model: this.model,
89
- prompt: resolved.text,
90
- ...image && { image },
91
- config
92
- });
93
- if (!operation.name) {
94
- throw new Error(
95
- "Veo did not return an operation name for the video generation job."
96
- );
97
- }
98
- return { jobId: operation.name, model: this.model };
99
- } catch (error) {
100
- logger.errors(`${this.name}.createVideoJob fatal`, {
101
- error,
102
- source: `${this.name}.createVideoJob`
103
- });
104
- throw error;
105
- }
106
- }
107
- /**
108
- * Route image prompt parts onto Veo's request fields by `metadata.role`.
109
- */
110
- async routeImageParts(parts) {
111
- let image;
112
- let lastFrame;
113
- const referenceImages = [];
114
- for (const part of parts) {
115
- const role = part.metadata?.role;
116
- switch (role) {
117
- case "end_frame": {
118
- if (lastFrame) {
119
- throw new Error(
120
- `${this.name}: Veo accepts at most one 'end_frame' image.`
121
- );
122
- }
123
- lastFrame = await imagePartToVeoImage(part);
124
- break;
125
- }
126
- case "reference":
127
- case "character": {
128
- referenceImages.push({
129
- image: await imagePartToVeoImage(part),
130
- referenceType: VideoGenerationReferenceType.ASSET
131
- });
132
- break;
133
- }
134
- case "start_frame":
135
- case void 0: {
136
- if (image) {
137
- throw new Error(
138
- `${this.name}: Veo accepts at most one starting image; received multiple 'start_frame'/un-roled images. Use metadata.role ('end_frame', 'reference') to disambiguate the others.`
139
- );
140
- }
141
- image = await imagePartToVeoImage(part);
142
- break;
143
- }
144
- case "mask":
145
- case "control":
146
- throw new Error(
147
- `${this.name}: unsupported image role "${role}" for Veo video generation.`
148
- );
149
- }
150
- }
151
- return { image, lastFrame, referenceImages };
152
- }
153
- async getVideoStatus(jobId) {
154
- const operation = await this.getOperation(jobId);
155
- if (!operation.done) {
156
- return { jobId, status: "processing" };
157
- }
158
- if (operation.error) {
159
- return {
160
- jobId,
161
- status: "failed",
162
- error: operationErrorMessage(operation.error)
163
- };
164
- }
165
- const videos = operation.response?.generatedVideos ?? [];
166
- if (videos.length === 0) {
167
- const reasons = operation.response?.raiMediaFilteredReasons;
168
- return {
169
- jobId,
170
- status: "failed",
171
- error: reasons?.length ? `Video was filtered by Responsible-AI: ${reasons.join("; ")}` : "Veo returned no generated videos."
172
- };
173
- }
174
- return { jobId, status: "completed" };
175
- }
176
- async getVideoUrl(jobId) {
177
- const operation = await this.getOperation(jobId);
178
- if (!operation.done) {
179
- throw new Error(
180
- `Video is not ready yet. Check status first. Job ID: ${jobId}`
181
- );
182
- }
183
- if (operation.error) {
184
- throw new Error(
185
- `Video generation failed: ${operationErrorMessage(operation.error)}`
186
- );
187
- }
188
- const uri = operation.response?.generatedVideos?.[0]?.video?.uri;
189
- if (!uri) {
190
- const reasons = operation.response?.raiMediaFilteredReasons;
191
- throw new Error(
192
- reasons?.length ? `Video was filtered by Responsible-AI: ${reasons.join("; ")}` : `Video URL not found in operation response. Job ID: ${jobId}`
193
- );
194
- }
195
- return { jobId, url: uri };
196
- }
197
- availableDurations() {
198
- return getGeminiVideoDurationOptions(this.model);
199
- }
200
- snapDuration(seconds) {
201
- return snapToDurationOption(seconds, this.availableDurations());
202
- }
203
- /**
204
- * Fetch the long-running operation by name. The SDK's
205
- * `operations.getVideosOperation` needs a real `GenerateVideosOperation`
206
- * instance (it calls `_fromAPIResponse` on it), so reconstruct one from
207
- * the job ID rather than passing an object literal.
208
- */
209
- async getOperation(jobId) {
210
- const operation = new GenerateVideosOperation();
211
- operation.name = jobId;
212
- return await this.client.operations.getVideosOperation({ operation });
213
- }
214
- }
215
- function createGeminiVideo(model, apiKey, config) {
216
- return new GeminiVideoAdapter({ apiKey, ...config }, model);
217
- }
218
- function geminiVideo(model, config) {
219
- const apiKey = getGeminiApiKeyFromEnv();
220
- return createGeminiVideo(model, apiKey, config);
221
- }
222
- export {
223
- GeminiVideoAdapter,
224
- createGeminiVideo,
225
- geminiVideo
226
- };
227
- //# sourceMappingURL=video.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"video.js","sources":["../../../src/adapters/video.ts"],"sourcesContent":["import {\n GenerateVideosOperation,\n VideoGenerationReferenceType,\n} from '@google/genai'\nimport { resolveMediaPrompt } from '@tanstack/ai'\nimport { BaseVideoAdapter, snapToDurationOption } from '@tanstack/ai/adapters'\nimport { arrayBufferToBase64 } from '@tanstack/ai-utils'\nimport { createGeminiClient, getGeminiApiKeyFromEnv } from '../utils'\nimport { getGeminiVideoDurationOptions } from '../video/video-provider-options'\nimport type { DurationOptions } from '@tanstack/ai/adapters'\nimport type {\n ImagePart,\n MediaInputMetadata,\n VideoGenerationOptions,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '@tanstack/ai'\nimport type {\n GenerateVideosConfig,\n GoogleGenAI,\n Image,\n VideoGenerationReferenceImage,\n} from '@google/genai'\nimport type {\n GeminiVideoModel,\n GeminiVideoModelDurationByName,\n GeminiVideoModelInputModalitiesByName,\n GeminiVideoModelProviderOptionsByName,\n GeminiVideoModelSizeByName,\n GeminiVideoProviderOptions,\n GeminiVideoSize,\n} from '../video/video-provider-options'\nimport type { GeminiClientConfig } from '../utils'\n\n/**\n * Configuration for Gemini video adapter.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface GeminiVideoConfig extends GeminiClientConfig {}\n\n/**\n * Extract a human-readable message from a long-running operation's error,\n * which the SDK types as `Record<string, unknown>` (a google.rpc.Status).\n */\nfunction operationErrorMessage(error: Record<string, unknown>): string {\n if (typeof error.message === 'string' && error.message.length > 0) {\n return error.message\n }\n return JSON.stringify(error)\n}\n\n/**\n * Convert a TanStack image prompt part into the genai `Image` shape Veo\n * accepts: base64 `imageBytes` (data sources, data: URIs, fetched HTTP\n * URLs) or a `gcsUri` passthrough for Cloud Storage references.\n */\nasync function imagePartToVeoImage(\n part: ImagePart<MediaInputMetadata>,\n): Promise<Image> {\n if (part.source.type === 'data') {\n return {\n imageBytes: part.source.value,\n mimeType: part.source.mimeType || 'image/png',\n }\n }\n const url = part.source.value\n if (url.startsWith('gs://')) {\n return {\n gcsUri: url,\n ...(part.source.mimeType && { mimeType: part.source.mimeType }),\n }\n }\n if (url.startsWith('data:')) {\n const match = url.match(/^data:([^;,]+)?(;base64)?,(.*)$/)\n if (!match || !match[2]) {\n throw new Error(\n 'gemini: only base64 data: URIs are supported for video image inputs.',\n )\n }\n return {\n imageBytes: match[3] ?? '',\n mimeType: match[1] || part.source.mimeType || 'image/png',\n }\n }\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(\n `Failed to fetch image input (${response.status} ${response.statusText}): ${url}`,\n )\n }\n const blob = await response.blob()\n const buffer = await blob.arrayBuffer()\n return {\n imageBytes: arrayBufferToBase64(buffer),\n mimeType: part.source.mimeType || blob.type || 'image/png',\n }\n}\n\n/**\n * Gemini Veo Video Generation Adapter\n *\n * Tree-shakeable adapter for Google Veo video generation. Veo runs as a\n * long-running operation: `createVideoJob` starts the operation via the\n * `:predictLongRunning` endpoint, `getVideoStatus` polls it, and\n * `getVideoUrl` extracts the generated video's URI once it completes.\n *\n * Image prompt parts are routed by `metadata.role`:\n * - `'start_frame'` (or the first un-roled image) → the input image the\n * video starts from\n * - `'end_frame'` → `lastFrame` (the frame the video ends on)\n * - `'reference'` / `'character'` → `referenceImages` (asset references,\n * Veo 3.1)\n *\n * Note: the returned video URI is served by the Gemini Files API and\n * requires the API key (`x-goog-api-key` header or `?key=` query\n * parameter) to download.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport class GeminiVideoAdapter<\n TModel extends GeminiVideoModel,\n> extends BaseVideoAdapter<\n TModel,\n GeminiVideoProviderOptions,\n GeminiVideoModelProviderOptionsByName,\n GeminiVideoModelSizeByName,\n GeminiVideoModelInputModalitiesByName,\n GeminiVideoModelDurationByName\n> {\n readonly name = 'gemini' as const\n\n protected client: GoogleGenAI\n\n constructor(config: GeminiVideoConfig, model: TModel) {\n super({}, model)\n this.client = createGeminiClient(config)\n }\n\n async createVideoJob(\n options: VideoGenerationOptions<\n GeminiVideoProviderOptions,\n GeminiVideoSize,\n GeminiVideoModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult> {\n const { prompt, size, duration, modelOptions, logger } = options\n\n logger.request(\n `activity=video.create provider=${this.name} model=${this.model} size=${size ?? 'default'} duration=${duration ?? 'default'}`,\n { provider: this.name, model: this.model },\n )\n\n try {\n const resolved = resolveMediaPrompt(prompt)\n\n if (resolved.videos.length > 0) {\n throw new Error(\n `${this.name}.createVideoJob does not support video prompt parts (model: ${this.model}).`,\n )\n }\n if (resolved.audios.length > 0) {\n throw new Error(\n `${this.name}.createVideoJob does not support audio prompt parts (model: ${this.model}).`,\n )\n }\n\n const { image, lastFrame, referenceImages } = await this.routeImageParts(\n resolved.images,\n )\n\n const config: GenerateVideosConfig = {\n ...modelOptions,\n ...(size !== undefined && { aspectRatio: size }),\n ...(duration !== undefined && { durationSeconds: duration }),\n ...(lastFrame && { lastFrame }),\n ...(referenceImages.length > 0 && { referenceImages }),\n }\n\n const operation = await this.client.models.generateVideos({\n model: this.model,\n prompt: resolved.text,\n ...(image && { image }),\n config,\n })\n\n if (!operation.name) {\n throw new Error(\n 'Veo did not return an operation name for the video generation job.',\n )\n }\n\n return { jobId: operation.name, model: this.model }\n } catch (error) {\n logger.errors(`${this.name}.createVideoJob fatal`, {\n error,\n source: `${this.name}.createVideoJob`,\n })\n throw error\n }\n }\n\n /**\n * Route image prompt parts onto Veo's request fields by `metadata.role`.\n */\n private async routeImageParts(\n parts: Array<ImagePart<MediaInputMetadata>>,\n ): Promise<{\n image: Image | undefined\n lastFrame: Image | undefined\n referenceImages: Array<VideoGenerationReferenceImage>\n }> {\n let image: Image | undefined\n let lastFrame: Image | undefined\n const referenceImages: Array<VideoGenerationReferenceImage> = []\n\n for (const part of parts) {\n const role = part.metadata?.role\n switch (role) {\n case 'end_frame': {\n if (lastFrame) {\n throw new Error(\n `${this.name}: Veo accepts at most one 'end_frame' image.`,\n )\n }\n lastFrame = await imagePartToVeoImage(part)\n break\n }\n case 'reference':\n case 'character': {\n referenceImages.push({\n image: await imagePartToVeoImage(part),\n referenceType: VideoGenerationReferenceType.ASSET,\n })\n break\n }\n case 'start_frame':\n case undefined: {\n if (image) {\n throw new Error(\n `${this.name}: Veo accepts at most one starting image; received multiple 'start_frame'/un-roled images. Use metadata.role ('end_frame', 'reference') to disambiguate the others.`,\n )\n }\n image = await imagePartToVeoImage(part)\n break\n }\n case 'mask':\n case 'control':\n throw new Error(\n `${this.name}: unsupported image role \"${role}\" for Veo video generation.`,\n )\n }\n }\n\n return { image, lastFrame, referenceImages }\n }\n\n async getVideoStatus(jobId: string): Promise<VideoStatusResult> {\n const operation = await this.getOperation(jobId)\n\n if (!operation.done) {\n return { jobId, status: 'processing' }\n }\n\n if (operation.error) {\n return {\n jobId,\n status: 'failed',\n error: operationErrorMessage(operation.error),\n }\n }\n\n // The operation can finish \"successfully\" with every sample dropped by\n // Responsible-AI filters — surface that as a failure instead of letting\n // getVideoUrl() throw on an empty response.\n const videos = operation.response?.generatedVideos ?? []\n if (videos.length === 0) {\n const reasons = operation.response?.raiMediaFilteredReasons\n return {\n jobId,\n status: 'failed',\n error: reasons?.length\n ? `Video was filtered by Responsible-AI: ${reasons.join('; ')}`\n : 'Veo returned no generated videos.',\n }\n }\n\n return { jobId, status: 'completed' }\n }\n\n async getVideoUrl(jobId: string): Promise<VideoUrlResult> {\n const operation = await this.getOperation(jobId)\n\n if (!operation.done) {\n throw new Error(\n `Video is not ready yet. Check status first. Job ID: ${jobId}`,\n )\n }\n\n if (operation.error) {\n throw new Error(\n `Video generation failed: ${operationErrorMessage(operation.error)}`,\n )\n }\n\n const uri = operation.response?.generatedVideos?.[0]?.video?.uri\n if (!uri) {\n const reasons = operation.response?.raiMediaFilteredReasons\n throw new Error(\n reasons?.length\n ? `Video was filtered by Responsible-AI: ${reasons.join('; ')}`\n : `Video URL not found in operation response. Job ID: ${jobId}`,\n )\n }\n\n return { jobId, url: uri }\n }\n\n override availableDurations(): DurationOptions<\n GeminiVideoModelDurationByName[TModel]\n > {\n return getGeminiVideoDurationOptions(this.model)\n }\n\n override snapDuration(\n seconds: number,\n ): GeminiVideoModelDurationByName[TModel] | undefined {\n return snapToDurationOption(seconds, this.availableDurations())\n }\n\n /**\n * Fetch the long-running operation by name. The SDK's\n * `operations.getVideosOperation` needs a real `GenerateVideosOperation`\n * instance (it calls `_fromAPIResponse` on it), so reconstruct one from\n * the job ID rather than passing an object literal.\n */\n private async getOperation(jobId: string): Promise<GenerateVideosOperation> {\n const operation = new GenerateVideosOperation()\n operation.name = jobId\n return await this.client.operations.getVideosOperation({ operation })\n }\n}\n\n/**\n * Creates a Gemini video adapter with an explicit API key.\n * Type resolution happens here at the call site.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @param model - The model name (e.g., 'veo-3.1-generate-preview')\n * @param apiKey - Your Google API key\n * @param config - Optional additional configuration\n * @returns Configured Gemini video adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGeminiVideo('veo-3.1-generate-preview', 'your-api-key');\n *\n * const { jobId } = await generateVideo({\n * adapter,\n * prompt: 'A beautiful sunset over the ocean',\n * duration: adapter.snapDuration(7), // → 6\n * });\n * ```\n */\nexport function createGeminiVideo<TModel extends GeminiVideoModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GeminiVideoConfig, 'apiKey'>,\n): GeminiVideoAdapter<TModel> {\n return new GeminiVideoAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Gemini video adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `GOOGLE_API_KEY` or `GEMINI_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @param model - The model name (e.g., 'veo-3.1-generate-preview')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Gemini video adapter instance with resolved types\n * @throws Error if GOOGLE_API_KEY or GEMINI_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses GOOGLE_API_KEY from environment\n * const adapter = geminiVideo('veo-3.1-generate-preview');\n *\n * // Create a video generation job\n * const { jobId } = await generateVideo({\n * adapter,\n * prompt: 'A cat playing piano'\n * });\n *\n * // Poll for status\n * const status = await getVideoJobStatus({ adapter, jobId });\n * ```\n */\nexport function geminiVideo<TModel extends GeminiVideoModel>(\n model: TModel,\n config?: Omit<GeminiVideoConfig, 'apiKey'>,\n): GeminiVideoAdapter<TModel> {\n const apiKey = getGeminiApiKeyFromEnv()\n return createGeminiVideo(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +0,0 @@
1
- /**
2
- * @experimental Gemini's Interactions API is in Beta per Google. Shapes and
3
- * behavior may change between minor releases of `@tanstack/ai-gemini`.
4
- */
5
- export { GeminiTextInteractionsAdapter, createGeminiTextInteractions, geminiTextInteractions, type GeminiTextInteractionsConfig, type GeminiTextInteractionsProviderOptions, type GeminiInteractionsStream, } from './text-interactions/adapter.js';
6
- export type { GeminiInteractionsCustomEvent, GeminiInteractionsCustomEventName, GeminiInteractionsCustomEventValue, } from './text-interactions/events.js';
@@ -1,7 +0,0 @@
1
- import { GeminiTextInteractionsAdapter, createGeminiTextInteractions, geminiTextInteractions } from "./text-interactions/adapter.js";
2
- export {
3
- GeminiTextInteractionsAdapter,
4
- createGeminiTextInteractions,
5
- geminiTextInteractions
6
- };
7
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,75 +0,0 @@
1
- import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from '@tanstack/ai/adapters';
2
- import { GeminiChatModelToolCapabilitiesByName, GeminiModelInputModalitiesByName, GeminiModels } from '../../model-meta.js';
3
- import { Modality, StreamChunk, TextOptions } from '@tanstack/ai';
4
- import { GeminiInteractionsStream } from './events.js';
5
- import { ExternalTextInteractionsProviderOptions } from './provider-options.js';
6
- import { GeminiMessageMetadataByModality } from '../../message-types.js';
7
- import { GeminiClientConfig } from '../../utils.js';
8
- export type GeminiTextInteractionsConfig = GeminiClientConfig;
9
- export type GeminiTextInteractionsProviderOptions = ExternalTextInteractionsProviderOptions;
10
- /**
11
- * Resolve provider options for a specific model. The Interactions API's
12
- * request shape is the same across all chat-capable Gemini models — the
13
- * SDK doesn't expose a per-model param union — so this currently falls
14
- * through to the flat `GeminiTextInteractionsProviderOptions` for every
15
- * model. The alias exists for parity with `GeminiTextAdapter`, so a
16
- * per-model map can be slotted in later without changing the adapter
17
- * signature.
18
- */
19
- type ResolveProviderOptions = GeminiTextInteractionsProviderOptions;
20
- /**
21
- * Resolve input modalities for a specific model. Reuses the chat-model
22
- * modality map from `model-meta.ts`: passing a `document` content block
23
- * to a model that doesn't support it is a compile error, matching the
24
- * sibling `GeminiTextAdapter`.
25
- */
26
- type ResolveInputModalities<TModel extends string> = TModel extends keyof GeminiModelInputModalitiesByName ? GeminiModelInputModalitiesByName[TModel] : readonly ['text', 'image', 'audio', 'video', 'document'];
27
- /**
28
- * Resolve tool capabilities for a specific model. Reuses the chat-model
29
- * capability map: `google_maps` / `google_search_retrieval` /
30
- * `mcp_server` are rejected at runtime by `convertToolsToInteractionsFormat`,
31
- * but per-model gating happens here at compile time.
32
- */
33
- type ResolveToolCapabilities<TModel extends string> = TModel extends keyof GeminiChatModelToolCapabilitiesByName ? NonNullable<GeminiChatModelToolCapabilitiesByName[TModel]> : readonly [];
34
- /**
35
- * Tree-shakeable adapter for Gemini's stateful Interactions API. Routes
36
- * through `client.interactions.create` and surfaces the server-assigned
37
- * `interactionId` via an AG-UI `CUSTOM` event with
38
- * `name: 'gemini.interactionId'` emitted just before `RUN_FINISHED`; pass
39
- * that id back on the next turn via `modelOptions.previous_interaction_id`
40
- * to continue the conversation without resending history.
41
- *
42
- * The Interactions API does NOT support stateless multi-turn replay —
43
- * passing more than one message in `messages` without a
44
- * `previous_interaction_id` throws. For a chat UI that maintains local
45
- * history (e.g. `useChat`), see the "Wiring with `useChat`" section of
46
- * `docs/adapters/gemini.md` for the canonical client/server pattern.
47
- *
48
- * Supports user-defined function tools and the built-in tools
49
- * `google_search`, `code_execution`, `url_context`, `file_search`, and
50
- * `computer_use`. Built-in tool *activity* for the four search/exec
51
- * variants is surfaced via `CUSTOM` events
52
- * (`gemini.googleSearchCall` / `gemini.googleSearchResult` and the
53
- * corresponding per-tool variants) carrying the raw Interactions delta;
54
- * see {@link GeminiInteractionsCustomEvent}. `computer_use` is accepted
55
- * in the request but the Interactions API does not currently stream
56
- * per-delta CUSTOM events for it. `google_search_retrieval`,
57
- * `google_maps`, and `mcp_server` are not supported on this adapter.
58
- *
59
- * @experimental Interactions API is in Beta per Google; shapes may change.
60
- * @see https://ai.google.dev/gemini-api/docs/interactions
61
- */
62
- export declare class GeminiTextInteractionsAdapter<TModel extends GeminiModels, TProviderOptions extends Record<string, any> = ResolveProviderOptions, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends BaseTextAdapter<TModel, TProviderOptions, TInputModalities, GeminiMessageMetadataByModality, TToolCapabilities> {
63
- readonly kind: "text";
64
- readonly name: "gemini-text-interactions";
65
- private readonly client;
66
- private readonly interactionIdByThread;
67
- constructor(config: GeminiTextInteractionsConfig, model: TModel);
68
- chatStream(options: TextOptions<GeminiTextInteractionsProviderOptions>): AsyncIterable<StreamChunk>;
69
- structuredOutput(options: StructuredOutputOptions<GeminiTextInteractionsProviderOptions>): Promise<StructuredOutputResult<unknown>>;
70
- }
71
- /** @experimental Interactions API is in Beta. */
72
- export declare function createGeminiTextInteractions<TModel extends GeminiModels>(model: TModel, apiKey: string, config?: Omit<GeminiTextInteractionsConfig, 'apiKey'>): GeminiTextInteractionsAdapter<TModel, ResolveProviderOptions, ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>>;
73
- /** @experimental Interactions API is in Beta. */
74
- export declare function geminiTextInteractions<TModel extends GeminiModels>(model: TModel, config?: Omit<GeminiTextInteractionsConfig, 'apiKey'>): GeminiTextInteractionsAdapter<TModel, ResolveProviderOptions, ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>>;
75
- export type { GeminiInteractionsStream };