@umituz/react-native-ai-groq-provider 1.0.23 → 1.0.25

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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/application/use-cases/chat-session.usecase.ts +19 -9
  3. package/src/application/use-cases/streaming.usecase.ts +13 -7
  4. package/src/application/use-cases/structured-generation.usecase.ts +17 -5
  5. package/src/application/use-cases/text-generation.usecase.ts +4 -3
  6. package/src/domain/entities/error.types.ts +17 -2
  7. package/src/index.ts +26 -68
  8. package/src/infrastructure/http/groq-http-client.ts +68 -12
  9. package/src/infrastructure/http/streaming-client.ts +135 -84
  10. package/src/infrastructure/telemetry/TelemetryHooks.ts +40 -23
  11. package/src/infrastructure/utils/calculation.util.ts +46 -14
  12. package/src/infrastructure/utils/content-mapper.util.ts +1 -1
  13. package/src/presentation/hooks/use-groq.hook.ts +14 -22
  14. package/src/providers/ConfigBuilder.ts +2 -73
  15. package/src/providers/ProviderFactory.ts +7 -62
  16. package/src/shared/request-builder.ts +8 -4
  17. package/src/shared/response-handler.ts +81 -0
  18. package/src/types/react-native-global.d.ts +12 -0
  19. package/src/application/use-cases/index.ts +0 -19
  20. package/src/domain/entities/index.ts +0 -7
  21. package/src/infrastructure/http/index.ts +0 -7
  22. package/src/infrastructure/telemetry/index.ts +0 -5
  23. package/src/infrastructure/utils/async/index.ts +0 -6
  24. package/src/infrastructure/utils/index.ts +0 -8
  25. package/src/presentation/hooks/index.ts +0 -7
  26. package/src/presentation/hooks/useGroq.ts +0 -235
  27. package/src/presentation/hooks/useOperationManager.ts +0 -119
  28. package/src/presentation/index.ts +0 -6
  29. package/src/providers/index.ts +0 -16
  30. package/src/shared/index.ts +0 -16
@@ -3,8 +3,8 @@
3
3
  * Builder pattern for Groq configuration
4
4
  */
5
5
 
6
- import type { GroqConfig, GroqGenerationConfig } from "../domain/entities";
7
- import { DEFAULT_MODELS } from "../domain/entities";
6
+ import type { GroqConfig, GroqGenerationConfig } from "../domain/entities/groq.types";
7
+ import { DEFAULT_MODELS } from "../domain/entities/groq.types";
8
8
 
9
9
  /**
10
10
  * Builder for Groq configuration
@@ -12,41 +12,26 @@ import { DEFAULT_MODELS } from "../domain/entities";
12
12
  export class ConfigBuilder {
13
13
  private config: Partial<GroqConfig> = {};
14
14
 
15
- /**
16
- * Set API key
17
- */
18
15
  withApiKey(apiKey: string): ConfigBuilder {
19
16
  this.config.apiKey = apiKey;
20
17
  return this;
21
18
  }
22
19
 
23
- /**
24
- * Set base URL
25
- */
26
20
  withBaseUrl(baseUrl: string): ConfigBuilder {
27
21
  this.config.baseUrl = baseUrl;
28
22
  return this;
29
23
  }
30
24
 
31
- /**
32
- * Set timeout
33
- */
34
25
  withTimeout(timeoutMs: number): ConfigBuilder {
35
26
  this.config.timeoutMs = timeoutMs;
36
27
  return this;
37
28
  }
38
29
 
39
- /**
40
- * Set default text model
41
- */
42
30
  withTextModel(model: string): ConfigBuilder {
43
31
  this.config.textModel = model;
44
32
  return this;
45
33
  }
46
34
 
47
- /**
48
- * Build configuration
49
- */
50
35
  build(): GroqConfig {
51
36
  if (!this.config.apiKey) {
52
37
  throw new Error("API key is required. Use withApiKey() to set it.");
@@ -59,13 +44,6 @@ export class ConfigBuilder {
59
44
  textModel: this.config.textModel || DEFAULT_MODELS.TEXT,
60
45
  };
61
46
  }
62
-
63
- /**
64
- * Create a new builder instance
65
- */
66
- static create(): ConfigBuilder {
67
- return new ConfigBuilder();
68
- }
69
47
  }
