@tanstack/ai-gemini 0.18.1 → 0.18.3

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 (78) hide show
  1. package/dist/esm/adapters/audio.d.ts +92 -0
  2. package/dist/esm/adapters/audio.js +66 -0
  3. package/dist/esm/adapters/audio.js.map +1 -0
  4. package/dist/esm/adapters/image.d.ts +101 -0
  5. package/dist/esm/adapters/image.js +253 -0
  6. package/dist/esm/adapters/image.js.map +1 -0
  7. package/dist/esm/adapters/summarize.d.ts +33 -0
  8. package/dist/esm/adapters/summarize.js +18 -0
  9. package/dist/esm/adapters/summarize.js.map +1 -0
  10. package/dist/esm/adapters/text.d.ts +85 -0
  11. package/dist/esm/adapters/text.js +658 -0
  12. package/dist/esm/adapters/text.js.map +1 -0
  13. package/dist/esm/adapters/tts.d.ts +165 -0
  14. package/dist/esm/adapters/tts.js +192 -0
  15. package/dist/esm/adapters/tts.js.map +1 -0
  16. package/dist/esm/adapters/video.d.ts +108 -0
  17. package/dist/esm/adapters/video.js +227 -0
  18. package/dist/esm/adapters/video.js.map +1 -0
  19. package/dist/esm/experimental/index.d.ts +6 -0
  20. package/dist/esm/experimental/index.js +7 -0
  21. package/dist/esm/experimental/index.js.map +1 -0
  22. package/dist/esm/experimental/text-interactions/adapter.d.ts +75 -0
  23. package/dist/esm/experimental/text-interactions/adapter.js +1052 -0
  24. package/dist/esm/experimental/text-interactions/adapter.js.map +1 -0
  25. package/dist/esm/experimental/text-interactions/events.d.ts +147 -0
  26. package/dist/esm/experimental/text-interactions/provider-options.d.ts +15 -0
  27. package/dist/esm/image/image-provider-options.d.ts +181 -0
  28. package/dist/esm/image/image-provider-options.js +67 -0
  29. package/dist/esm/image/image-provider-options.js.map +1 -0
  30. package/dist/esm/index.d.ts +33 -0
  31. package/dist/esm/index.js +38 -0
  32. package/dist/esm/index.js.map +1 -0
  33. package/dist/esm/message-types.d.ts +104 -0
  34. package/dist/esm/model-meta.d.ts +242 -0
  35. package/dist/esm/model-meta.js +159 -0
  36. package/dist/esm/model-meta.js.map +1 -0
  37. package/dist/esm/text/text-provider-options.d.ts +196 -0
  38. package/dist/esm/tools/code-execution-tool.d.ts +10 -0
  39. package/dist/esm/tools/code-execution-tool.js +18 -0
  40. package/dist/esm/tools/code-execution-tool.js.map +1 -0
  41. package/dist/esm/tools/computer-use-tool.d.ts +13 -0
  42. package/dist/esm/tools/computer-use-tool.js +33 -0
  43. package/dist/esm/tools/computer-use-tool.js.map +1 -0
  44. package/dist/esm/tools/file-search-tool.d.ts +10 -0
  45. package/dist/esm/tools/file-search-tool.js +19 -0
  46. package/dist/esm/tools/file-search-tool.js.map +1 -0
  47. package/dist/esm/tools/function-declaration-tool.d.ts +5 -0
  48. package/dist/esm/tools/function-declaration-tool.js +28 -0
  49. package/dist/esm/tools/function-declaration-tool.js.map +1 -0
  50. package/dist/esm/tools/google-maps-tool.d.ts +10 -0
  51. package/dist/esm/tools/google-maps-tool.js +19 -0
  52. package/dist/esm/tools/google-maps-tool.js.map +1 -0
  53. package/dist/esm/tools/google-search-retriveal-tool.d.ts +10 -0
  54. package/dist/esm/tools/google-search-retriveal-tool.js +19 -0
  55. package/dist/esm/tools/google-search-retriveal-tool.js.map +1 -0
  56. package/dist/esm/tools/google-search-tool.d.ts +10 -0
  57. package/dist/esm/tools/google-search-tool.js +19 -0
  58. package/dist/esm/tools/google-search-tool.js.map +1 -0
  59. package/dist/esm/tools/index.d.ts +18 -0
  60. package/dist/esm/tools/index.js +21 -0
  61. package/dist/esm/tools/index.js.map +1 -0
  62. package/dist/esm/tools/tool-converter.d.ts +22 -0
  63. package/dist/esm/tools/tool-converter.js +66 -0
  64. package/dist/esm/tools/tool-converter.js.map +1 -0
  65. package/dist/esm/tools/url-context-tool.d.ts +10 -0
  66. package/dist/esm/tools/url-context-tool.js +18 -0
  67. package/dist/esm/tools/url-context-tool.js.map +1 -0
  68. package/dist/esm/usage.d.ts +67 -0
  69. package/dist/esm/usage.js +94 -0
  70. package/dist/esm/usage.js.map +1 -0
  71. package/dist/esm/utils/client.d.ts +17 -0
  72. package/dist/esm/utils/client.js +30 -0
  73. package/dist/esm/utils/client.js.map +1 -0
  74. package/dist/esm/utils/index.d.ts +1 -0
  75. package/dist/esm/video/video-provider-options.d.ts +90 -0
  76. package/dist/esm/video/video-provider-options.js +15 -0
  77. package/dist/esm/video/video-provider-options.js.map +1 -0
  78. package/package.json +4 -4
