@tanstack/ai-gemini 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/esm/adapters/image.d.ts +83 -0
- package/dist/esm/adapters/image.js +60 -0
- package/dist/esm/adapters/image.js.map +1 -0
- package/dist/esm/adapters/summarize.d.ts +53 -0
- package/dist/esm/adapters/summarize.js +139 -0
- package/dist/esm/adapters/summarize.js.map +1 -0
- package/dist/esm/adapters/text.d.ts +63 -0
- package/dist/esm/{gemini-adapter.js → adapters/text.js} +86 -132
- package/dist/esm/adapters/text.js.map +1 -0
- package/dist/esm/adapters/tts.d.ts +129 -0
- package/dist/esm/adapters/tts.js +78 -0
- package/dist/esm/adapters/tts.js.map +1 -0
- package/dist/esm/image/image-provider-options.d.ts +139 -0
- package/dist/esm/image/image-provider-options.js +53 -0
- package/dist/esm/image/image-provider-options.js.map +1 -0
- package/dist/esm/index.d.ts +15 -2
- package/dist/esm/index.js +22 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/model-meta.d.ts +128 -1
- package/dist/esm/model-meta.js +71 -5
- package/dist/esm/model-meta.js.map +1 -1
- package/dist/esm/tools/tool-converter.js +5 -3
- package/dist/esm/tools/tool-converter.js.map +1 -1
- package/dist/esm/utils/client.d.ts +17 -0
- package/dist/esm/utils/client.js +25 -0
- package/dist/esm/utils/client.js.map +1 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/package.json +5 -4
- package/src/adapters/image.ts +188 -0
- package/src/adapters/summarize.ts +242 -0
- package/src/{gemini-adapter.ts → adapters/text.ts} +196 -245
- package/src/adapters/tts.ts +223 -0
- package/src/image/image-provider-options.ts +239 -0
- package/src/index.ts +66 -2
- package/src/model-meta.ts +87 -62
- package/src/tools/tool-converter.ts +6 -5
- package/src/utils/client.ts +43 -0
- package/src/utils/index.ts +6 -0
- package/dist/esm/gemini-adapter.d.ts +0 -71
- package/dist/esm/gemini-adapter.js.map +0 -1
package/src/model-meta.ts
CHANGED
|
@@ -121,7 +121,7 @@ const GEMINI_2_5_PRO = {
|
|
|
121
121
|
GeminiThinkingOptions
|
|
122
122
|
>
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
const GEMINI_2_5_PRO_TTS = {
|
|
125
125
|
name: 'gemini-2.5-pro-preview-tts',
|
|
126
126
|
max_input_tokens: 8_192,
|
|
127
127
|
max_output_tokens: 16_384,
|
|
@@ -141,10 +141,10 @@ const GEMINI_2_5_PRO = {
|
|
|
141
141
|
},
|
|
142
142
|
} as const satisfies ModelMeta<
|
|
143
143
|
GeminiToolConfigOptions &
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
>
|
|
144
|
+
GeminiSafetyOptions &
|
|
145
|
+
GeminiGenerationConfigOptions &
|
|
146
|
+
GeminiCachedContentOptions
|
|
147
|
+
>
|
|
148
148
|
|
|
149
149
|
const GEMINI_2_5_FLASH = {
|
|
150
150
|
name: 'gemini-2.5-flash',
|
|
@@ -220,7 +220,7 @@ const GEMINI_2_5_FLASH_PREVIEW = {
|
|
|
220
220
|
GeminiStructuredOutputOptions &
|
|
221
221
|
GeminiThinkingOptions
|
|
222
222
|
>
|
|
223
|
-
|
|
223
|
+
|
|
224
224
|
const GEMINI_2_5_FLASH_IMAGE = {
|
|
225
225
|
name: 'gemini-2.5-flash-image',
|
|
226
226
|
max_input_tokens: 1_048_576,
|
|
@@ -247,11 +247,11 @@ const GEMINI_2_5_FLASH_IMAGE = {
|
|
|
247
247
|
},
|
|
248
248
|
} as const satisfies ModelMeta<
|
|
249
249
|
GeminiToolConfigOptions &
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
GeminiSafetyOptions &
|
|
251
|
+
GeminiGenerationConfigOptions &
|
|
252
|
+
GeminiCachedContentOptions
|
|
253
253
|
>
|
|
254
|
-
|
|
254
|
+
/**
|
|
255
255
|
const GEMINI_2_5_FLASH_LIVE = {
|
|
256
256
|
name: 'gemini-2.5-flash-native-audio-preview-09-2025',
|
|
257
257
|
max_input_tokens: 141_072,
|
|
@@ -285,7 +285,7 @@ const GEMINI_2_5_FLASH_LIVE = {
|
|
|
285
285
|
GeminiCachedContentOptions &
|
|
286
286
|
GeminiThinkingOptions
|
|
287
287
|
>
|
|
288
|
-
|
|
288
|
+
*/
|
|
289
289
|
const GEMINI_2_5_FLASH_TTS = {
|
|
290
290
|
name: 'gemini-2.5-flash-preview-tts',
|
|
291
291
|
max_input_tokens: 8_192,
|
|
@@ -306,10 +306,10 @@ const GEMINI_2_5_FLASH_TTS = {
|
|
|
306
306
|
},
|
|
307
307
|
} as const satisfies ModelMeta<
|
|
308
308
|
GeminiToolConfigOptions &
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
>
|
|
309
|
+
GeminiSafetyOptions &
|
|
310
|
+
GeminiGenerationConfigOptions &
|
|
311
|
+
GeminiCachedContentOptions
|
|
312
|
+
>
|
|
313
313
|
|
|
314
314
|
const GEMINI_2_5_FLASH_LITE = {
|
|
315
315
|
name: 'gemini-2.5-flash-lite',
|
|
@@ -418,7 +418,7 @@ const GEMINI_2_FLASH = {
|
|
|
418
418
|
GeminiCachedContentOptions &
|
|
419
419
|
GeminiStructuredOutputOptions
|
|
420
420
|
>
|
|
421
|
-
|
|
421
|
+
|
|
422
422
|
const GEMINI_2_FLASH_IMAGE = {
|
|
423
423
|
name: 'gemini-2.0-flash-preview-image-generation',
|
|
424
424
|
max_input_tokens: 32_768,
|
|
@@ -444,10 +444,10 @@ const GEMINI_2_FLASH_IMAGE = {
|
|
|
444
444
|
},
|
|
445
445
|
} as const satisfies ModelMeta<
|
|
446
446
|
GeminiToolConfigOptions &
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
>
|
|
447
|
+
GeminiSafetyOptions &
|
|
448
|
+
GeminiGenerationConfigOptions &
|
|
449
|
+
GeminiCachedContentOptions
|
|
450
|
+
>
|
|
451
451
|
/*
|
|
452
452
|
const GEMINI_2_FLASH_LIVE = {
|
|
453
453
|
name: 'gemini-2.0-flash-live-001',
|
|
@@ -514,7 +514,7 @@ const GEMINI_2_FLASH_LITE = {
|
|
|
514
514
|
GeminiStructuredOutputOptions
|
|
515
515
|
>
|
|
516
516
|
|
|
517
|
-
|
|
517
|
+
const IMAGEN_4_GENERATE = {
|
|
518
518
|
name: 'imagen-4.0-generate-001',
|
|
519
519
|
max_input_tokens: 480,
|
|
520
520
|
max_output_tokens: 4,
|
|
@@ -532,9 +532,9 @@ const GEMINI_2_FLASH_LITE = {
|
|
|
532
532
|
},
|
|
533
533
|
} as const satisfies ModelMeta<
|
|
534
534
|
GeminiToolConfigOptions &
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
535
|
+
GeminiSafetyOptions &
|
|
536
|
+
GeminiGenerationConfigOptions &
|
|
537
|
+
GeminiCachedContentOptions
|
|
538
538
|
>
|
|
539
539
|
|
|
540
540
|
const IMAGEN_4_GENERATE_ULTRA = {
|
|
@@ -555,9 +555,9 @@ const IMAGEN_4_GENERATE_ULTRA = {
|
|
|
555
555
|
},
|
|
556
556
|
} as const satisfies ModelMeta<
|
|
557
557
|
GeminiToolConfigOptions &
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
558
|
+
GeminiSafetyOptions &
|
|
559
|
+
GeminiGenerationConfigOptions &
|
|
560
|
+
GeminiCachedContentOptions
|
|
561
561
|
>
|
|
562
562
|
|
|
563
563
|
const IMAGEN_4_GENERATE_FAST = {
|
|
@@ -578,9 +578,9 @@ const IMAGEN_4_GENERATE_FAST = {
|
|
|
578
578
|
},
|
|
579
579
|
} as const satisfies ModelMeta<
|
|
580
580
|
GeminiToolConfigOptions &
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
581
|
+
GeminiSafetyOptions &
|
|
582
|
+
GeminiGenerationConfigOptions &
|
|
583
|
+
GeminiCachedContentOptions
|
|
584
584
|
>
|
|
585
585
|
|
|
586
586
|
const IMAGEN_3 = {
|
|
@@ -600,11 +600,11 @@ const IMAGEN_3 = {
|
|
|
600
600
|
},
|
|
601
601
|
} as const satisfies ModelMeta<
|
|
602
602
|
GeminiToolConfigOptions &
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
603
|
+
GeminiSafetyOptions &
|
|
604
|
+
GeminiGenerationConfigOptions &
|
|
605
|
+
GeminiCachedContentOptions
|
|
606
606
|
>
|
|
607
|
-
|
|
607
|
+
/**
|
|
608
608
|
const VEO_3_1_PREVIEW = {
|
|
609
609
|
name: 'veo-3.1-generate-preview',
|
|
610
610
|
max_input_tokens: 1024,
|
|
@@ -719,28 +719,6 @@ const VEO_2 = {
|
|
|
719
719
|
GeminiCachedContentOptions
|
|
720
720
|
> */
|
|
721
721
|
|
|
722
|
-
const GEMINI_EMBEDDING = {
|
|
723
|
-
name: 'gemini-embedding-001',
|
|
724
|
-
max_input_tokens: 2048,
|
|
725
|
-
supports: {
|
|
726
|
-
input: ['text'],
|
|
727
|
-
output: ['text'],
|
|
728
|
-
},
|
|
729
|
-
pricing: {
|
|
730
|
-
input: {
|
|
731
|
-
normal: 0,
|
|
732
|
-
},
|
|
733
|
-
output: {
|
|
734
|
-
normal: 0.15,
|
|
735
|
-
},
|
|
736
|
-
},
|
|
737
|
-
} as const satisfies ModelMeta<
|
|
738
|
-
GeminiToolConfigOptions &
|
|
739
|
-
GeminiSafetyOptions &
|
|
740
|
-
GeminiGenerationConfigOptions &
|
|
741
|
-
GeminiCachedContentOptions
|
|
742
|
-
>
|
|
743
|
-
|
|
744
722
|
/* const GEMINI_MODEL_META = {
|
|
745
723
|
[GEMINI_3_PRO.name]: GEMINI_3_PRO,
|
|
746
724
|
[GEMINI_2_5_PRO.name]: GEMINI_2_5_PRO,
|
|
@@ -765,7 +743,6 @@ const GEMINI_EMBEDDING = {
|
|
|
765
743
|
[VEO_3.name]: VEO_3,
|
|
766
744
|
[VEO_3_FAST.name]: VEO_3_FAST,
|
|
767
745
|
[VEO_2.name]: VEO_2,
|
|
768
|
-
[GEMINI_EMBEDDING.name]: GEMINI_EMBEDDING,
|
|
769
746
|
} as const */
|
|
770
747
|
|
|
771
748
|
export const GEMINI_MODELS = [
|
|
@@ -779,16 +756,66 @@ export const GEMINI_MODELS = [
|
|
|
779
756
|
GEMINI_2_FLASH_LITE.name,
|
|
780
757
|
] as const
|
|
781
758
|
|
|
782
|
-
|
|
759
|
+
export type GeminiModels = (typeof GEMINI_MODELS)[number]
|
|
760
|
+
|
|
761
|
+
export type GeminiImageModels = (typeof GEMINI_IMAGE_MODELS)[number]
|
|
762
|
+
|
|
763
|
+
export const GEMINI_IMAGE_MODELS = [
|
|
783
764
|
GEMINI_2_5_FLASH_IMAGE.name,
|
|
784
765
|
GEMINI_2_FLASH_IMAGE.name,
|
|
785
766
|
IMAGEN_3.name,
|
|
786
767
|
IMAGEN_4_GENERATE.name,
|
|
787
768
|
IMAGEN_4_GENERATE_FAST.name,
|
|
788
769
|
IMAGEN_4_GENERATE_ULTRA.name,
|
|
789
|
-
] as const
|
|
770
|
+
] as const
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Text-to-speech models
|
|
774
|
+
* @experimental Gemini TTS is an experimental feature and may change.
|
|
775
|
+
*/
|
|
776
|
+
export const GEMINI_TTS_MODELS = [
|
|
777
|
+
GEMINI_2_5_FLASH_TTS.name,
|
|
778
|
+
GEMINI_2_5_PRO_TTS.name,
|
|
779
|
+
] as const
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Available voice names for Gemini TTS
|
|
783
|
+
* @see https://ai.google.dev/gemini-api/docs/speech-generation
|
|
784
|
+
*/
|
|
785
|
+
export const GEMINI_TTS_VOICES = [
|
|
786
|
+
'Zephyr',
|
|
787
|
+
'Puck',
|
|
788
|
+
'Charon',
|
|
789
|
+
'Kore',
|
|
790
|
+
'Fenrir',
|
|
791
|
+
'Leda',
|
|
792
|
+
'Orus',
|
|
793
|
+
'Aoede',
|
|
794
|
+
'Callirrhoe',
|
|
795
|
+
'Autonoe',
|
|
796
|
+
'Enceladus',
|
|
797
|
+
'Iapetus',
|
|
798
|
+
'Umbriel',
|
|
799
|
+
'Algieba',
|
|
800
|
+
'Despina',
|
|
801
|
+
'Erinome',
|
|
802
|
+
'Algenib',
|
|
803
|
+
'Rasalgethi',
|
|
804
|
+
'Laomedeia',
|
|
805
|
+
'Achernar',
|
|
806
|
+
'Alnilam',
|
|
807
|
+
'Schedar',
|
|
808
|
+
'Gacrux',
|
|
809
|
+
'Pulcherrima',
|
|
810
|
+
'Achird',
|
|
811
|
+
'Zubenelgenubi',
|
|
812
|
+
'Vindemiatrix',
|
|
813
|
+
'Sadachbia',
|
|
814
|
+
'Sadaltager',
|
|
815
|
+
'Sulafat',
|
|
816
|
+
] as const
|
|
790
817
|
|
|
791
|
-
export
|
|
818
|
+
export type GeminiTTSVoice = (typeof GEMINI_TTS_VOICES)[number]
|
|
792
819
|
|
|
793
820
|
/* const GEMINI_AUDIO_MODELS = [
|
|
794
821
|
GEMINI_2_5_PRO_TTS.name,
|
|
@@ -805,8 +832,6 @@ export const GEMINI_EMBEDDING_MODELS = [GEMINI_EMBEDDING.name] as const
|
|
|
805
832
|
VEO_2.name,
|
|
806
833
|
] as const */
|
|
807
834
|
|
|
808
|
-
// export type GeminiChatModels = (typeof GEMINI_MODELS)[number]
|
|
809
|
-
|
|
810
835
|
// Manual type map for per-model provider options
|
|
811
836
|
export type GeminiChatModelProviderOptionsByName = {
|
|
812
837
|
// Models with thinking and structured output support
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { convertZodToJsonSchema } from '@tanstack/ai'
|
|
2
1
|
import { convertCodeExecutionToolToAdapterFormat } from './code-execution-tool'
|
|
3
2
|
import { convertComputerUseToolToAdapterFormat } from './computer-use-tool'
|
|
4
3
|
import { convertFileSearchToolToAdapterFormat } from './file-search-tool'
|
|
@@ -76,13 +75,15 @@ export function convertToolsToProviderFormat<TTool extends Tool>(
|
|
|
76
75
|
)
|
|
77
76
|
}
|
|
78
77
|
|
|
79
|
-
//
|
|
80
|
-
const jsonSchema = convertZodToJsonSchema(tool.inputSchema)
|
|
81
|
-
|
|
78
|
+
// Tool schemas are already converted to JSON Schema in the ai layer
|
|
82
79
|
functionDeclarations.push({
|
|
83
80
|
name: tool.name,
|
|
84
81
|
description: tool.description,
|
|
85
|
-
parameters:
|
|
82
|
+
parameters: tool.inputSchema ?? {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {},
|
|
85
|
+
required: [],
|
|
86
|
+
},
|
|
86
87
|
})
|
|
87
88
|
break
|
|
88
89
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { GoogleGenAI } from '@google/genai'
|
|
2
|
+
|
|
3
|
+
export interface GeminiClientConfig {
|
|
4
|
+
apiKey: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a Google Generative AI client instance
|
|
9
|
+
*/
|
|
10
|
+
export function createGeminiClient(config: GeminiClientConfig): GoogleGenAI {
|
|
11
|
+
return new GoogleGenAI({
|
|
12
|
+
apiKey: config.apiKey,
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Gets Google API key from environment variables
|
|
18
|
+
* @throws Error if GOOGLE_API_KEY or GEMINI_API_KEY is not found
|
|
19
|
+
*/
|
|
20
|
+
export function getGeminiApiKeyFromEnv(): string {
|
|
21
|
+
const env =
|
|
22
|
+
typeof globalThis !== 'undefined' && (globalThis as any).window?.env
|
|
23
|
+
? (globalThis as any).window.env
|
|
24
|
+
: typeof process !== 'undefined'
|
|
25
|
+
? process.env
|
|
26
|
+
: undefined
|
|
27
|
+
const key = env?.GOOGLE_API_KEY || env?.GEMINI_API_KEY
|
|
28
|
+
|
|
29
|
+
if (!key) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
'GOOGLE_API_KEY or GEMINI_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key.',
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return key
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Generates a unique ID with a prefix
|
|
40
|
+
*/
|
|
41
|
+
export function generateId(prefix: string): string {
|
|
42
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`
|
|
43
|
+
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { BaseAdapter, AIAdapterConfig, ChatOptions, EmbeddingOptions, EmbeddingResult, StreamChunk, SummarizationOptions, SummarizationResult } from '@tanstack/ai';
|
|
2
|
-
import { GEMINI_EMBEDDING_MODELS, GEMINI_MODELS, GeminiChatModelProviderOptionsByName, GeminiModelInputModalitiesByName } from './model-meta.js';
|
|
3
|
-
import { ExternalTextProviderOptions } from './text/text-provider-options.js';
|
|
4
|
-
import { GeminiMessageMetadataByModality } from './message-types.js';
|
|
5
|
-
export interface GeminiAdapterConfig extends AIAdapterConfig {
|
|
6
|
-
apiKey: string;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Gemini-specific provider options
|
|
10
|
-
* Based on Google Generative AI SDK
|
|
11
|
-
* @see https://ai.google.dev/api/rest/v1/GenerationConfig
|
|
12
|
-
*/
|
|
13
|
-
export type GeminiProviderOptions = ExternalTextProviderOptions;
|
|
14
|
-
export declare class GeminiAdapter extends BaseAdapter<typeof GEMINI_MODELS, typeof GEMINI_EMBEDDING_MODELS, GeminiProviderOptions, Record<string, any>, GeminiChatModelProviderOptionsByName, GeminiModelInputModalitiesByName, GeminiMessageMetadataByModality> {
|
|
15
|
-
name: string;
|
|
16
|
-
models: readonly ["gemini-3-pro-preview", "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-preview-09-2025", "gemini-2.5-flash-lite", "gemini-2.5-flash-lite-preview-09-2025", "gemini-2.0-flash", "gemini-2.0-flash-lite"];
|
|
17
|
-
embeddingModels: readonly ["gemini-embedding-001"];
|
|
18
|
-
_modelProviderOptionsByName: GeminiChatModelProviderOptionsByName;
|
|
19
|
-
_modelInputModalitiesByName: GeminiModelInputModalitiesByName;
|
|
20
|
-
_messageMetadataByModality: GeminiMessageMetadataByModality;
|
|
21
|
-
private client;
|
|
22
|
-
constructor(config: GeminiAdapterConfig);
|
|
23
|
-
chatStream(options: ChatOptions<string, GeminiProviderOptions>): AsyncIterable<StreamChunk>;
|
|
24
|
-
summarize(options: SummarizationOptions): Promise<SummarizationResult>;
|
|
25
|
-
createEmbeddings(options: EmbeddingOptions): Promise<EmbeddingResult>;
|
|
26
|
-
private buildSummarizationPrompt;
|
|
27
|
-
private estimateTokens;
|
|
28
|
-
private processStreamChunks;
|
|
29
|
-
private convertContentPartToGemini;
|
|
30
|
-
private formatMessages;
|
|
31
|
-
/**
|
|
32
|
-
* Maps common options to Gemini-specific format
|
|
33
|
-
* Handles translation of normalized options to Gemini's API format
|
|
34
|
-
*/
|
|
35
|
-
private mapCommonOptionsToGemini;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Creates a Gemini adapter with simplified configuration
|
|
39
|
-
* @param apiKey - Your Google API key
|
|
40
|
-
* @returns A fully configured Gemini adapter instance
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```typescript
|
|
44
|
-
* const gemini = createGemini("AIza...");
|
|
45
|
-
*
|
|
46
|
-
* const ai = new AI({
|
|
47
|
-
* adapters: {
|
|
48
|
-
* gemini,
|
|
49
|
-
* }
|
|
50
|
-
* });
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
export declare function createGemini(apiKey: string, config?: Omit<GeminiAdapterConfig, 'apiKey'>): GeminiAdapter;
|
|
54
|
-
/**
|
|
55
|
-
* Create a Gemini adapter with automatic API key detection from environment variables.
|
|
56
|
-
*
|
|
57
|
-
* Looks for `GOOGLE_API_KEY` or `GEMINI_API_KEY` in:
|
|
58
|
-
* - `process.env` (Node.js)
|
|
59
|
-
* - `window.env` (Browser with injected env)
|
|
60
|
-
*
|
|
61
|
-
* @param config - Optional configuration (excluding apiKey which is auto-detected)
|
|
62
|
-
* @returns Configured Gemini adapter instance
|
|
63
|
-
* @throws Error if API key is not found in environment
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```typescript
|
|
67
|
-
* // Automatically uses GOOGLE_API_KEY or GEMINI_API_KEY from environment
|
|
68
|
-
* const aiInstance = ai(gemini());
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
|
-
export declare function gemini(config?: Omit<GeminiAdapterConfig, 'apiKey'>): GeminiAdapter;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gemini-adapter.js","sources":["../../src/gemini-adapter.ts"],"sourcesContent":["import { FinishReason, GoogleGenAI } from '@google/genai'\nimport { BaseAdapter } from '@tanstack/ai'\nimport { GEMINI_EMBEDDING_MODELS, GEMINI_MODELS } from './model-meta'\nimport { convertToolsToProviderFormat } from './tools/tool-converter'\nimport type {\n AIAdapterConfig,\n ChatOptions,\n ContentPart,\n EmbeddingOptions,\n EmbeddingResult,\n ModelMessage,\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n} from '@tanstack/ai'\nimport type {\n GeminiChatModelProviderOptionsByName,\n GeminiModelInputModalitiesByName,\n} from './model-meta'\nimport type { ExternalTextProviderOptions } from './text/text-provider-options'\nimport type {\n GenerateContentParameters,\n GenerateContentResponse,\n Part,\n} from '@google/genai'\nimport type {\n GeminiAudioMetadata,\n GeminiDocumentMetadata,\n GeminiImageMetadata,\n GeminiMessageMetadataByModality,\n GeminiVideoMetadata,\n} from './message-types'\n\nexport interface GeminiAdapterConfig extends AIAdapterConfig {\n apiKey: string\n}\n\n/**\n * Gemini-specific provider options\n * Based on Google Generative AI SDK\n * @see https://ai.google.dev/api/rest/v1/GenerationConfig\n */\nexport type GeminiProviderOptions = ExternalTextProviderOptions\n\nexport class GeminiAdapter extends BaseAdapter<\n typeof GEMINI_MODELS,\n typeof GEMINI_EMBEDDING_MODELS,\n GeminiProviderOptions,\n Record<string, any>,\n GeminiChatModelProviderOptionsByName,\n GeminiModelInputModalitiesByName,\n GeminiMessageMetadataByModality\n> {\n name = 'gemini'\n models = GEMINI_MODELS\n embeddingModels = GEMINI_EMBEDDING_MODELS\n declare _modelProviderOptionsByName: GeminiChatModelProviderOptionsByName\n declare _modelInputModalitiesByName: GeminiModelInputModalitiesByName\n declare _messageMetadataByModality: GeminiMessageMetadataByModality\n private client: GoogleGenAI\n\n constructor(config: GeminiAdapterConfig) {\n super(config)\n this.client = new GoogleGenAI({\n apiKey: config.apiKey,\n })\n }\n\n async *chatStream(\n options: ChatOptions<string, GeminiProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n // Map common options to Gemini format\n const mappedOptions = this.mapCommonOptionsToGemini(options)\n\n try {\n const result =\n await this.client.models.generateContentStream(mappedOptions)\n\n yield* this.processStreamChunks(result, options.model)\n } catch (error) {\n const timestamp = Date.now()\n yield {\n type: 'error',\n id: this.generateId(),\n model: options.model,\n timestamp,\n error: {\n message:\n error instanceof Error\n ? error.message\n : 'An unknown error occurred during the chat stream.',\n },\n }\n }\n }\n\n async summarize(options: SummarizationOptions): Promise<SummarizationResult> {\n const prompt = this.buildSummarizationPrompt(options, options.text)\n\n // Use models API like chatCompletion\n const result = await this.client.models.generateContent({\n model: options.model,\n contents: [{ role: 'user', parts: [{ text: prompt }] }],\n config: {\n temperature: 0.3,\n maxOutputTokens: options.maxLength || 500,\n },\n })\n\n // Extract text from candidates or use .text() method\n let summary = ''\n if (result.candidates?.[0]?.content?.parts) {\n const parts = result.candidates[0].content.parts\n for (const part of parts) {\n if (part.text) {\n summary += part.text\n }\n }\n }\n\n if (!summary && typeof result.text === 'string') {\n summary = result.text\n }\n\n const promptTokens = this.estimateTokens(prompt)\n const completionTokens = this.estimateTokens(summary)\n\n return {\n id: this.generateId(),\n model: options.model,\n summary,\n usage: {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n },\n }\n }\n\n async createEmbeddings(options: EmbeddingOptions): Promise<EmbeddingResult> {\n const inputs = Array.isArray(options.input)\n ? options.input\n : [options.input]\n\n // According to docs: contents can be a string or array of strings\n // Response has embeddings (plural) array with values property\n const result = await this.client.models.embedContent({\n model: options.model,\n contents: inputs,\n })\n\n // Extract embeddings from result.embeddings array\n const embeddings: Array<Array<number>> = []\n if (result.embeddings && Array.isArray(result.embeddings)) {\n for (const embedding of result.embeddings) {\n if (embedding.values && Array.isArray(embedding.values)) {\n embeddings.push(embedding.values)\n } else if (Array.isArray(embedding)) {\n embeddings.push(embedding)\n }\n }\n }\n\n const promptTokens = inputs.reduce(\n (sum, input) => sum + this.estimateTokens(input),\n 0,\n )\n\n return {\n id: this.generateId(),\n model: options.model || 'gemini-embedding-001',\n embeddings,\n usage: {\n promptTokens,\n totalTokens: promptTokens,\n },\n }\n }\n\n private buildSummarizationPrompt(\n options: SummarizationOptions,\n text: string,\n ): string {\n let prompt = 'You are a professional summarizer. '\n\n switch (options.style) {\n case 'bullet-points':\n prompt += 'Provide a summary in bullet point format. '\n break\n case 'paragraph':\n prompt += 'Provide a summary in paragraph format. '\n break\n case 'concise':\n prompt += 'Provide a very concise summary in 1-2 sentences. '\n break\n default:\n prompt += 'Provide a clear and concise summary. '\n }\n\n if (options.focus && options.focus.length > 0) {\n prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `\n }\n\n prompt += `\\n\\nText to summarize:\\n${text}\\n\\nSummary:`\n\n return prompt\n }\n\n private estimateTokens(text: string): number {\n // Rough approximation: 1 token ≈ 4 characters\n return Math.ceil(text.length / 4)\n }\n\n private async *processStreamChunks(\n result: AsyncGenerator<GenerateContentResponse, any, any>,\n model: string,\n ): AsyncIterable<StreamChunk> {\n const timestamp = Date.now()\n let accumulatedContent = ''\n const toolCallMap = new Map<\n string,\n { name: string; args: string; index: number }\n >()\n let nextToolIndex = 0\n // Iterate over the stream result (it's already an AsyncGenerator)\n for await (const chunk of result) {\n // Extract content from candidates[0].content.parts\n // Parts can contain text or functionCall\n if (chunk.candidates?.[0]?.content?.parts) {\n const parts = chunk.candidates[0].content.parts\n\n for (const part of parts) {\n // Handle text content\n if (part.text) {\n accumulatedContent += part.text\n yield {\n type: 'content',\n id: this.generateId(),\n model,\n timestamp,\n delta: part.text,\n content: accumulatedContent,\n role: 'assistant',\n }\n }\n\n // Handle function calls (tool calls)\n // Check both camelCase (SDK) and snake_case (direct API) formats\n const functionCall = part.functionCall\n if (functionCall) {\n const toolCallId =\n functionCall.name || `call_${Date.now()}_${nextToolIndex}`\n const functionArgs = functionCall.args || {}\n\n // Check if we've seen this tool call before (for streaming args)\n let toolCallData = toolCallMap.get(toolCallId)\n if (!toolCallData) {\n toolCallData = {\n name: functionCall.name || '',\n args:\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs),\n index: nextToolIndex++,\n }\n toolCallMap.set(toolCallId, toolCallData)\n } else {\n // Merge arguments if streaming\n\n try {\n const existingArgs = JSON.parse(toolCallData.args)\n const newArgs =\n typeof functionArgs === 'string'\n ? JSON.parse(functionArgs)\n : functionArgs\n const mergedArgs = { ...existingArgs, ...newArgs }\n toolCallData.args = JSON.stringify(mergedArgs)\n } catch {\n // If parsing fails, use new args\n toolCallData.args =\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs)\n }\n }\n\n yield {\n type: 'tool_call',\n id: this.generateId(),\n model,\n timestamp,\n toolCall: {\n id: toolCallId,\n type: 'function',\n function: {\n name: toolCallData.name,\n arguments: toolCallData.args,\n },\n },\n index: toolCallData.index,\n }\n }\n }\n } else if (chunk.data) {\n // Fallback to chunk.data if available\n accumulatedContent += chunk.data\n yield {\n type: 'content',\n id: this.generateId(),\n model,\n timestamp,\n delta: chunk.data,\n content: accumulatedContent,\n role: 'assistant',\n }\n }\n\n // Check for finish reason\n if (chunk.candidates?.[0]?.finishReason) {\n const finishReason = chunk.candidates[0].finishReason\n\n // UNEXPECTED_TOOL_CALL means Gemini tried to call a function but it wasn't properly declared\n // This typically means there's an issue with the tool declaration format\n // We should map it to tool_calls to try to process it anyway\n if (finishReason === FinishReason.UNEXPECTED_TOOL_CALL) {\n // Try to extract function call from content.parts if available\n if (chunk.candidates[0].content?.parts) {\n for (const part of chunk.candidates[0].content.parts) {\n const functionCall = part.functionCall\n if (functionCall) {\n // We found a function call - process it\n const toolCallId =\n functionCall.name || `call_${Date.now()}_${nextToolIndex}`\n const functionArgs = functionCall.args || {}\n\n toolCallMap.set(toolCallId, {\n name: functionCall.name || '',\n args:\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs),\n index: nextToolIndex++,\n })\n\n yield {\n type: 'tool_call',\n id: this.generateId(),\n model,\n timestamp,\n toolCall: {\n id: toolCallId,\n type: 'function',\n function: {\n name: functionCall.name || '',\n arguments:\n typeof functionArgs === 'string'\n ? functionArgs\n : JSON.stringify(functionArgs),\n },\n },\n index: nextToolIndex - 1,\n }\n }\n }\n }\n }\n if (finishReason === FinishReason.MAX_TOKENS) {\n yield {\n type: 'error',\n id: this.generateId(),\n model,\n timestamp,\n error: {\n message:\n 'The response was cut off because the maximum token limit was reached.',\n },\n }\n }\n\n yield {\n type: 'done',\n id: this.generateId(),\n model,\n timestamp,\n finishReason: toolCallMap.size > 0 ? 'tool_calls' : 'stop',\n usage: chunk.usageMetadata\n ? {\n promptTokens: chunk.usageMetadata.promptTokenCount ?? 0,\n completionTokens: chunk.usageMetadata.thoughtsTokenCount ?? 0,\n totalTokens: chunk.usageMetadata.totalTokenCount ?? 0,\n }\n : undefined,\n }\n }\n }\n }\n\n private convertContentPartToGemini(part: ContentPart): Part {\n switch (part.type) {\n case 'text':\n return { text: part.content }\n case 'image':\n case 'audio':\n case 'video':\n case 'document': {\n const metadata = part.metadata as\n | GeminiDocumentMetadata\n | GeminiImageMetadata\n | GeminiVideoMetadata\n | GeminiAudioMetadata\n | undefined\n // Gemini uses inlineData for base64 and fileData for URLs\n if (part.source.type === 'data') {\n return {\n inlineData: {\n data: part.source.value,\n mimeType: metadata?.mimeType ?? 'image/jpeg',\n },\n }\n } else {\n return {\n fileData: {\n fileUri: part.source.value,\n mimeType: metadata?.mimeType ?? 'image/jpeg',\n },\n }\n }\n }\n default: {\n // Exhaustive check - this should never happen with known types\n const _exhaustiveCheck: never = part\n throw new Error(\n `Unsupported content part type: ${(_exhaustiveCheck as ContentPart).type}`,\n )\n }\n }\n }\n\n private formatMessages(\n messages: Array<ModelMessage>,\n ): GenerateContentParameters['contents'] {\n return messages.map((msg) => {\n const role: 'user' | 'model' = msg.role === 'assistant' ? 'model' : 'user'\n const parts: Array<Part> = []\n\n // Handle multimodal content (array of ContentPart)\n if (Array.isArray(msg.content)) {\n for (const contentPart of msg.content) {\n parts.push(this.convertContentPartToGemini(contentPart))\n }\n } else if (msg.content) {\n // Handle string content (backward compatibility)\n parts.push({ text: msg.content })\n }\n\n // Handle tool calls (from assistant)\n if (msg.role === 'assistant' && msg.toolCalls?.length) {\n for (const toolCall of msg.toolCalls) {\n let parsedArgs: Record<string, unknown> = {}\n try {\n parsedArgs = toolCall.function.arguments\n ? JSON.parse(toolCall.function.arguments)\n : {}\n } catch {\n parsedArgs = toolCall.function.arguments as any\n }\n\n parts.push({\n functionCall: {\n name: toolCall.function.name,\n args: parsedArgs,\n },\n })\n }\n }\n\n // Handle tool results (from tool role)\n if (msg.role === 'tool' && msg.toolCallId) {\n parts.push({\n functionResponse: {\n name: msg.toolCallId, // Gemini uses function name here\n response: {\n content: msg.content || '',\n },\n },\n })\n }\n\n return {\n role,\n parts: parts.length > 0 ? parts : [{ text: '' }],\n }\n })\n }\n /**\n * Maps common options to Gemini-specific format\n * Handles translation of normalized options to Gemini's API format\n */\n private mapCommonOptionsToGemini(options: ChatOptions) {\n const providerOpts = options.providerOptions\n const requestOptions: GenerateContentParameters = {\n model: options.model,\n contents: this.formatMessages(options.messages),\n config: {\n ...providerOpts,\n temperature: options.options?.temperature,\n topP: options.options?.topP,\n maxOutputTokens: options.options?.maxTokens,\n systemInstruction: options.systemPrompts?.join('\\n'),\n ...providerOpts?.generationConfig,\n tools: convertToolsToProviderFormat(options.tools),\n },\n }\n\n return requestOptions\n }\n}\n\n/**\n * Creates a Gemini adapter with simplified configuration\n * @param apiKey - Your Google API key\n * @returns A fully configured Gemini adapter instance\n *\n * @example\n * ```typescript\n * const gemini = createGemini(\"AIza...\");\n *\n * const ai = new AI({\n * adapters: {\n * gemini,\n * }\n * });\n * ```\n */\nexport function createGemini(\n apiKey: string,\n config?: Omit<GeminiAdapterConfig, 'apiKey'>,\n): GeminiAdapter {\n return new GeminiAdapter({ apiKey, ...config })\n}\n\n/**\n * Create a Gemini adapter with automatic API key detection from environment variables.\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 * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Gemini adapter instance\n * @throws Error if API key is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses GOOGLE_API_KEY or GEMINI_API_KEY from environment\n * const aiInstance = ai(gemini());\n * ```\n */\nexport function gemini(\n config?: Omit<GeminiAdapterConfig, 'apiKey'>,\n): GeminiAdapter {\n const env =\n typeof globalThis !== 'undefined' && (globalThis as any).window?.env\n ? (globalThis as any).window.env\n : typeof process !== 'undefined'\n ? process.env\n : undefined\n const key = env?.GOOGLE_API_KEY || env?.GEMINI_API_KEY\n\n if (!key) {\n throw new Error(\n 'GOOGLE_API_KEY or GEMINI_API_KEY is required. Please set it in your environment variables or use createGemini(apiKey, config) instead.',\n )\n }\n\n return createGemini(key, config)\n}\n"],"names":[],"mappings":";;;;AA4CO,MAAM,sBAAsB,YAQjC;AAAA,EASA,YAAY,QAA6B;AACvC,UAAM,MAAM;AATd,SAAA,OAAO;AACP,SAAA,SAAS;AACT,SAAA,kBAAkB;AAQhB,SAAK,SAAS,IAAI,YAAY;AAAA,MAC5B,QAAQ,OAAO;AAAA,IAAA,CAChB;AAAA,EACH;AAAA,EAEA,OAAO,WACL,SAC4B;AAE5B,UAAM,gBAAgB,KAAK,yBAAyB,OAAO;AAE3D,QAAI;AACF,YAAM,SACJ,MAAM,KAAK,OAAO,OAAO,sBAAsB,aAAa;AAE9D,aAAO,KAAK,oBAAoB,QAAQ,QAAQ,KAAK;AAAA,IACvD,SAAS,OAAO;AACd,YAAM,YAAY,KAAK,IAAA;AACvB,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,IAAI,KAAK,WAAA;AAAA,QACT,OAAO,QAAQ;AAAA,QACf;AAAA,QACA,OAAO;AAAA,UACL,SACE,iBAAiB,QACb,MAAM,UACN;AAAA,QAAA;AAAA,MACR;AAAA,IAEJ;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,SAA6D;AAC3E,UAAM,SAAS,KAAK,yBAAyB,SAAS,QAAQ,IAAI;AAGlE,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,gBAAgB;AAAA,MACtD,OAAO,QAAQ;AAAA,MACf,UAAU,CAAC,EAAE,MAAM,QAAQ,OAAO,CAAC,EAAE,MAAM,OAAA,CAAQ,GAAG;AAAA,MACtD,QAAQ;AAAA,QACN,aAAa;AAAA,QACb,iBAAiB,QAAQ,aAAa;AAAA,MAAA;AAAA,IACxC,CACD;AAGD,QAAI,UAAU;AACd,QAAI,OAAO,aAAa,CAAC,GAAG,SAAS,OAAO;AAC1C,YAAM,QAAQ,OAAO,WAAW,CAAC,EAAE,QAAQ;AAC3C,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,MAAM;AACb,qBAAW,KAAK;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,WAAW,OAAO,OAAO,SAAS,UAAU;AAC/C,gBAAU,OAAO;AAAA,IACnB;AAEA,UAAM,eAAe,KAAK,eAAe,MAAM;AAC/C,UAAM,mBAAmB,KAAK,eAAe,OAAO;AAEpD,WAAO;AAAA,MACL,IAAI,KAAK,WAAA;AAAA,MACT,OAAO,QAAQ;AAAA,MACf;AAAA,MACA,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,aAAa,eAAe;AAAA,MAAA;AAAA,IAC9B;AAAA,EAEJ;AAAA,EAEA,MAAM,iBAAiB,SAAqD;AAC1E,UAAM,SAAS,MAAM,QAAQ,QAAQ,KAAK,IACtC,QAAQ,QACR,CAAC,QAAQ,KAAK;AAIlB,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,aAAa;AAAA,MACnD,OAAO,QAAQ;AAAA,MACf,UAAU;AAAA,IAAA,CACX;AAGD,UAAM,aAAmC,CAAA;AACzC,QAAI,OAAO,cAAc,MAAM,QAAQ,OAAO,UAAU,GAAG;AACzD,iBAAW,aAAa,OAAO,YAAY;AACzC,YAAI,UAAU,UAAU,MAAM,QAAQ,UAAU,MAAM,GAAG;AACvD,qBAAW,KAAK,UAAU,MAAM;AAAA,QAClC,WAAW,MAAM,QAAQ,SAAS,GAAG;AACnC,qBAAW,KAAK,SAAS;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAEA,UAAM,eAAe,OAAO;AAAA,MAC1B,CAAC,KAAK,UAAU,MAAM,KAAK,eAAe,KAAK;AAAA,MAC/C;AAAA,IAAA;AAGF,WAAO;AAAA,MACL,IAAI,KAAK,WAAA;AAAA,MACT,OAAO,QAAQ,SAAS;AAAA,MACxB;AAAA,MACA,OAAO;AAAA,QACL;AAAA,QACA,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,EAEJ;AAAA,EAEQ,yBACN,SACA,MACQ;AACR,QAAI,SAAS;AAEb,YAAQ,QAAQ,OAAA;AAAA,MACd,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF;AACE,kBAAU;AAAA,IAAA;AAGd,QAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,GAAG;AAC7C,gBAAU,mCAAmC,QAAQ,MAAM,KAAK,IAAI,CAAC;AAAA,IACvE;AAEA,cAAU;AAAA;AAAA;AAAA,EAA2B,IAAI;AAAA;AAAA;AAEzC,WAAO;AAAA,EACT;AAAA,EAEQ,eAAe,MAAsB;AAE3C,WAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AAAA,EAClC;AAAA,EAEA,OAAe,oBACb,QACA,OAC4B;AAC5B,UAAM,YAAY,KAAK,IAAA;AACvB,QAAI,qBAAqB;AACzB,UAAM,kCAAkB,IAAA;AAIxB,QAAI,gBAAgB;AAEpB,qBAAiB,SAAS,QAAQ;AAGhC,UAAI,MAAM,aAAa,CAAC,GAAG,SAAS,OAAO;AACzC,cAAM,QAAQ,MAAM,WAAW,CAAC,EAAE,QAAQ;AAE1C,mBAAW,QAAQ,OAAO;AAExB,cAAI,KAAK,MAAM;AACb,kCAAsB,KAAK;AAC3B,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,IAAI,KAAK,WAAA;AAAA,cACT;AAAA,cACA;AAAA,cACA,OAAO,KAAK;AAAA,cACZ,SAAS;AAAA,cACT,MAAM;AAAA,YAAA;AAAA,UAEV;AAIA,gBAAM,eAAe,KAAK;AAC1B,cAAI,cAAc;AAChB,kBAAM,aACJ,aAAa,QAAQ,QAAQ,KAAK,IAAA,CAAK,IAAI,aAAa;AAC1D,kBAAM,eAAe,aAAa,QAAQ,CAAA;AAG1C,gBAAI,eAAe,YAAY,IAAI,UAAU;AAC7C,gBAAI,CAAC,cAAc;AACjB,6BAAe;AAAA,gBACb,MAAM,aAAa,QAAQ;AAAA,gBAC3B,MACE,OAAO,iBAAiB,WACpB,eACA,KAAK,UAAU,YAAY;AAAA,gBACjC,OAAO;AAAA,cAAA;AAET,0BAAY,IAAI,YAAY,YAAY;AAAA,YAC1C,OAAO;AAGL,kBAAI;AACF,sBAAM,eAAe,KAAK,MAAM,aAAa,IAAI;AACjD,sBAAM,UACJ,OAAO,iBAAiB,WACpB,KAAK,MAAM,YAAY,IACvB;AACN,sBAAM,aAAa,EAAE,GAAG,cAAc,GAAG,QAAA;AACzC,6BAAa,OAAO,KAAK,UAAU,UAAU;AAAA,cAC/C,QAAQ;AAEN,6BAAa,OACX,OAAO,iBAAiB,WACpB,eACA,KAAK,UAAU,YAAY;AAAA,cACnC;AAAA,YACF;AAEA,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,IAAI,KAAK,WAAA;AAAA,cACT;AAAA,cACA;AAAA,cACA,UAAU;AAAA,gBACR,IAAI;AAAA,gBACJ,MAAM;AAAA,gBACN,UAAU;AAAA,kBACR,MAAM,aAAa;AAAA,kBACnB,WAAW,aAAa;AAAA,gBAAA;AAAA,cAC1B;AAAA,cAEF,OAAO,aAAa;AAAA,YAAA;AAAA,UAExB;AAAA,QACF;AAAA,MACF,WAAW,MAAM,MAAM;AAErB,8BAAsB,MAAM;AAC5B,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,IAAI,KAAK,WAAA;AAAA,UACT;AAAA,UACA;AAAA,UACA,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,UACT,MAAM;AAAA,QAAA;AAAA,MAEV;AAGA,UAAI,MAAM,aAAa,CAAC,GAAG,cAAc;AACvC,cAAM,eAAe,MAAM,WAAW,CAAC,EAAE;AAKzC,YAAI,iBAAiB,aAAa,sBAAsB;AAEtD,cAAI,MAAM,WAAW,CAAC,EAAE,SAAS,OAAO;AACtC,uBAAW,QAAQ,MAAM,WAAW,CAAC,EAAE,QAAQ,OAAO;AACpD,oBAAM,eAAe,KAAK;AAC1B,kBAAI,cAAc;AAEhB,sBAAM,aACJ,aAAa,QAAQ,QAAQ,KAAK,IAAA,CAAK,IAAI,aAAa;AAC1D,sBAAM,eAAe,aAAa,QAAQ,CAAA;AAE1C,4BAAY,IAAI,YAAY;AAAA,kBAC1B,MAAM,aAAa,QAAQ;AAAA,kBAC3B,MACE,OAAO,iBAAiB,WACpB,eACA,KAAK,UAAU,YAAY;AAAA,kBACjC,OAAO;AAAA,gBAAA,CACR;AAED,sBAAM;AAAA,kBACJ,MAAM;AAAA,kBACN,IAAI,KAAK,WAAA;AAAA,kBACT;AAAA,kBACA;AAAA,kBACA,UAAU;AAAA,oBACR,IAAI;AAAA,oBACJ,MAAM;AAAA,oBACN,UAAU;AAAA,sBACR,MAAM,aAAa,QAAQ;AAAA,sBAC3B,WACE,OAAO,iBAAiB,WACpB,eACA,KAAK,UAAU,YAAY;AAAA,oBAAA;AAAA,kBACnC;AAAA,kBAEF,OAAO,gBAAgB;AAAA,gBAAA;AAAA,cAE3B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,YAAI,iBAAiB,aAAa,YAAY;AAC5C,gBAAM;AAAA,YACJ,MAAM;AAAA,YACN,IAAI,KAAK,WAAA;AAAA,YACT;AAAA,YACA;AAAA,YACA,OAAO;AAAA,cACL,SACE;AAAA,YAAA;AAAA,UACJ;AAAA,QAEJ;AAEA,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,IAAI,KAAK,WAAA;AAAA,UACT;AAAA,UACA;AAAA,UACA,cAAc,YAAY,OAAO,IAAI,eAAe;AAAA,UACpD,OAAO,MAAM,gBACT;AAAA,YACE,cAAc,MAAM,cAAc,oBAAoB;AAAA,YACtD,kBAAkB,MAAM,cAAc,sBAAsB;AAAA,YAC5D,aAAa,MAAM,cAAc,mBAAmB;AAAA,UAAA,IAEtD;AAAA,QAAA;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAA2B,MAAyB;AAC1D,YAAQ,KAAK,MAAA;AAAA,MACX,KAAK;AACH,eAAO,EAAE,MAAM,KAAK,QAAA;AAAA,MACtB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,YAAY;AACf,cAAM,WAAW,KAAK;AAOtB,YAAI,KAAK,OAAO,SAAS,QAAQ;AAC/B,iBAAO;AAAA,YACL,YAAY;AAAA,cACV,MAAM,KAAK,OAAO;AAAA,cAClB,UAAU,UAAU,YAAY;AAAA,YAAA;AAAA,UAClC;AAAA,QAEJ,OAAO;AACL,iBAAO;AAAA,YACL,UAAU;AAAA,cACR,SAAS,KAAK,OAAO;AAAA,cACrB,UAAU,UAAU,YAAY;AAAA,YAAA;AAAA,UAClC;AAAA,QAEJ;AAAA,MACF;AAAA,MACA,SAAS;AAEP,cAAM,mBAA0B;AAChC,cAAM,IAAI;AAAA,UACR,kCAAmC,iBAAiC,IAAI;AAAA,QAAA;AAAA,MAE5E;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEQ,eACN,UACuC;AACvC,WAAO,SAAS,IAAI,CAAC,QAAQ;AAC3B,YAAM,OAAyB,IAAI,SAAS,cAAc,UAAU;AACpE,YAAM,QAAqB,CAAA;AAG3B,UAAI,MAAM,QAAQ,IAAI,OAAO,GAAG;AAC9B,mBAAW,eAAe,IAAI,SAAS;AACrC,gBAAM,KAAK,KAAK,2BAA2B,WAAW,CAAC;AAAA,QACzD;AAAA,MACF,WAAW,IAAI,SAAS;AAEtB,cAAM,KAAK,EAAE,MAAM,IAAI,SAAS;AAAA,MAClC;AAGA,UAAI,IAAI,SAAS,eAAe,IAAI,WAAW,QAAQ;AACrD,mBAAW,YAAY,IAAI,WAAW;AACpC,cAAI,aAAsC,CAAA;AAC1C,cAAI;AACF,yBAAa,SAAS,SAAS,YAC3B,KAAK,MAAM,SAAS,SAAS,SAAS,IACtC,CAAA;AAAA,UACN,QAAQ;AACN,yBAAa,SAAS,SAAS;AAAA,UACjC;AAEA,gBAAM,KAAK;AAAA,YACT,cAAc;AAAA,cACZ,MAAM,SAAS,SAAS;AAAA,cACxB,MAAM;AAAA,YAAA;AAAA,UACR,CACD;AAAA,QACH;AAAA,MACF;AAGA,UAAI,IAAI,SAAS,UAAU,IAAI,YAAY;AACzC,cAAM,KAAK;AAAA,UACT,kBAAkB;AAAA,YAChB,MAAM,IAAI;AAAA;AAAA,YACV,UAAU;AAAA,cACR,SAAS,IAAI,WAAW;AAAA,YAAA;AAAA,UAC1B;AAAA,QACF,CACD;AAAA,MACH;AAEA,aAAO;AAAA,QACL;AAAA,QACA,OAAO,MAAM,SAAS,IAAI,QAAQ,CAAC,EAAE,MAAM,GAAA,CAAI;AAAA,MAAA;AAAA,IAEnD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKQ,yBAAyB,SAAsB;AACrD,UAAM,eAAe,QAAQ;AAC7B,UAAM,iBAA4C;AAAA,MAChD,OAAO,QAAQ;AAAA,MACf,UAAU,KAAK,eAAe,QAAQ,QAAQ;AAAA,MAC9C,QAAQ;AAAA,QACN,GAAG;AAAA,QACH,aAAa,QAAQ,SAAS;AAAA,QAC9B,MAAM,QAAQ,SAAS;AAAA,QACvB,iBAAiB,QAAQ,SAAS;AAAA,QAClC,mBAAmB,QAAQ,eAAe,KAAK,IAAI;AAAA,QACnD,GAAG,cAAc;AAAA,QACjB,OAAO,6BAA6B,QAAQ,KAAK;AAAA,MAAA;AAAA,IACnD;AAGF,WAAO;AAAA,EACT;AACF;AAkBO,SAAS,aACd,QACA,QACe;AACf,SAAO,IAAI,cAAc,EAAE,QAAQ,GAAG,QAAQ;AAChD;AAmBO,SAAS,OACd,QACe;AACf,QAAM,MACJ,OAAO,eAAe,eAAgB,WAAmB,QAAQ,MAC5D,WAAmB,OAAO,MAC3B,OAAO,YAAY,cACjB,QAAQ,MACR;AACR,QAAM,MAAM,KAAK,kBAAkB,KAAK;AAExC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO,aAAa,KAAK,MAAM;AACjC;"}
|