70
48
 
71
49
  /**
@@ -74,86 +52,37 @@ export class ConfigBuilder {
74
52
  export class GenerationConfigBuilder {
75
53
  private config: GroqGenerationConfig = {};
76
54
 
77
- /**
78
- * Set temperature
79
- */
80
55
  withTemperature(temperature: number): GenerationConfigBuilder {
81
56
  this.config.temperature = temperature;
82
57
  return this;
83
58
  }
84
59
 
85
- /**
86
- * Set max tokens
87
- */
88
60
  withMaxTokens(maxTokens: number): GenerationConfigBuilder {
89
61
  this.config.maxTokens = maxTokens;
90
62
  return this;
91
63
  }
92
64
 
93
- /**
94
- * Set top P
95
- */
96
65
  withTopP(topP: number): GenerationConfigBuilder {
97
66
  this.config.topP = topP;
98
67
  return this;
99
68
  }
100
69
 
101
- /**
102
- * Set frequency penalty
103
- */
104
70
  withFrequencyPenalty(penalty: number): GenerationConfigBuilder {
105
71
  this.config.frequencyPenalty = penalty;
106
72
  return this;
107
73
  }
108
74
 
109
- /**
110
- * Set presence penalty
111
- */
112
75
  withPresencePenalty(penalty: number): GenerationConfigBuilder {
113
76
  this.config.presencePenalty = penalty;
114
77
  return this;
115
78
  }
116
79
 
117
- /**
118
- * Set stop sequences
119
- */
120
80
  withStop(stop: string[]): GenerationConfigBuilder {
121
81
  this.config.stop = stop;
122
82
  return this;
123
83
  }
124
84
 
125
- /**
126
- * Build configuration
127
- */
128
85
  build(): GroqGenerationConfig {
129
86
  return { ...this.config };
130
87
  }
131
-
132
- /**
133
- * Create a new builder instance
134
- */
135
- static create(): GenerationConfigBuilder {
136
- return new GenerationConfigBuilder();
137
- }
138
-
139
- /**
140
- * Create a balanced configuration
141
- */
142
- static balanced(): GenerationConfigBuilder {
143
- return new GenerationConfigBuilder().withTemperature(0.7);
144
- }
145
-
146
- /**
147
- * Create a creative configuration
148
- */
149
- static creative(): GenerationConfigBuilder {
150
- return new GenerationConfigBuilder().withTemperature(1.0);
151
- }
152
-
153
- /**
154
- * Create a precise configuration
155
- */
156
- static precise(): GenerationConfigBuilder {
157
- return new GenerationConfigBuilder().withTemperature(0.3);
158
- }
159
88
  }
@@ -3,8 +3,7 @@
3
3
  * Factory for creating configured Groq provider instances
4
4
  */
5
5
 
6
- import { groqHttpClient } from "../infrastructure/services/GroqClient";
7
- import { ConfigBuilder, GenerationConfigBuilder } from "./ConfigBuilder";
6
+ import { groqHttpClient } from "../infrastructure/http/groq-http-client";
8
7
 
9
8
  /**
10
9
  * Provider configuration options
@@ -16,14 +15,6 @@ export interface ProviderConfig {
16
15
  defaultModel?: string;
17
16
  }
18
17
 
19
- /**
20
- * Provider factory options
21
- */
22
- export interface ProviderFactoryOptions {
23
- enableTelemetry?: boolean;
24
- onError?: (error: Error) => void;
25
- }
26
-
27
18
  /**
28
19
  * Initialize Groq provider with configuration
29
20
  */
@@ -37,61 +28,15 @@ export function initializeProvider(config: ProviderConfig): void {
37
28
  }
38
29
 
39
30
  /**
40
- * Provider factory - creates configured provider instances
31
+ * Reset provider configuration
41
32
  */