@@ -0,0 +1,18 @@
1
+ import { brandProviderTool } from "@tanstack/ai";
2
+ function convertUrlContextToolToAdapterFormat(_tool) {
3
+ return {
4
+ urlContext: {}
5
+ };
6
+ }
7
+ function urlContextTool() {
8
+ return brandProviderTool({
9
+ name: "url_context",
10
+ description: "",
11
+ metadata: {}
12
+ });
13
+ }
14
+ export {
15
+ convertUrlContextToolToAdapterFormat,
16
+ urlContextTool
17
+ };
18
+ //# sourceMappingURL=url-context-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-context-tool.js","sources":["../../../src/tools/url-context-tool.ts"],"sourcesContent":["import { brandProviderTool } from '@tanstack/ai'\nimport type { ProviderTool, Tool } from '@tanstack/ai'\n\nexport interface UrlContextToolConfig {}\n\n/** @deprecated Renamed to `UrlContextToolConfig`. Will be removed in a future release. */\nexport type UrlContextTool = UrlContextToolConfig\n\nexport type GeminiUrlContextTool = ProviderTool<'gemini', 'url_context'>\n\nexport function convertUrlContextToolToAdapterFormat(_tool: Tool) {\n return {\n urlContext: {},\n }\n}\n\nexport function urlContextTool(): GeminiUrlContextTool {\n return brandProviderTool<GeminiUrlContextTool>({\n name: 'url_context',\n description: '',\n metadata: {},\n })\n}\n"],"names":[],"mappings":";AAUO,SAAS,qCAAqC,OAAa;AAChE,SAAO;AAAA,IACL,YAAY,CAAA;AAAA,EAAC;AAEjB;AAEO,SAAS,iBAAuC;AACrD,SAAO,kBAAwC;AAAA,IAC7C,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU,CAAA;AAAA,EAAC,CACZ;AACH;"}
@@ -0,0 +1,67 @@
1
+ import { TokenUsage } from '@tanstack/ai';
2
+ import { GenerateContentResponseUsageMetadata, ModalityTokenCount } from '@google/genai';
3
+ /**
4
+ * Flattened modality token counts for normalized usage reporting.
5
+ * Maps Gemini's ModalityTokenCount array to individual fields.
6
+ */
7
+ export interface FlattenedModalityTokens {
8
+ /** Text tokens */
9
+ textTokens?: number;
10
+ /** Image tokens */
11
+ imageTokens?: number;
12
+ /** Audio tokens */
13
+ audioTokens?: number;
14
+ /** Video tokens */
15
+ videoTokens?: number;
16
+ /** Document tokens (e.g. PDF inputs) */
17
+ documentTokens?: number;
18
+ }
19
+ /**
20
+ * Flattens Gemini's ModalityTokenCount array into individual token fields.
21
+ * Extracts TEXT, IMAGE, AUDIO, VIDEO, DOCUMENT modality counts into a
22
+ * normalized structure.
23
+ */
24
+ export declare function flattenModalityTokenCounts(modalities?: Array<ModalityTokenCount>): FlattenedModalityTokens;
25
+ /**
26
+ * Checks if a FlattenedModalityTokens object has any values set.
27
+ */
28
+ export declare function hasModalityTokens(tokens: FlattenedModalityTokens): boolean;
29
+ /**
30
+ * Gemini-specific provider usage details.
31
+ * These fields are unique to Gemini and placed in providerUsageDetails.
32
+ */
33
+ export type GeminiProviderUsageDetails = {
34
+ /**
35
+ * The traffic type for this request.
36
+ * Can indicate whether request was handled by different service tiers.
37
+ */
38
+ trafficType?: string;
39
+ /**
40
+ * Number of tokens in the results from tool executions,
41
+ * which are provided back to the model as input.
42
+ */
43
+ toolUsePromptTokenCount?: number;
44
+ /**
45
+ * Detailed breakdown by modality of the token counts from
46
+ * the results of tool executions.
47
+ */
48
+ toolUsePromptTokensDetails?: Array<{
49
+ modality: string;
50
+ tokenCount: number;
51
+ }>;
52
+ /**
53
+ * Detailed breakdown of cache tokens by modality.
54
+ * More granular than the normalized cachedTokens field.
55
+ */
56
+ cacheTokensDetails?: Array<{
57
+ modality: string;
58
+ tokenCount: number;
59
+ }>;
60
+ };
61
+ /**
62
+ * Build normalized TokenUsage from Gemini's usageMetadata.
63
+ * Handles modality breakdowns and thinking tokens. Returns `undefined` when the
64
+ * provider reported no usage metadata, so callers omit the field rather than
65
+ * fabricating zeroed totals.
66
+ */
67
+ export declare function buildGeminiUsage(usageMetadata: GenerateContentResponseUsageMetadata | undefined | null): TokenUsage<GeminiProviderUsageDetails> | undefined;
@@ -0,0 +1,94 @@
1
+ import { buildBaseUsage } from "@tanstack/ai";
2
+ function flattenModalityTokenCounts(modalities) {
3
+ if (!modalities || modalities.length === 0) {
4
+ return {};
5
+ }
6
+ const result = {};
7
+ for (const item of modalities) {
8
+ if (!item.modality || item.tokenCount === void 0) {
9
+ continue;
10
+ }
11
+ const modality = item.modality.toUpperCase();
12
+ const count = item.tokenCount;
13
+ switch (modality) {
14
+ case "TEXT":
15
+ result.textTokens = (result.textTokens ?? 0) + count;
16
+ break;
17
+ case "IMAGE":
18
+ result.imageTokens = (result.imageTokens ?? 0) + count;
19
+ break;
20
+ case "AUDIO":
21
+ result.audioTokens = (result.audioTokens ?? 0) + count;
22
+ break;
23
+ case "VIDEO":
24
+ result.videoTokens = (result.videoTokens ?? 0) + count;
25
+ break;
26
+ case "DOCUMENT":
27
+ result.documentTokens = (result.documentTokens ?? 0) + count;
28
+ break;
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+ function hasModalityTokens(tokens) {
34
+ return tokens.textTokens !== void 0 || tokens.imageTokens !== void 0 || tokens.audioTokens !== void 0 || tokens.videoTokens !== void 0 || tokens.documentTokens !== void 0;
35
+ }
36
+ function buildGeminiUsage(usageMetadata) {
37
+ if (!usageMetadata) return void 0;
38
+ const promptTokens = usageMetadata.promptTokenCount ?? 0;
39
+ const completionTokens = usageMetadata.candidatesTokenCount ?? 0;
40
+ const result = buildBaseUsage({
41
+ promptTokens,
42
+ completionTokens,
43
+ totalTokens: usageMetadata.totalTokenCount ?? promptTokens + completionTokens
44
+ });
45
+ const promptModalities = flattenModalityTokenCounts(
46
+ usageMetadata.promptTokensDetails
47
+ );
48
+ const cachedTokens = usageMetadata.cachedContentTokenCount;
49
+ const promptTokensDetails = {
50
+ ...hasModalityTokens(promptModalities) ? promptModalities : {},
51
+ ...cachedTokens !== void 0 && cachedTokens > 0 ? { cachedTokens } : {}
52
+ };
53
+ const completionModalities = flattenModalityTokenCounts(
54
+ usageMetadata.candidatesTokensDetails
55
+ );
56
+ const thoughtsTokens = usageMetadata.thoughtsTokenCount;
57
+ const completionTokensDetails = {
58
+ ...hasModalityTokens(completionModalities) ? completionModalities : {},
59
+ // Map thoughtsTokenCount to reasoningTokens for consistency with OpenAI
60
+ ...thoughtsTokens !== void 0 && thoughtsTokens > 0 ? { reasoningTokens: thoughtsTokens } : {}
61
+ };
62
+ const providerDetails = {
63
+ ...usageMetadata.trafficType ? { trafficType: usageMetadata.trafficType } : {},
64
+ ...usageMetadata.toolUsePromptTokenCount !== void 0 && usageMetadata.toolUsePromptTokenCount > 0 ? { toolUsePromptTokenCount: usageMetadata.toolUsePromptTokenCount } : {},
65
+ ...usageMetadata.toolUsePromptTokensDetails && usageMetadata.toolUsePromptTokensDetails.length > 0 ? {
66
+ toolUsePromptTokensDetails: usageMetadata.toolUsePromptTokensDetails.map((item) => ({
67
+ modality: item.modality || "UNKNOWN",
68
+ tokenCount: item.tokenCount ?? 0
69
+ }))
70
+ } : {},
71
+ ...usageMetadata.cacheTokensDetails && usageMetadata.cacheTokensDetails.length > 0 ? {
72
+ cacheTokensDetails: usageMetadata.cacheTokensDetails.map((item) => ({
73
+ modality: item.modality || "UNKNOWN",
74
+ tokenCount: item.tokenCount ?? 0
75
+ }))
76
+ } : {}
77
+ };
78
+ if (Object.keys(promptTokensDetails).length > 0) {
79
+ result.promptTokensDetails = promptTokensDetails;
80
+ }
81
+ if (Object.keys(providerDetails).length > 0) {
82
+ result.providerUsageDetails = providerDetails;
83
+ }
84
+ if (Object.keys(completionTokensDetails).length > 0) {
85
+ result.completionTokensDetails = completionTokensDetails;
86
+ }
87
+ return result;
88
+ }
89
+ export {
90
+ buildGeminiUsage,
91
+ flattenModalityTokenCounts,
92
+ hasModalityTokens
93
+ };
94
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sources":["../../src/usage.ts"],"sourcesContent":["import { buildBaseUsage } from '@tanstack/ai'\nimport type { TokenUsage } from '@tanstack/ai'\nimport type {\n GenerateContentResponseUsageMetadata,\n ModalityTokenCount,\n} from '@google/genai'\n\n/**\n * Flattened modality token counts for normalized usage reporting.\n * Maps Gemini's ModalityTokenCount array to individual fields.\n */\nexport interface FlattenedModalityTokens {\n /** Text tokens */\n textTokens?: number\n /** Image tokens */\n imageTokens?: number\n /** Audio tokens */\n audioTokens?: number\n /** Video tokens */\n videoTokens?: number\n /** Document tokens (e.g. PDF inputs) */\n documentTokens?: number\n}\n\n/**\n * Flattens Gemini's ModalityTokenCount array into individual token fields.\n * Extracts TEXT, IMAGE, AUDIO, VIDEO, DOCUMENT modality counts into a\n * normalized structure.\n */\nexport function flattenModalityTokenCounts(\n modalities?: Array<ModalityTokenCount>,\n): FlattenedModalityTokens {\n if (!modalities || modalities.length === 0) {\n return {}\n }\n\n const result: FlattenedModalityTokens = {}\n\n for (const item of modalities) {\n if (!item.modality || item.tokenCount === undefined) {\n continue\n }\n\n const modality = item.modality.toUpperCase()\n const count = item.tokenCount\n\n switch (modality) {\n case 'TEXT':\n result.textTokens = (result.textTokens ?? 0) + count\n break\n case 'IMAGE':\n result.imageTokens = (result.imageTokens ?? 0) + count\n break\n case 'AUDIO':\n result.audioTokens = (result.audioTokens ?? 0) + count\n break\n case 'VIDEO':\n result.videoTokens = (result.videoTokens ?? 0) + count\n break\n case 'DOCUMENT':\n result.documentTokens = (result.documentTokens ?? 0) + count\n break\n }\n }\n\n return result\n}\n\n/**\n * Checks if a FlattenedModalityTokens object has any values set.\n */\nexport function hasModalityTokens(tokens: FlattenedModalityTokens): boolean {\n return (\n tokens.textTokens !== undefined ||\n tokens.imageTokens !== undefined ||\n tokens.audioTokens !== undefined ||\n tokens.videoTokens !== undefined ||\n tokens.documentTokens !== undefined\n )\n}\n\n/**\n * Gemini-specific provider usage details.\n * These fields are unique to Gemini and placed in providerUsageDetails.\n */\nexport type GeminiProviderUsageDetails = {\n /**\n * The traffic type for this request.\n * Can indicate whether request was handled by different service tiers.\n */\n trafficType?: string\n /**\n * Number of tokens in the results from tool executions,\n * which are provided back to the model as input.\n */\n toolUsePromptTokenCount?: number\n /**\n * Detailed breakdown by modality of the token counts from\n * the results of tool executions.\n */\n toolUsePromptTokensDetails?: Array<{\n modality: string\n tokenCount: number\n }>\n /**\n * Detailed breakdown of cache tokens by modality.\n * More granular than the normalized cachedTokens field.\n */\n cacheTokensDetails?: Array<{\n modality: string\n tokenCount: number\n }>\n}\n\n/**\n * Build normalized TokenUsage from Gemini's usageMetadata.\n * Handles modality breakdowns and thinking tokens. Returns `undefined` when the\n * provider reported no usage metadata, so callers omit the field rather than\n * fabricating zeroed totals.\n */\nexport function buildGeminiUsage(\n usageMetadata: GenerateContentResponseUsageMetadata | undefined | null,\n): TokenUsage<GeminiProviderUsageDetails> | undefined {\n if (!usageMetadata) return undefined\n\n const promptTokens = usageMetadata.promptTokenCount ?? 0\n const completionTokens = usageMetadata.candidatesTokenCount ?? 0\n\n const result = buildBaseUsage<GeminiProviderUsageDetails>({\n promptTokens: promptTokens,\n completionTokens: completionTokens,\n totalTokens:\n usageMetadata.totalTokenCount ?? promptTokens + completionTokens,\n })\n\n // Add prompt token details\n // Flatten modality breakdown for prompt\n const promptModalities = flattenModalityTokenCounts(\n usageMetadata.promptTokensDetails,\n )\n const cachedTokens = usageMetadata.cachedContentTokenCount\n\n const promptTokensDetails = {\n ...(hasModalityTokens(promptModalities) ? promptModalities : {}),\n ...(cachedTokens !== undefined && cachedTokens > 0 ? { cachedTokens } : {}),\n }\n\n // Add completion token details\n // Flatten modality breakdown for candidates (output)\n const completionModalities = flattenModalityTokenCounts(\n usageMetadata.candidatesTokensDetails,\n )\n const thoughtsTokens = usageMetadata.thoughtsTokenCount\n\n const completionTokensDetails = {\n ...(hasModalityTokens(completionModalities) ? completionModalities : {}),\n // Map thoughtsTokenCount to reasoningTokens for consistency with OpenAI\n ...(thoughtsTokens !== undefined && thoughtsTokens > 0\n ? { reasoningTokens: thoughtsTokens }\n : {}),\n }\n\n // Add provider-specific details\n const providerDetails: GeminiProviderUsageDetails = {\n ...(usageMetadata.trafficType\n ? { trafficType: usageMetadata.trafficType }\n : {}),\n ...(usageMetadata.toolUsePromptTokenCount !== undefined &&\n usageMetadata.toolUsePromptTokenCount > 0\n ? { toolUsePromptTokenCount: usageMetadata.toolUsePromptTokenCount }\n : {}),\n ...(usageMetadata.toolUsePromptTokensDetails &&\n usageMetadata.toolUsePromptTokensDetails.length > 0\n ? {\n toolUsePromptTokensDetails:\n usageMetadata.toolUsePromptTokensDetails.map((item) => ({\n modality: item.modality || 'UNKNOWN',\n tokenCount: item.tokenCount ?? 0,\n })),\n }\n : {}),\n ...(usageMetadata.cacheTokensDetails &&\n usageMetadata.cacheTokensDetails.length > 0\n ? {\n cacheTokensDetails: usageMetadata.cacheTokensDetails.map((item) => ({\n modality: item.modality || 'UNKNOWN',\n tokenCount: item.tokenCount ?? 0,\n })),\n }\n : {}),\n }\n\n // Add prompt token details if available\n if (Object.keys(promptTokensDetails).length > 0) {\n result.promptTokensDetails = promptTokensDetails\n }\n // Add provider details if available\n if (Object.keys(providerDetails).length > 0) {\n result.providerUsageDetails = providerDetails\n }\n // Add completion token details if available\n if (Object.keys(completionTokensDetails).length > 0) {\n result.completionTokensDetails = completionTokensDetails\n }\n\n return result\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { GoogleGenAI, GoogleGenAIOptions } from '@google/genai';
2
+ export interface GeminiClientConfig extends GoogleGenAIOptions {
3
+ apiKey: string;
4
+ }
5
+ /**
6
+ * Creates a Google Generative AI client instance
7
+ */
8
+ export declare function createGeminiClient(config: GeminiClientConfig): GoogleGenAI;
9
+ /**
10
+ * Gets Google API key from environment variables
11
+ * @throws Error if GOOGLE_API_KEY or GEMINI_API_KEY is not found
12
+ */
13
+ export declare function getGeminiApiKeyFromEnv(): string;
14
+ /**
15
+ * Generates a unique ID with a prefix
16
+ */
17
+ export declare function generateId(prefix: string): string;
@@ -0,0 +1,30 @@
1
+ import { GoogleGenAI } from "@google/genai";
2
+ import { generateId as generateId$1, getApiKeyFromEnv } from "@tanstack/ai-utils";
3
+ function createGeminiClient(config) {
4
+ return new GoogleGenAI({
5
+ ...config,
6
+ apiKey: config.apiKey
7
+ });
8
+ }
9
+ function getGeminiApiKeyFromEnv() {
10
+ try {
11
+ return getApiKeyFromEnv("GOOGLE_API_KEY");
12
+ } catch {
13
+ try {
14
+ return getApiKeyFromEnv("GEMINI_API_KEY");
15
+ } catch {
16
+ throw new Error(
17
+ "GOOGLE_API_KEY or GEMINI_API_KEY is not set. Please set one of these environment variables or pass the API key directly."
18
+ );
19
+ }
20
+ }
21
+ }
22
+ function generateId(prefix) {
23
+ return generateId$1(prefix);
24
+ }
25
+ export {
26
+ createGeminiClient,
27
+ generateId,
28
+ getGeminiApiKeyFromEnv
29
+ };
30
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import { GoogleGenAI } from '@google/genai'\nimport { generateId as _generateId, getApiKeyFromEnv } from '@tanstack/ai-utils'\nimport type { GoogleGenAIOptions } from '@google/genai'\n\nexport interface GeminiClientConfig extends GoogleGenAIOptions {\n apiKey: string\n}\n\n/**\n * Creates a Google Generative AI client instance\n */\nexport function createGeminiClient(config: GeminiClientConfig): GoogleGenAI {\n return new GoogleGenAI({\n ...config,\n apiKey: config.apiKey,\n })\n}\n\n/**\n * Gets Google API key from environment variables\n * @throws Error if GOOGLE_API_KEY or GEMINI_API_KEY is not found\n */\nexport function getGeminiApiKeyFromEnv(): string {\n try {\n return getApiKeyFromEnv('GOOGLE_API_KEY')\n } catch {\n try {\n return getApiKeyFromEnv('GEMINI_API_KEY')\n } catch {\n throw new Error(\n 'GOOGLE_API_KEY or GEMINI_API_KEY is not set. Please set one of these environment variables or pass the API key directly.',\n )\n }\n }\n}\n\n/**\n * Generates a unique ID with a prefix\n */\nexport function generateId(prefix: string): string {\n return _generateId(prefix)\n}\n"],"names":["_generateId"],"mappings":";;AAWO,SAAS,mBAAmB,QAAyC;AAC1E,SAAO,IAAI,YAAY;AAAA,IACrB,GAAG;AAAA,IACH,QAAQ,OAAO;AAAA,EAAA,CAChB;AACH;AAMO,SAAS,yBAAiC;AAC/C,MAAI;AACF,WAAO,iBAAiB,gBAAgB;AAAA,EAC1C,QAAQ;AACN,QAAI;AACF,aAAO,iBAAiB,gBAAgB;AAAA,IAC1C,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAKO,SAAS,WAAW,QAAwB;AACjD,SAAOA,aAAY,MAAM;AAC3B;"}
@@ -0,0 +1 @@
1
+ export { createGeminiClient, generateId, getGeminiApiKeyFromEnv, type GeminiClientConfig, } from './client.js';
@@ -0,0 +1,90 @@
1
+ import { DurationOptions } from '@tanstack/ai/adapters';
2
+ import { GenerateVideosConfig } from '@google/genai';
3
+ import { GEMINI_VIDEO_MODELS } from '../model-meta.js';
4
+ /**
5
+ * Model type for Gemini Veo video generation.
6
+ * @experimental Video generation is an experimental feature and may change.
7
+ */
8
+ export type GeminiVideoModel = (typeof GEMINI_VIDEO_MODELS)[number];
9
+ /**
10
+ * Supported aspect ratios for Veo video generation. This is the `size` value
11
+ * for the Gemini video adapter — Veo expresses output shape as an aspect
12
+ * ratio (plus an optional `resolution` in `modelOptions`), not pixel
13
+ * dimensions.
14
+ *
15
+ * @experimental Video generation is an experimental feature and may change.
16
+ */
17
+ export type GeminiVideoSize = '16:9' | '9:16';
18
+ /**
19
+ * Provider-specific options for Gemini Veo video generation.
20
+ *
21
+ * Derived from the SDK's `GenerateVideosConfig`, minus the fields the
22
+ * adapter manages itself:
23
+ * - `durationSeconds` — set via the typed top-level `duration` option
24
+ * (use `adapter.snapDuration(seconds)` to coerce raw seconds)
25
+ * - `aspectRatio` — set via the top-level `size` option
26
+ * - `lastFrame` / `referenceImages` — set via image parts in the `prompt`
27
+ * with `metadata.role: 'end_frame'` / `'reference'`
28
+ * - `httpOptions` / `abortSignal` — client-level transport concerns
29
+ *
30
+ * @experimental Video generation is an experimental feature and may change.
31
+ */
32
+ export type GeminiVideoProviderOptions = Omit<GenerateVideosConfig, 'durationSeconds' | 'aspectRatio' | 'lastFrame' | 'referenceImages' | 'httpOptions' | 'abortSignal'>;
33
+ /**
34
+ * Model-specific provider options mapping.
35
+ *
36
+ * @experimental Video generation is an experimental feature and may change.
37
+ */
38
+ export type GeminiVideoModelProviderOptionsByName = {
39
+ [TModel in GeminiVideoModel]: GeminiVideoProviderOptions;
40
+ };
41
+ /**
42
+ * Model-specific size (aspect ratio) mapping.
43
+ *
44
+ * @experimental Video generation is an experimental feature and may change.
45
+ */
46
+ export type GeminiVideoModelSizeByName = {
47
+ [TModel in GeminiVideoModel]: GeminiVideoSize;
48
+ };
49
+ /**
50
+ * Per-model prompt input modalities. Every Veo model accepts image
51
+ * conditioning inputs (first frame, last frame, reference images) alongside
52
+ * the text prompt.
53
+ *
54
+ * @experimental Video generation is an experimental feature and may change.
55
+ */
56
+ export type GeminiVideoModelInputModalitiesByName = {
57
+ [TModel in GeminiVideoModel]: readonly ['image'];
58
+ };
59
+ /**
60
+ * Per-model duration unions (seconds, as numbers — the API's
61
+ * `parameters.durationSeconds` field is numeric).
62
+ *
63
+ * @experimental Video generation is an experimental feature and may change.
64
+ */
65
+ export type GeminiVideoModelDurationByName = {
66
+ 'veo-3.1-generate-preview': 4 | 6 | 8;
67
+ 'veo-3.1-fast-generate-preview': 4 | 6 | 8;
68
+ 'veo-3.0-generate-001': 4 | 6 | 8;
69
+ 'veo-3.0-fast-generate-001': 4 | 6 | 8;
70
+ 'veo-2.0-generate-001': 5 | 6 | 8;
71
+ };
72
+ /**
73
+ * Runtime duration table backing `availableDurations()` / `snapDuration()`.
74
+ *
75
+ * Curated from the official Veo docs
76
+ * (https://ai.google.dev/gemini-api/docs/video) — the Gemini OpenAPI spec
77
+ * types the `:predictLongRunning` request's `parameters` as unconstrained,
78
+ * so it carries no per-model duration information to derive these from.
79
+ *
80
+ * @experimental Video generation is an experimental feature and may change.
81
+ */
82
+ export declare const GEMINI_VIDEO_DURATIONS: {
83
+ readonly [TModel in GeminiVideoModel]: DurationOptions<GeminiVideoModelDurationByName[TModel]>;
84
+ };
85
+ /**
86
+ * Look up the duration options for a Veo model.
87
+ *
88
+ * @experimental Video generation is an experimental feature and may change.
89
+ */
90
+ export declare function getGeminiVideoDurationOptions<TModel extends GeminiVideoModel>(model: TModel): DurationOptions<GeminiVideoModelDurationByName[TModel]>;
@@ -0,0 +1,15 @@
1
+ const GEMINI_VIDEO_DURATIONS = {
2
+ "veo-3.1-generate-preview": { kind: "discrete", values: [4, 6, 8] },
3
+ "veo-3.1-fast-generate-preview": { kind: "discrete", values: [4, 6, 8] },
4
+ "veo-3.0-generate-001": { kind: "discrete", values: [4, 6, 8] },
5
+ "veo-3.0-fast-generate-001": { kind: "discrete", values: [4, 6, 8] },
6
+ "veo-2.0-generate-001": { kind: "discrete", values: [5, 6, 8] }
7
+ };
8
+ function getGeminiVideoDurationOptions(model) {
9
+ return GEMINI_VIDEO_DURATIONS[model];
10
+ }
11
+ export {
12
+ GEMINI_VIDEO_DURATIONS,
13
+ getGeminiVideoDurationOptions
14
+ };
15
+ //# sourceMappingURL=video-provider-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-provider-options.js","sources":["../../../src/video/video-provider-options.ts"],"sourcesContent":["/**\n * Gemini Veo Video Generation Provider Options\n *\n * Based on https://ai.google.dev/gemini-api/docs/video\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nimport type { DurationOptions } from '@tanstack/ai/adapters'\nimport type { GenerateVideosConfig } from '@google/genai'\nimport type { GEMINI_VIDEO_MODELS } from '../model-meta'\n\n/**\n * Model type for Gemini Veo video generation.\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type GeminiVideoModel = (typeof GEMINI_VIDEO_MODELS)[number]\n\n/**\n * Supported aspect ratios for Veo video generation. This is the `size` value\n * for the Gemini video adapter — Veo expresses output shape as an aspect\n * ratio (plus an optional `resolution` in `modelOptions`), not pixel\n * dimensions.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type GeminiVideoSize = '16:9' | '9:16'\n\n/**\n * Provider-specific options for Gemini Veo video generation.\n *\n * Derived from the SDK's `GenerateVideosConfig`, minus the fields the\n * adapter manages itself:\n * - `durationSeconds` — set via the typed top-level `duration` option\n * (use `adapter.snapDuration(seconds)` to coerce raw seconds)\n * - `aspectRatio` — set via the top-level `size` option\n * - `lastFrame` / `referenceImages` — set via image parts in the `prompt`\n * with `metadata.role: 'end_frame'` / `'reference'`\n * - `httpOptions` / `abortSignal` — client-level transport concerns\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type GeminiVideoProviderOptions = Omit<\n GenerateVideosConfig,\n | 'durationSeconds'\n | 'aspectRatio'\n | 'lastFrame'\n | 'referenceImages'\n | 'httpOptions'\n | 'abortSignal'\n>\n\n/**\n * Model-specific provider options mapping.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type GeminiVideoModelProviderOptionsByName = {\n [TModel in GeminiVideoModel]: GeminiVideoProviderOptions\n}\n\n/**\n * Model-specific size (aspect ratio) mapping.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type GeminiVideoModelSizeByName = {\n [TModel in GeminiVideoModel]: GeminiVideoSize\n}\n\n/**\n * Per-model prompt input modalities. Every Veo model accepts image\n * conditioning inputs (first frame, last frame, reference images) alongside\n * the text prompt.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type GeminiVideoModelInputModalitiesByName = {\n [TModel in GeminiVideoModel]: readonly ['image']\n}\n\n/**\n * Per-model duration unions (seconds, as numbers — the API's\n * `parameters.durationSeconds` field is numeric).\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type GeminiVideoModelDurationByName = {\n 'veo-3.1-generate-preview': 4 | 6 | 8\n 'veo-3.1-fast-generate-preview': 4 | 6 | 8\n 'veo-3.0-generate-001': 4 | 6 | 8\n 'veo-3.0-fast-generate-001': 4 | 6 | 8\n 'veo-2.0-generate-001': 5 | 6 | 8\n}\n\n/**\n * Runtime duration table backing `availableDurations()` / `snapDuration()`.\n *\n * Curated from the official Veo docs\n * (https://ai.google.dev/gemini-api/docs/video) — the Gemini OpenAPI spec\n * types the `:predictLongRunning` request's `parameters` as unconstrained,\n * so it carries no per-model duration information to derive these from.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport const GEMINI_VIDEO_DURATIONS: {\n readonly [TModel in GeminiVideoModel]: DurationOptions<\n GeminiVideoModelDurationByName[TModel]\n >\n} = {\n 'veo-3.1-generate-preview': { kind: 'discrete', values: [4, 6, 8] },\n 'veo-3.1-fast-generate-preview': { kind: 'discrete', values: [4, 6, 8] },\n 'veo-3.0-generate-001': { kind: 'discrete', values: [4, 6, 8] },\n 'veo-3.0-fast-generate-001': { kind: 'discrete', values: [4, 6, 8] },\n 'veo-2.0-generate-001': { kind: 'discrete', values: [5, 6, 8] },\n}\n\n/**\n * Look up the duration options for a Veo model.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport function getGeminiVideoDurationOptions<TModel extends GeminiVideoModel>(\n model: TModel,\n): DurationOptions<GeminiVideoModelDurationByName[TModel]> {\n return GEMINI_VIDEO_DURATIONS[model]\n}\n"],"names":[],"mappings":"AAwGO,MAAM,yBAIT;AAAA,EACF,4BAA4B,EAAE,MAAM,YAAY,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAA;AAAA,EAChE,iCAAiC,EAAE,MAAM,YAAY,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAA;AAAA,EACrE,wBAAwB,EAAE,MAAM,YAAY,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAA;AAAA,EAC5D,6BAA6B,EAAE,MAAM,YAAY,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAA;AAAA,EACjE,wBAAwB,EAAE,MAAM,YAAY,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAA;AAC9D;AAOO,SAAS,8BACd,OACyD;AACzD,SAAO,uBAAuB,KAAK;AACrC;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-gemini",
3
- "version": "0.18.1",
3
+ "version": "0.18.3",
4
4
  "description": "Google Gemini adapter for TanStack AI chat, images, speech, audio generation, and structured outputs.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -56,16 +56,16 @@
56
56
  "dependencies": {
57
57
  "@google/genai": "^2.8.0",
58
58
  "partial-json": "^0.1.7",
59
- "@tanstack/ai-utils": "0.3.0"
59
+ "@tanstack/ai-utils": "0.3.1"
60
60
  },
61
61
  "peerDependencies": {
62
- "@tanstack/ai": "^0.36.0"
62
+ "@tanstack/ai": "^0.38.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@vitest/coverage-v8": "4.0.14",
66
66
  "vite": "^7.3.3",
67
67
  "zod": "^4.2.0",
68
- "@tanstack/ai": "0.36.0"
68
+ "@tanstack/ai": "0.38.0"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "vite build",