@umituz/react-native-ai-gemini-provider 3.0.26 → 3.0.28
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/dist/domain/entities/gemini.types.d.ts +2 -7
- package/dist/infrastructure/services/BaseService.d.ts +1 -1
- package/dist/infrastructure/utils/content-mapper.util.d.ts +1 -1
- package/package.json +1 -1
- package/src/domain/entities/error.types.ts +3 -3
- package/src/domain/entities/gemini.types.ts +2 -7
- package/src/index.ts +4 -5
- package/src/infrastructure/services/BaseService.ts +2 -1
- package/src/infrastructure/services/ChatSession.ts +34 -6
- package/src/infrastructure/services/GeminiClient.ts +1 -2
- package/src/infrastructure/services/Streaming.ts +1 -1
- package/src/infrastructure/services/StructuredText.ts +5 -1
- package/src/infrastructure/telemetry/TelemetryHooks.ts +6 -3
- package/src/infrastructure/utils/content-mapper.util.ts +2 -1
- package/src/infrastructure/utils/error-mapper.util.ts +30 -5
- package/src/infrastructure/utils/gemini-data-transformer.util.ts +4 -0
- package/src/infrastructure/utils/stream-processor.util.ts +6 -8
- package/src/presentation/hooks/useGemini.ts +3 -2
- package/src/providers/ConfigBuilder.ts +2 -1
- package/src/providers/ProviderFactory.ts +2 -9
- package/src/infrastructure/services/GeminiProvider.ts +0 -38
- package/src/infrastructure/services/index.ts +0 -16
- package/src/infrastructure/telemetry/index.ts +0 -5
- package/src/infrastructure/utils/async/index.ts +0 -8
- package/src/presentation/hooks/index.ts +0 -1
- package/src/providers/index.ts +0 -9
|
@@ -5,20 +5,15 @@ import type { GenerationConfig } from "@google/generative-ai";
|
|
|
5
5
|
export interface GeminiConfig {
|
|
6
6
|
/** API key for authentication */
|
|
7
7
|
apiKey: string;
|
|
8
|
-
/**
|
|
9
|
-
baseUrl?: string;
|
|
10
|
-
/** Default timeout in milliseconds */
|
|
8
|
+
/** Default timeout in milliseconds (used by external consumers for timeout logic) */
|
|
11
9
|
defaultTimeoutMs?: number;
|
|
12
10
|
/** Default model to use for text generation */
|
|
13
11
|
textModel?: string;
|
|
14
12
|
}
|
|
15
13
|
/**
|
|
16
14
|
* Generation configuration for AI requests
|
|
17
|
-
* Extends the SDK's GenerationConfig with proper schema typing
|
|
18
15
|
*/
|
|
19
|
-
export type GeminiGenerationConfig =
|
|
20
|
-
responseSchema?: GenerationConfig["responseSchema"];
|
|
21
|
-
};
|
|
16
|
+
export type GeminiGenerationConfig = GenerationConfig;
|
|
22
17
|
/**
|
|
23
18
|
* Harm categories for content safety filtering
|
|
24
19
|
*/
|
|
@@ -42,4 +42,4 @@ export declare function transformResponse(response: {
|
|
|
42
42
|
/**
|
|
43
43
|
* Extract text from content parts
|
|
44
44
|
*/
|
|
45
|
-
export declare function extractTextFromParts(parts: GeminiPart[]): string;
|
|
45
|
+
export declare function extractTextFromParts(parts: GeminiPart[] | undefined): string;
|
package/package.json
CHANGED
|
@@ -118,9 +118,9 @@ export class GeminiError extends Error {
|
|
|
118
118
|
static fromError(error: unknown, info: GeminiErrorInfo): GeminiError {
|
|
119
119
|
const geminiError = new GeminiError(info);
|
|
120
120
|
|
|
121
|
-
//
|
|
122
|
-
if (error instanceof Error && error.stack
|
|
123
|
-
geminiError.stack = error.stack
|
|
121
|
+
// Preserve original error's stack trace for better debugging
|
|
122
|
+
if (error instanceof Error && error.stack) {
|
|
123
|
+
geminiError.stack = `${geminiError.stack}\nCaused by: ${error.stack}`;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
return geminiError;
|
|
@@ -6,9 +6,7 @@ import type { GenerationConfig } from "@google/generative-ai";
|
|
|
6
6
|
export interface GeminiConfig {
|
|
7
7
|
/** API key for authentication */
|
|
8
8
|
apiKey: string;
|
|
9
|
-
/**
|
|
10
|
-
baseUrl?: string;
|
|
11
|
-
/** Default timeout in milliseconds */
|
|
9
|
+
/** Default timeout in milliseconds (used by external consumers for timeout logic) */
|
|
12
10
|
defaultTimeoutMs?: number;
|
|
13
11
|
/** Default model to use for text generation */
|
|
14
12
|
textModel?: string;
|
|
@@ -16,11 +14,8 @@ export interface GeminiConfig {
|
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
16
|
* Generation configuration for AI requests
|
|
19
|
-
* Extends the SDK's GenerationConfig with proper schema typing
|
|
20
17
|
*/
|
|
21
|
-
export type GeminiGenerationConfig =
|
|
22
|
-
responseSchema?: GenerationConfig["responseSchema"];
|
|
23
|
-
};
|
|
18
|
+
export type GeminiGenerationConfig = GenerationConfig;
|
|
24
19
|
|
|
25
20
|
/**
|
|
26
21
|
* Harm categories for content safety filtering
|
package/src/index.ts
CHANGED
|
@@ -48,15 +48,14 @@ export {
|
|
|
48
48
|
export { textGeneration } from "./infrastructure/services/TextGeneration";
|
|
49
49
|
export { structuredText } from "./infrastructure/services/StructuredText";
|
|
50
50
|
export { streaming } from "./infrastructure/services/Streaming";
|
|
51
|
-
export { geminiProvider, GeminiProvider } from "./infrastructure/services/GeminiProvider";
|
|
52
51
|
|
|
53
52
|
// React Hook
|
|
54
|
-
export { useGemini } from "./presentation/hooks";
|
|
55
|
-
export type { UseGeminiOptions, UseGeminiReturn } from "./presentation/hooks";
|
|
53
|
+
export { useGemini } from "./presentation/hooks/useGemini";
|
|
54
|
+
export type { UseGeminiOptions, UseGeminiReturn } from "./presentation/hooks/useGemini";
|
|
56
55
|
|
|
57
56
|
// Provider Configuration & Factory
|
|
58
|
-
export { ConfigBuilder, providerFactory } from "./providers";
|
|
57
|
+
export { ConfigBuilder, providerFactory } from "./providers/ProviderFactory";
|
|
59
58
|
export type {
|
|
60
59
|
ProviderConfig,
|
|
61
60
|
ProviderFactoryOptions,
|
|
62
|
-
} from "./providers";
|
|
61
|
+
} from "./providers/ProviderFactory";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { geminiClient } from "./GeminiClient";
|
|
2
2
|
import { toSdkContent } from "../utils/content-mapper.util";
|
|
3
3
|
import { createGeminiError } from "../utils/error-mapper.util";
|
|
4
|
+
import { GeminiError } from "../../domain/entities";
|
|
4
5
|
import type { GeminiContent, GeminiGenerationConfig } from "../../domain/entities";
|
|
5
6
|
import type { GenerativeModel } from "@google/generative-ai";
|
|
6
7
|
|
|
@@ -31,7 +32,7 @@ export abstract class BaseGeminiService {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
protected handleError(error: unknown, abortMessage: string): never {
|
|
34
|
-
if (error instanceof
|
|
35
|
+
if (error instanceof GeminiError) {
|
|
35
36
|
throw error;
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -64,9 +64,20 @@ export function resolveAudioMimeType(extension: string): string {
|
|
|
64
64
|
return AUDIO_MIME[extension.toLowerCase()] ?? "audio/mp4";
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
const IMAGE_MIME: Record<string, string> = {
|
|
68
|
+
png: "image/png",
|
|
69
|
+
jpg: "image/jpeg",
|
|
70
|
+
jpeg: "image/jpeg",
|
|
71
|
+
webp: "image/webp",
|
|
72
|
+
gif: "image/gif",
|
|
73
|
+
heic: "image/heic",
|
|
74
|
+
heif: "image/heif",
|
|
75
|
+
bmp: "image/bmp",
|
|
76
|
+
};
|
|
77
|
+
|
|
67
78
|
/** Resolve MIME type for an image file extension */
|
|
68
79
|
export function resolveImageMimeType(extension: string): string {
|
|
69
|
-
return extension.toLowerCase()
|
|
80
|
+
return IMAGE_MIME[extension.toLowerCase()] ?? "image/jpeg";
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
// ─── History Utilities ───────────────────────────────────────────────────────
|
|
@@ -90,9 +101,12 @@ export function buildChatHistory(
|
|
|
90
101
|
const last = result[result.length - 1];
|
|
91
102
|
|
|
92
103
|
if (last && last.role === role) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
// Merge by extracting all text from existing parts and appending new content
|
|
105
|
+
const existingText = last.parts
|
|
106
|
+
.map((p) => ("text" in p ? (p.text ?? "") : ""))
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join("");
|
|
109
|
+
last.parts = [{ text: existingText + "\n" + m.content }];
|
|
96
110
|
} else {
|
|
97
111
|
result.push({ role, parts: [{ text: m.content }] });
|
|
98
112
|
}
|
|
@@ -162,7 +176,17 @@ export function createChatSession(config: GeminiChatConfig = {}) {
|
|
|
162
176
|
const result = await chat.sendMessage(parts as Part[]);
|
|
163
177
|
if (!result.response) throw new Error("No response from Gemini SDK");
|
|
164
178
|
const candidate = result.response.candidates?.[0];
|
|
165
|
-
|
|
179
|
+
|
|
180
|
+
// SDK's text() throws on safety-blocked responses with no text
|
|
181
|
+
let text: string;
|
|
182
|
+
try {
|
|
183
|
+
text = result.response.text();
|
|
184
|
+
} catch {
|
|
185
|
+
if (String(candidate?.finishReason) === "SAFETY") {
|
|
186
|
+
throw new Error("Response blocked by safety filter.");
|
|
187
|
+
}
|
|
188
|
+
throw new Error("No text content in response");
|
|
189
|
+
}
|
|
166
190
|
|
|
167
191
|
if (__DEV__) {
|
|
168
192
|
console.log("[ChatSession.send] <<< GEMINI SDK RESPONSE");
|
|
@@ -175,7 +199,7 @@ export function createChatSession(config: GeminiChatConfig = {}) {
|
|
|
175
199
|
|
|
176
200
|
return {
|
|
177
201
|
text,
|
|
178
|
-
finishReason: candidate?.finishReason
|
|
202
|
+
finishReason: candidate?.finishReason,
|
|
179
203
|
};
|
|
180
204
|
},
|
|
181
205
|
};
|
|
@@ -200,6 +224,10 @@ export function createChatSession(config: GeminiChatConfig = {}) {
|
|
|
200
224
|
export async function sendChatMessage(
|
|
201
225
|
opts: SendChatMessageOptions,
|
|
202
226
|
): Promise<string> {
|
|
227
|
+
if (!opts.message || opts.message.trim().length === 0) {
|
|
228
|
+
throw new Error("Message cannot be empty");
|
|
229
|
+
}
|
|
230
|
+
|
|
203
231
|
if (__DEV__) {
|
|
204
232
|
console.log("═══════════════════════════════════════════════════");
|
|
205
233
|
console.log("[sendChatMessage] >>> START");
|
|
@@ -26,12 +26,11 @@ class GeminiClient {
|
|
|
26
26
|
private initialized = false;
|
|
27
27
|
|
|
28
28
|
initialize(config: GeminiConfig): void {
|
|
29
|
-
if (this.initialized) return;
|
|
30
|
-
|
|
31
29
|
if (!config.apiKey || config.apiKey.trim().length < 10) {
|
|
32
30
|
throw new Error("API key is required and must be at least 10 characters");
|
|
33
31
|
}
|
|
34
32
|
|
|
33
|
+
// Allow re-initialization with new config (e.g. API key change)
|
|
35
34
|
this.client = new GoogleGenerativeAI(config.apiKey);
|
|
36
35
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
37
36
|
this.initialized = true;
|
|
@@ -16,6 +16,10 @@ class StructuredTextService {
|
|
|
16
16
|
config?: Omit<GeminiGenerationConfig, "responseMimeType" | "responseSchema">,
|
|
17
17
|
signal?: AbortSignal,
|
|
18
18
|
): Promise<T> {
|
|
19
|
+
if (!prompt || prompt.trim().length < 3) {
|
|
20
|
+
throw new Error("Prompt must be at least 3 characters");
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
if (!schema || typeof schema !== "object" || Object.keys(schema).length === 0) {
|
|
20
24
|
throw new Error("Schema must be a non-empty object");
|
|
21
25
|
}
|
|
@@ -47,7 +51,7 @@ class StructuredTextService {
|
|
|
47
51
|
throw new Error("No candidates in response");
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
const text = extractTextFromParts(candidates[0]
|
|
54
|
+
const text = extractTextFromParts(candidates[0]?.content?.parts);
|
|
51
55
|
|
|
52
56
|
if (!text || text.trim().length === 0) {
|
|
53
57
|
throw new Error("Empty response received from Gemini");
|
|
@@ -40,7 +40,9 @@ class TelemetryHooks {
|
|
|
40
40
|
* Emit a telemetry event to all listeners
|
|
41
41
|
*/
|
|
42
42
|
emit(event: TelemetryEvent): void {
|
|
43
|
-
|
|
43
|
+
// Snapshot to prevent mutation during iteration
|
|
44
|
+
const snapshot = [...this.listeners];
|
|
45
|
+
for (const listener of snapshot) {
|
|
44
46
|
// Skip listeners that have failed too many times
|
|
45
47
|
if (this.failedListeners.has(listener)) {
|
|
46
48
|
continue;
|
|
@@ -85,12 +87,13 @@ class TelemetryHooks {
|
|
|
85
87
|
* Log response received
|
|
86
88
|
*/
|
|
87
89
|
logResponse(model: string, startTime: number, feature?: string, metadata?: Record<string, unknown>): void {
|
|
90
|
+
const now = Date.now();
|
|
88
91
|
this.emit({
|
|
89
92
|
type: "response",
|
|
90
|
-
timestamp:
|
|
93
|
+
timestamp: now,
|
|
91
94
|
model,
|
|
92
95
|
feature,
|
|
93
|
-
duration:
|
|
96
|
+
duration: now - startTime,
|
|
94
97
|
metadata,
|
|
95
98
|
});
|
|
96
99
|
}
|
|
@@ -159,7 +159,8 @@ export function transformResponse(
|
|
|
159
159
|
/**
|
|
160
160
|
* Extract text from content parts
|
|
161
161
|
*/
|
|
162
|
-
export function extractTextFromParts(parts: GeminiPart[]): string {
|
|
162
|
+
export function extractTextFromParts(parts: GeminiPart[] | undefined): string {
|
|
163
|
+
if (!parts || parts.length === 0) return "";
|
|
163
164
|
return parts
|
|
164
165
|
.map((part) => ("text" in part ? (part.text || "") : ""))
|
|
165
166
|
.join("");
|
|
@@ -27,7 +27,7 @@ const ERROR_PATTERNS: Array<{
|
|
|
27
27
|
retryable: false,
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
pattern: ["safety", "
|
|
30
|
+
pattern: ["safety", "safety filter", "harmful", "blocked by safety"],
|
|
31
31
|
type: GeminiErrorType.SAFETY,
|
|
32
32
|
retryable: false,
|
|
33
33
|
},
|
|
@@ -76,21 +76,46 @@ function matchesPattern(message: string, patterns: string[]): boolean {
|
|
|
76
76
|
return patterns.some((pattern) => {
|
|
77
77
|
const lowerPattern = pattern.toLowerCase();
|
|
78
78
|
|
|
79
|
-
// Use word boundary matching for
|
|
79
|
+
// Use word boundary matching for accuracy
|
|
80
80
|
// This prevents "invalid" from matching "valid"
|
|
81
81
|
const words = lowerPattern.split(/\s+/);
|
|
82
82
|
return words.every((word) => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return regex.test(lower) || lower.includes(word);
|
|
83
|
+
const escaped = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
84
|
+
return new RegExp(`\\b${escaped}\\b`, 'i').test(lower);
|
|
86
85
|
});
|
|
87
86
|
});
|
|
88
87
|
}
|
|
89
88
|
|
|
89
|
+
/** Map HTTP status codes to error types as a primary classification signal */
|
|
90
|
+
const STATUS_CODE_MAP: Record<number, { type: GeminiErrorType; retryable: boolean }> = {
|
|
91
|
+
400: { type: GeminiErrorType.VALIDATION, retryable: false },
|
|
92
|
+
401: { type: GeminiErrorType.AUTHENTICATION, retryable: false },
|
|
93
|
+
403: { type: GeminiErrorType.AUTHENTICATION, retryable: false },
|
|
94
|
+
404: { type: GeminiErrorType.MODEL_NOT_FOUND, retryable: false },
|
|
95
|
+
429: { type: GeminiErrorType.RATE_LIMIT, retryable: true },
|
|
96
|
+
500: { type: GeminiErrorType.SERVER, retryable: true },
|
|
97
|
+
502: { type: GeminiErrorType.SERVER, retryable: true },
|
|
98
|
+
503: { type: GeminiErrorType.SERVER, retryable: true },
|
|
99
|
+
504: { type: GeminiErrorType.SERVER, retryable: true },
|
|
100
|
+
};
|
|
101
|
+
|
|
90
102
|
function mapGeminiError(error: unknown): GeminiErrorInfo {
|
|
91
103
|
const message = error instanceof Error ? error.message : String(error);
|
|
92
104
|
const statusCode = getStatusCode(error);
|
|
93
105
|
|
|
106
|
+
// Primary: classify by HTTP status code when available
|
|
107
|
+
if (statusCode && STATUS_CODE_MAP[statusCode]) {
|
|
108
|
+
const { type, retryable } = STATUS_CODE_MAP[statusCode];
|
|
109
|
+
return {
|
|
110
|
+
type,
|
|
111
|
+
messageKey: `error.gemini.${type.toLowerCase()}`,
|
|
112
|
+
retryable,
|
|
113
|
+
originalError: error,
|
|
114
|
+
statusCode,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Secondary: classify by error message pattern
|
|
94
119
|
for (const { pattern, type, retryable } of ERROR_PATTERNS) {
|
|
95
120
|
const patterns = Array.isArray(pattern) ? pattern : [pattern.source];
|
|
96
121
|
|
|
@@ -24,6 +24,10 @@ export function extractTextFromResponse(response: GeminiResponse): string {
|
|
|
24
24
|
break;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
if (!candidate.content?.parts) {
|
|
28
|
+
throw new Error("No content in response candidate");
|
|
29
|
+
}
|
|
30
|
+
|
|
27
31
|
const textPart = candidate.content.parts.find(
|
|
28
32
|
(p): p is { text: string } => "text" in p && typeof p.text === "string",
|
|
29
33
|
);
|
|
@@ -21,14 +21,12 @@ export async function processStream(
|
|
|
21
21
|
let fullText = "";
|
|
22
22
|
|
|
23
23
|
for await (const chunk of stream) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} catch (chunkError) {
|
|
31
|
-
logError(onError, chunkError, "stream-chunk");
|
|
24
|
+
// chunk.text() errors are critical (e.g. safety blocks mid-stream)
|
|
25
|
+
// and must propagate, unlike callback errors which are safe to swallow
|
|
26
|
+
const chunkText = chunk.text();
|
|
27
|
+
if (chunkText) {
|
|
28
|
+
fullText += chunkText;
|
|
29
|
+
safeCallChunk(onChunk, chunkText, onError);
|
|
32
30
|
}
|
|
33
31
|
}
|
|
34
32
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useState, useCallback, useMemo } from "react";
|
|
2
2
|
import type { GeminiGenerationConfig } from "../../domain/entities";
|
|
3
3
|
import { DEFAULT_MODELS } from "../../domain/entities";
|
|
4
|
-
import { textGeneration
|
|
5
|
-
import {
|
|
4
|
+
import { textGeneration } from "../../infrastructure/services/TextGeneration";
|
|
5
|
+
import { structuredText } from "../../infrastructure/services/StructuredText";
|
|
6
|
+
import { executeWithState, type AsyncStateSetters } from "../../infrastructure/utils/async/execute-state.util";
|
|
6
7
|
import { parseJsonResponse } from "../../infrastructure/utils/json-parser.util";
|
|
7
8
|
import { useOperationManager } from "./useOperationManager";
|
|
8
9
|
|
|
@@ -117,8 +117,9 @@ export class ConfigBuilder {
|
|
|
117
117
|
const builder = new ConfigBuilder();
|
|
118
118
|
if (config.apiKey) builder.withApiKey(config.apiKey);
|
|
119
119
|
if (config.textModel) builder.withTextModel(config.textModel);
|
|
120
|
-
|
|
120
|
+
// Apply strategy first (sets default timeout), then explicit timeout overrides it
|
|
121
121
|
if (config.strategy) builder.withStrategy(config.strategy);
|
|
122
|
+
if (config.timeout != null && config.timeout > 0) builder.withTimeout(config.timeout);
|
|
122
123
|
return builder;
|
|
123
124
|
}
|
|
124
125
|
}
|
|
@@ -66,15 +66,8 @@ class ProviderFactory {
|
|
|
66
66
|
throw new Error("Provider not initialized. Call initialize() first.");
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
this.initialize({ ...this.currentConfig, ...updates });
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Otherwise, update using builder
|
|
76
|
-
this.builder = ConfigBuilder.from({ ...this.currentConfig, ...updates });
|
|
77
|
-
this.currentConfig = this.builder.build();
|
|
69
|
+
// Re-initialize with merged config to ensure GeminiClient is updated
|
|
70
|
+
this.initialize({ ...this.currentConfig, ...updates });
|
|
78
71
|
}
|
|
79
72
|
}
|
|
80
73
|
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { GeminiConfig } from "../../domain/entities";
|
|
2
|
-
import { geminiClient } from "./GeminiClient";
|
|
3
|
-
import { structuredText } from "./StructuredText";
|
|
4
|
-
|
|
5
|
-
export class GeminiProvider {
|
|
6
|
-
readonly providerId = "gemini";
|
|
7
|
-
readonly providerName = "Google Gemini";
|
|
8
|
-
|
|
9
|
-
initialize(config: GeminiConfig): void {
|
|
10
|
-
geminiClient.initialize(config);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
isInitialized(): boolean {
|
|
14
|
-
return geminiClient.isInitialized();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
reset(): void {
|
|
18
|
-
geminiClient.reset();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async generateStructuredText<T>(
|
|
22
|
-
prompt: string,
|
|
23
|
-
schema: Record<string, unknown>,
|
|
24
|
-
model: string,
|
|
25
|
-
): Promise<T> {
|
|
26
|
-
if (!prompt || prompt.trim().length < 3) {
|
|
27
|
-
throw new Error("Prompt must be at least 3 characters");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!this.isInitialized()) {
|
|
31
|
-
throw new Error("Provider not initialized. Call initialize() first.");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return structuredText.generateStructuredText<T>(model, prompt, schema);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const geminiProvider = new GeminiProvider();
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export { geminiClient } from "./GeminiClient";
|
|
2
|
-
export { textGeneration } from "./TextGeneration";
|
|
3
|
-
export { structuredText } from "./StructuredText";
|
|
4
|
-
export { streaming } from "./Streaming";
|
|
5
|
-
export { geminiProvider, GeminiProvider } from "./GeminiProvider";
|
|
6
|
-
export {
|
|
7
|
-
createChatSession,
|
|
8
|
-
sendChatMessage,
|
|
9
|
-
buildChatHistory,
|
|
10
|
-
trimChatHistory,
|
|
11
|
-
resolveAudioMimeType,
|
|
12
|
-
resolveImageMimeType,
|
|
13
|
-
type ChatSendResult,
|
|
14
|
-
type ChatHistoryMessage,
|
|
15
|
-
type SendChatMessageOptions,
|
|
16
|
-
} from "./ChatSession";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useGemini, type UseGeminiOptions, type UseGeminiReturn } from "./useGemini";
|
package/src/providers/index.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider Configuration & Factory - Public API
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { ConfigBuilder } from "./ConfigBuilder";
|
|
6
|
-
export type { ProviderConfig } from "./ConfigBuilder";
|
|
7
|
-
|
|
8
|
-
export { providerFactory } from "./ProviderFactory";
|
|
9
|
-
export type { ProviderFactoryOptions } from "./ProviderFactory";
|