42
- export const providerFactory = {
43
- /**
44
- * Create a new provider instance
45
- */
46
- create(config: ProviderConfig): void {
47
- initializeProvider(config);
48
- },
49
-
50
- /**
51
- * Create provider from environment variables
52
- */
53
- fromEnv(): void {
54
- const apiKey = process.env.GROQ_API_KEY;
55
-
56
- if (!apiKey) {
57
- throw new Error("GROQ_API_KEY environment variable is not set");
58
- }
59
-
60
- initializeProvider({
61
- apiKey,
62
- baseUrl: process.env.GROQ_BASE_URL,
63
- timeoutMs: process.env.GROQ_TIMEOUT_MS ? parseInt(process.env.GROQ_TIMEOUT_MS) : undefined,
64
- });
65
- },
66
-
67
- /**
68
- * Reset provider (clear configuration)
69
- */
70
- reset(): void {
71
- groqHttpClient.reset();
72
- },
73
-
74
- /**
75
- * Check if provider is initialized
76
- */
77
- isInitialized(): boolean {
78
- return groqHttpClient.isInitialized();
79
- },
80
- };
81
-
82
- /**
83
- * Convenience function to initialize provider
84
- */
85
- export function configureProvider(config: ProviderConfig): void {
86
- providerFactory.create(config);
33
+ export function resetProvider(): void {
34
+ groqHttpClient.reset();
87
35
  }
88
36
 
89
37
  /**
90
- * Convenience function to reset provider
38
+ * Check if provider is initialized
91
39
  */
92
- export function resetProvider(): void {
93
- providerFactory.reset();
40
+ export function isProviderInitialized(): boolean {
41
+ return groqHttpClient.isInitialized();
94
42
  }
95
-
96
- // Re-export builders
97
- export { ConfigBuilder, GenerationConfigBuilder };
@@ -7,8 +7,8 @@ import type {
7
7
  GroqChatRequest,
8
8
  GroqGenerationConfig,
9
9
  GroqMessage,
10
- } from "../domain/entities";
11
- import { DEFAULT_MODELS } from "../domain/entities";
10
+ } from "../domain/entities/groq.types";
11
+ import { DEFAULT_MODELS } from "../domain/entities/groq.types";
12
12
 
13
13
  export interface RequestBuilderOptions {
14
14
  model?: string;
@@ -32,8 +32,12 @@ export class RequestBuilder {
32
32
  return {
33
33
  model,
34
34
  messages,
35
- temperature: generationConfig.temperature ?? defaultTemperature,
36
- max_tokens: generationConfig.maxTokens ?? defaultMaxTokens,
35
+ temperature: generationConfig.temperature !== undefined
36
+ ? generationConfig.temperature
37
+ : defaultTemperature,
38
+ max_tokens: generationConfig.maxTokens !== undefined
39
+ ? generationConfig.maxTokens
40
+ : defaultMaxTokens,
37
41
  top_p: generationConfig.topP,
38
42
  n: generationConfig.n,
39
43
  stop: generationConfig.stop,
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Response Handler Utility
3
+ * Handles API response parsing and extraction
4
+ */
5
+
6
+ import type { GroqChatResponse, GroqUsage, GroqFinishReason } from "../domain/entities/groq.types";
7
+
8
+ interface Logger {
9
+ debug: (tag: string, message: string, context?: Record<string, unknown>) => void;
10
+ }
11
+
12
+ export interface ResponseHandlerResult {
13
+ content: string;
14
+ usage: {
15
+ promptTokens: number;
16
+ completionTokens: number;
17
+ totalTokens: number;
18
+ };
19
+ finishReason: GroqFinishReason;
20
+ }
21
+
22
+ export class ResponseHandler {
23
+ /**
24
+ * Extract content from chat completion response
25
+ */
26
+ static extractContent(response: GroqChatResponse): string {
27
+ if (!response.choices || response.choices.length === 0) {
28
+ return "";
29
+ }
30
+ return response.choices[0].message?.content || "";
31
+ }
32
+
33
+ /**
34
+ * Handle complete response and extract all relevant data
35
+ */
36
+ static handleResponse(response: GroqChatResponse): ResponseHandlerResult {
37
+ if (!response.choices || response.choices.length === 0) {
38
+ return {
39
+ content: "",
40
+ usage: this.extractUsage(response.usage),
41
+ finishReason: "stop",
42
+ };
43
+ }
44
+
45
+ const choice = response.choices[0];
46
+ return {
47
+ content: choice.message?.content || "",
48
+ usage: this.extractUsage(response.usage),
49
+ finishReason: choice.finish_reason || "stop",
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Extract usage information
55
+ */
56
+ private static extractUsage(usage: GroqUsage): {
57
+ promptTokens: number;
58
+ completionTokens: number;
59
+ totalTokens: number;
60
+ } {
61
+ return {
62
+ promptTokens: usage.prompt_tokens || 0,
63
+ completionTokens: usage.completion_tokens || 0,
64
+ totalTokens: usage.total_tokens || 0,
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Log response details
70
+ */
71
+ static logResponse(logger: Logger, response: GroqChatResponse, apiMs: number): void {
72
+ logger.debug("ResponseHandler", "API response received", {
73
+ model: response.model,
74
+ promptTokens: response.usage.prompt_tokens,
75
+ completionTokens: response.usage.completion_tokens,
76
+ totalTokens: response.usage.total_tokens,
77
+ finishReason: response.choices[0]?.finish_reason,
78
+ apiDuration: `${apiMs}ms`,
79
+ });
80
+ }
81
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * React Native Global Declarations
3
+ * Type definitions for React Native globals
4
+ */
5
+
6
+ declare const __DEV__: boolean;
7
+
8
+ declare global {
9
+ const __DEV__: boolean;
10
+ }
11
+
12
+ export {};
@@ -1,19 +0,0 @@
1
- /**
2
- * Application Layer - Use Cases
3
- * Business logic orchestrators
4
- */
5
-
6
- export { generateText } from "./text-generation.usecase";
7
- export type { TextGenerationOptions } from "./text-generation.usecase";
8
-
9
- export { generateStructured } from "./structured-generation.usecase";
10
- export type { StructuredGenerationOptions } from "./structured-generation.usecase";
11
-
12
- export { streamText } from "./streaming.usecase";
13
- export type { StreamingCallbacks, StreamingOptions } from "./streaming.usecase";
14
-
15
- export {
16
- chatSessionManager,
17
- type ChatSession,
18
- type ChatSendResult,
19
- } from "./chat-session.usecase";
@@ -1,7 +0,0 @@
1
- /**
2
- * Domain Entities
3
- */
4
-
5
- export * from "./groq.types";
6
- export * from "./models";
7
- export * from "./error.types";
@@ -1,7 +0,0 @@
1
- /**
2
- * Infrastructure HTTP Layer
3
- * HTTP communication with Groq API
4
- */
5
-
6
- export { groqHttpClient } from "./groq-http-client";
7
- export { streamChatCompletion } from "./streaming-client";
@@ -1,5 +0,0 @@
1
- /**
2
- * Telemetry
3
- */
4
-
5
- export { telemetry, useTelemetry } from "./TelemetryHooks";
@@ -1,6 +0,0 @@
1
- /**
2
- * Async utilities
3
- */
4
-
5
- export { executeWithState, executeWithRetry } from "./execute-state.util";
6
- export type { AsyncStateSetters, AsyncCallbacks } from "./execute-state.util";
@@ -1,8 +0,0 @@
1
- /**
2
- * Infrastructure Utilities
3
- */
4
-
5
- export * from "./content-mapper.util";
6
- export * from "./error-mapper.util";
7
- export * from "./calculation.util";
8
- export * from "./async";
@@ -1,7 +0,0 @@
1
- /**
2
- * Presentation Layer - Hooks
3
- * React hooks for UI integration
4
- */
5
-
6
- export { useGroq } from "./use-groq.hook";
7
- export type { UseGroqOptions, UseGroqReturn } from "./use-groq.hook";
@@ -1,235 +0,0 @@
1
- /**
2
- * useGroq Hook
3
- * Main React hook for Groq text generation
4
- */
5
-
6
- import { useState, useCallback, useRef, useMemo } from "react";
7
- import type { GroqGenerationConfig } from "../../domain/entities";
8
- import { textGeneration } from "../../infrastructure/services/TextGeneration";
9
- import { structuredText } from "../../infrastructure/services/StructuredText";
10
- import { streaming } from "../../infrastructure/services/Streaming";
11
- import { getUserFriendlyError } from "../../infrastructure/utils/error-mapper.util";
12
- import { telemetry } from "../../infrastructure/telemetry";
13
-
14
- export interface UseGroqOptions {
15
- /** Initial model to use */
16
- model?: string;
17
- /** Default generation config */
18
- generationConfig?: GroqGenerationConfig;
19
- /** Callback when generation starts */
20
- onStart?: () => void;
21
- /** Callback when generation completes */
22
- onSuccess?: (result: string) => void;
23
- /** Callback when generation fails */
24
- onError?: (error: string) => void;
25
- }
26
-
27
- export interface UseGroqReturn {
28
- /** Loading state */
29
- isLoading: boolean;
30
- /** Error message */
31
- error: string | null;
32
- /** Generated result */
33
- result: string | null;
34
- /** Generate text from a prompt */
35
- generate: (prompt: string, options?: GroqGenerationConfig) => Promise<string>;
36
- /** Generate structured JSON output */
37
- generateJSON: <T = Record<string, unknown>>(
38
- prompt: string,
39
- options?: GroqGenerationConfig & { schema?: Record<string, unknown> }
40
- ) => Promise<T>;
41
- /** Stream text generation */
42
- stream: (
43
- prompt: string,
44
- onChunk: (chunk: string) => void,
45
- options?: GroqGenerationConfig
46
- ) => Promise<void>;
47
- /** Reset state */
48
- reset: () => void;
49
- /** Clear error */
50
- clearError: () => void;
51
- }
52
-
53
- /**
54
- * Hook for Groq text generation
55
- * Optimized to prevent unnecessary re-renders and memory leaks
56
- */
57
- export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
58
- const [isLoading, setIsLoading] = useState(false);
59
- const [error, setError] = useState<string | null>(null);
60
- const [result, setResult] = useState<string | null>(null);
61
- const abortControllerRef = useRef<AbortController | null>(null);
62
-
63
- // Memoize options to prevent unnecessary callback recreations
64
- const stableOptions = useMemo(() => options, [
65
- options.model,
66
- options.generationConfig?.temperature,
67
- options.generationConfig?.maxTokens,
68
- options.generationConfig?.topP,
69
- options.onStart,
70
- options.onSuccess,
71
- options.onError,
72
- ]);
73
-
74
- const generate = useCallback(
75
- async (prompt: string, config?: GroqGenerationConfig): Promise<string> => {
76
- // Cancel any ongoing request
77
- if (abortControllerRef.current) {
78
- abortControllerRef.current.abort();
79
- }
80
-
81
- abortControllerRef.current = new AbortController();
82
- setIsLoading(true);
83
- setError(null);
84
- setResult(null);
85
-
86
- telemetry.log("groq_generate_start", { prompt: prompt.substring(0, 100) });
87
- stableOptions.onStart?.();
88
-
89
- try {
90
- const response = await textGeneration(prompt, {
91
- model: stableOptions.model,
92
- generationConfig: { ...stableOptions.generationConfig, ...config },
93
- });
94
-
95
- setResult(response);
96
- stableOptions.onSuccess?.(response);
97
- telemetry.log("groq_generate_success", { responseLength: response.length });
98
-
99
- return response;
100
- } catch (err) {
101
- const errorMessage = getUserFriendlyError(err);
102
- setError(errorMessage);
103
- stableOptions.onError?.(errorMessage);
104
- telemetry.log("groq_generate_error", { error: errorMessage });
105
- throw err;
106
- } finally {
107
- setIsLoading(false);
108
- abortControllerRef.current = null;
109
- }
110
- },
111
- [stableOptions]
112
- );
113
-
114
- const generateJSON = useCallback(
115
- async <T = Record<string, unknown>,>(
116
- prompt: string,
117
- config?: GroqGenerationConfig & { schema?: Record<string, unknown> }
118
- ): Promise<T> => {
119
- // Cancel any ongoing request
120
- if (abortControllerRef.current) {
121
- abortControllerRef.current.abort();
122
- }
123
-
124
- abortControllerRef.current = new AbortController();
125
- setIsLoading(true);
126
- setError(null);
127
- setResult(null);
128
-
129
- telemetry.log("groq_generate_json_start", { prompt: prompt.substring(0, 100) });
130
- stableOptions.onStart?.();
131
-
132
- try {
133
- const response = await structuredText<T>(prompt, {
134
- model: stableOptions.model,
135
- generationConfig: { ...stableOptions.generationConfig, ...config },
136
- schema: config?.schema,
137
- });
138
-
139
- setResult(JSON.stringify(response, null, 2));
140
- stableOptions.onSuccess?.(JSON.stringify(response, null, 2));
141
- telemetry.log("groq_generate_json_success");
142
-
143
- return response;
144
- } catch (err) {
145
- const errorMessage = getUserFriendlyError(err);
146
- setError(errorMessage);
147
- stableOptions.onError?.(errorMessage);
148
- telemetry.log("groq_generate_json_error", { error: errorMessage });
149
- throw err;
150
- } finally {
151
- setIsLoading(false);
152
- abortControllerRef.current = null;
153
- }
154
- },
155
- [stableOptions]
156
- );
157
-
158
- const stream = useCallback(
159
- async (
160
- prompt: string,
161
- onChunk: (chunk: string) => void,
162
- config?: GroqGenerationConfig
163
- ): Promise<void> => {
164
- // Cancel any ongoing request
165
- if (abortControllerRef.current) {
166
- abortControllerRef.current.abort();
167
- }
168
-
169
- abortControllerRef.current = new AbortController();
170
- setIsLoading(true);
171
- setError(null);
172
- setResult(null);
173
-
174
- let fullContent = "";
175
-
176
- telemetry.log("groq_stream_start", { prompt: prompt.substring(0, 100) });
177
- stableOptions.onStart?.();
178
-
179
- try {
180
- for await (const streamingResult of streaming(prompt, {
181
- model: stableOptions.model,
182
- generationConfig: { ...stableOptions.generationConfig, ...config },
183
- callbacks: {
184
- onChunk: (c) => {
185
- fullContent += c;
186
- onChunk(c);
187
- },
188
- },
189
- })) {
190
- // Consume the async iterator (streaming is handled via callbacks)
191
- void streamingResult;
192
- }
193
-
194
- setResult(fullContent);
195
- stableOptions.onSuccess?.(fullContent);
196
- telemetry.log("groq_stream_success", { contentLength: fullContent.length });
197
- } catch (err) {
198
- const errorMessage = getUserFriendlyError(err);
199
- setError(errorMessage);
200
- stableOptions.onError?.(errorMessage);
201
- telemetry.log("groq_stream_error", { error: errorMessage });
202
- throw err;
203
- } finally {
204
- setIsLoading(false);
205
- abortControllerRef.current = null;
206
- }
207
- },
208
- [stableOptions]
209
- );
210
-
211
- const reset = useCallback(() => {
212
- if (abortControllerRef.current) {
213
- abortControllerRef.current.abort();
214
- abortControllerRef.current = null;
215
- }
216
- setIsLoading(false);
217
- setError(null);
218
- setResult(null);
219
- }, []);
220
-
221
- const clearError = useCallback(() => {
222
- setError(null);
223
- }, []);
224
-
225
- return {
226
- isLoading,
227
- error,
228
- result,
229
- generate,
230
- generateJSON,
231
- stream,
232
- reset,
233
- clearError,
234
- };
235
- }