@sprqvntrs/llm 3.13.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 SPRQVNTRS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,595 @@
1
+ # @sprqvntrs/llm
2
+
3
+ A unified LLM client library for seamless integration with multiple AI providers (OpenAI and Anthropic). This package provides a consistent API across different LLM providers with built-in support for structured outputs, batch processing, embeddings, and web search.
4
+
5
+ ## Features
6
+
7
+ - **Unified Interface**: Single consistent API for both OpenAI and Anthropic
8
+ - **Structured Outputs**: Generate responses that match Zod schemas with automatic validation
9
+ - **Multi-Provider Support**: Seamlessly switch between OpenAI and Anthropic
10
+ - **Web Search Integration**: Enable web search capabilities for real-time information
11
+ - **Batch Processing**: Process multiple items in parallel with configurable batch sizes
12
+ - **Embeddings**: Generate embeddings for semantic search and similarity tasks
13
+ - **Language Validation**: Check and validate content language
14
+ - **Retry Logic**: Built-in retry mechanisms with configurable attempts
15
+ - **Type Safety**: Full TypeScript support with provider-specific model type inference
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @sprqvntrs/llm
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### Basic Usage
26
+
27
+ ```typescript
28
+ import { LLM } from '@sprqvntrs/llm';
29
+ import { z } from 'zod';
30
+
31
+ // Get a client for your chosen provider
32
+ const client = LLM.getClient('openai', 'gpt-4o');
33
+
34
+ // Validate configuration
35
+ client.validateConfiguration(); // throws if not configured
36
+
37
+ // Create a structured response
38
+ const schema = z.object({
39
+ summary: z.string(),
40
+ sentiment: z.enum(['positive', 'negative', 'neutral']),
41
+ });
42
+
43
+ const result = await client.createStructuredResponse({
44
+ prompt: 'Analyze this text and provide a summary with sentiment.',
45
+ schema,
46
+ });
47
+
48
+ console.log(result.summary); // Structured output
49
+ console.log(result.sentiment); // Type-safe enum
50
+ ```
51
+
52
+ ### Environment Setup
53
+
54
+ Set up your API keys as environment variables:
55
+
56
+ ```bash
57
+ # For OpenAI
58
+ export OPENAI_API_KEY="sk-..."
59
+
60
+ # For Anthropic
61
+ export ANTHROPIC_API_KEY="sk-ant-..."
62
+
63
+ # For Anthropic with structured output support (optional)
64
+ # Anthropic will use OpenAI for formatting if available
65
+ export OPENAI_API_KEY="sk-..."
66
+ ```
67
+
68
+ Alternatively, pass API keys directly:
69
+
70
+ ```typescript
71
+ const client = LLM.getClient('openai', 'gpt-4o', {
72
+ apiKey: 'sk-your-key-here',
73
+ });
74
+ ```
75
+
76
+ ## Core API
77
+
78
+ ### LLM.getClient()
79
+
80
+ Factory method to create a client for a specific provider.
81
+
82
+ ```typescript
83
+ const client = LLM.getClient(provider, model, options?);
84
+ ```
85
+
86
+ **Parameters:**
87
+ - `provider: 'openai' | 'anthropic'` - The LLM provider
88
+ - `model: string` - The model identifier
89
+ - `options?: LlmClientOptions` - Optional configuration
90
+
91
+ **Options:**
92
+ ```typescript
93
+ {
94
+ apiKey?: string; // Override environment API key
95
+ debug?: boolean; // Enable debug logging
96
+ useReasoningMode?: boolean; // Enable reasoning endpoints (OpenAI only)
97
+ openaiApiKey?: string; // OpenAI key for Anthropic formatting
98
+ }
99
+ ```
100
+
101
+ **Returns:** `LlmClientInterface` - A client implementing the unified interface
102
+
103
+ **Example:**
104
+ ```typescript
105
+ // Using environment variables
106
+ const client1 = LLM.getClient('openai', 'gpt-4o');
107
+
108
+ // Override with explicit keys
109
+ const client2 = LLM.getClient('anthropic', 'claude-sonnet-4-5-20250929', {
110
+ apiKey: process.env.ANTHROPIC_KEY,
111
+ openaiApiKey: process.env.OPENAI_KEY,
112
+ });
113
+
114
+ // Enable debug mode
115
+ const client3 = LLM.getClient('openai', 'gpt-4o', { debug: true });
116
+ ```
117
+
118
+ ### createStructuredResponse()
119
+
120
+ Generate a response that conforms to a Zod schema with automatic validation and retry logic.
121
+
122
+ ```typescript
123
+ const result = await client.createStructuredResponse({
124
+ prompt: string;
125
+ schema: ZodSchema;
126
+ formatGuidance?: string;
127
+ reasoningEffort?: 'low' | 'medium' | 'high';
128
+ maxAttempts?: number;
129
+ logExecutionTime?: boolean;
130
+ useWebSearch?: boolean;
131
+ });
132
+ ```
133
+
134
+ **Parameters:**
135
+ - `prompt` - The prompt to send to the model
136
+ - `schema` - A Zod schema defining the expected response structure
137
+ - `formatGuidance` - Optional guidance for formatting the response
138
+ - `reasoningEffort` - Level of reasoning (OpenAI o1 models only)
139
+ - `'low'` - Minimal reasoning
140
+ - `'medium'` - Standard reasoning
141
+ - `'high'` - Extended reasoning
142
+ - `maxAttempts` - Retry attempts if validation fails (default: 1)
143
+ - `logExecutionTime` - Log warnings for slow executions
144
+ - `useWebSearch` - Enable web search for this request
145
+
146
+ **Returns:** Promise resolving to typed object matching the schema
147
+
148
+ **Example:**
149
+ ```typescript
150
+ const schema = z.object({
151
+ title: z.string(),
152
+ sections: z.array(z.object({
153
+ heading: z.string(),
154
+ content: z.string(),
155
+ })),
156
+ metadata: z.object({
157
+ wordCount: z.number(),
158
+ estimatedReadTime: z.number(),
159
+ }),
160
+ });
161
+
162
+ const article = await client.createStructuredResponse({
163
+ prompt: 'Create a blog post about TypeScript best practices',
164
+ schema,
165
+ formatGuidance: 'Ensure all sections are well-structured and informative',
166
+ maxAttempts: 3, // Retry up to 3 times if validation fails
167
+ });
168
+
169
+ console.log(article.title);
170
+ console.log(article.sections[0].heading);
171
+ console.log(article.metadata.wordCount);
172
+ ```
173
+
174
+ ### processBatchWithLLM()
175
+
176
+ Process a batch of items in parallel, automatically chunking into smaller batches.
177
+
178
+ ```typescript
179
+ const results = await client.processBatchWithLLM(
180
+ items,
181
+ processFn,
182
+ batchSize?
183
+ );
184
+ ```
185
+
186
+ **Parameters:**
187
+ - `items: T[]` - Array of items to process
188
+ - `processFn: (batch: T[]) => Promise<R[]>` - Function to process each batch
189
+ - `batchSize?: number` - Items per batch (default: provider-specific)
190
+
191
+ **Returns:** Promise resolving to flattened array of results
192
+
193
+ **Example:**
194
+ ```typescript
195
+ const articles = ['article1', 'article2', 'article3', 'article4'];
196
+
197
+ const summaries = await client.processBatchWithLLM(
198
+ articles,
199
+ async (batch) => {
200
+ // This function is called with [2 items] at a time
201
+ return Promise.all(batch.map(article =>
202
+ client.createStructuredResponse({
203
+ prompt: `Summarize: ${article}`,
204
+ schema: z.object({ summary: z.string() }),
205
+ })
206
+ ));
207
+ },
208
+ 2, // Process 2 items at a time
209
+ );
210
+
211
+ console.log(summaries); // All summaries processed efficiently
212
+ ```
213
+
214
+ ### generateEmbedding()
215
+
216
+ Generate a vector embedding for semantic search and similarity tasks.
217
+
218
+ ```typescript
219
+ const embedding = await client.generateEmbedding(text);
220
+ ```
221
+
222
+ **Parameters:**
223
+ - `text: string` - The text to embed
224
+
225
+ **Returns:** Promise resolving to numeric array (vector)
226
+
227
+ **Example:**
228
+ ```typescript
229
+ const embedding = await client.generateEmbedding(
230
+ 'The quick brown fox jumps over the lazy dog'
231
+ );
232
+
233
+ console.log(embedding.length); // 3072 for text-embedding-3-large
234
+ // Store in vector database for similarity search
235
+ ```
236
+
237
+ ### validateConfiguration()
238
+
239
+ Check if the client is properly configured with valid credentials.
240
+
241
+ ```typescript
242
+ try {
243
+ client.validateConfiguration();
244
+ console.log('Client is ready to use');
245
+ } catch (error) {
246
+ console.error('Configuration error:', error.message);
247
+ }
248
+ ```
249
+
250
+ ## Helper Functions
251
+
252
+ ### isContentInLanguage()
253
+
254
+ Validate that content is written in the expected language.
255
+
256
+ ```typescript
257
+ import { isContentInLanguage } from '@sprqvntrs/llm';
258
+
259
+ const isEnglish = await isContentInLanguage({
260
+ llm: client,
261
+ content: 'Hello, how are you?',
262
+ expectedLanguage: 'English',
263
+ });
264
+
265
+ console.log(isEnglish); // true
266
+ ```
267
+
268
+ ### formatContentToStructure()
269
+
270
+ Convert unstructured content (from an LLM or other source) into a structured format.
271
+
272
+ ```typescript
273
+ import { formatContentToStructure } from '@sprqvntrs/llm';
274
+
275
+ const schema = z.object({
276
+ name: z.string(),
277
+ age: z.number(),
278
+ email: z.string().email(),
279
+ });
280
+
281
+ const structured = await formatContentToStructure({
282
+ llm: client,
283
+ unstructuredContent: 'John is 30 years old and his email is john@example.com',
284
+ schema,
285
+ additionalInstructions: 'Ensure email format is valid',
286
+ });
287
+
288
+ console.log(structured.name); // "John"
289
+ console.log(structured.age); // 30
290
+ console.log(structured.email); // "john@example.com"
291
+ ```
292
+
293
+ ### generateAndFormatWithLanguageCheck()
294
+
295
+ Orchestrate content generation with language validation and formatting in a single call.
296
+
297
+ ```typescript
298
+ import { generateAndFormatWithLanguageCheck } from '@sprqvntrs/llm';
299
+
300
+ const schema = z.object({
301
+ response: z.string(),
302
+ isValid: z.boolean(),
303
+ });
304
+
305
+ const result = await generateAndFormatWithLanguageCheck({
306
+ generateContent: async () => {
307
+ // Function that generates the initial content
308
+ const completion = await client.createStructuredResponse({
309
+ prompt: 'Generate a story about adventure',
310
+ schema: z.object({ text: z.string() }),
311
+ });
312
+ return completion.text;
313
+ },
314
+ languageCheckLlm: client,
315
+ formatterLlm: client,
316
+ expectedLanguage: 'English',
317
+ schema,
318
+ maxAttempts: 3,
319
+ additionalInstructions: 'Ensure proper formatting',
320
+ });
321
+
322
+ console.log(result.response); // Formatted content
323
+ console.log(result.languageCorrect); // Language validation result
324
+ ```
325
+
326
+ ## Model Types and Configuration
327
+
328
+ ### Available Models
329
+
330
+ The package includes pre-configured default models for common tasks:
331
+
332
+ ```typescript
333
+ import { DEFAULT_MODELS } from '@sprqvntrs/llm';
334
+
335
+ // Access default configurations
336
+ DEFAULT_MODELS.OPENAI_DEFAULT; // gpt-5-mini-2025-08-07
337
+ DEFAULT_MODELS.ANTHROPIC_DEFAULT; // claude-sonnet-4-5-20250929
338
+ DEFAULT_MODELS.STRUCTURED_FORMATTER; // gpt-5-mini-2025-08-07 (for Anthropic formatting)
339
+ DEFAULT_MODELS.LANGUAGE_DETECTOR; // gpt-5-nano-2025-08-07
340
+ ```
341
+
342
+ ### Type-Safe Model Selection
343
+
344
+ The package provides TypeScript types that enable IDE autocomplete for provider-specific models:
345
+
346
+ ```typescript
347
+ import type { ModelConfig, OpenAIModel, AnthropicModel } from '@sprqvntrs/llm';
348
+
349
+ // Type-safe configuration with autocomplete
350
+ const openaiConfig: ModelConfig<'openai'> = {
351
+ provider: 'openai',
352
+ model: 'gpt-4o', // Autocomplete shows only OpenAI models
353
+ };
354
+
355
+ const anthropicConfig: ModelConfig<'anthropic'> = {
356
+ provider: 'anthropic',
357
+ model: 'claude-sonnet-4-5-20250929', // Autocomplete shows only Anthropic models
358
+ };
359
+ ```
360
+
361
+ ### Web Search Configuration
362
+
363
+ Enable real-time web search for responses:
364
+
365
+ ```typescript
366
+ import { WEB_SEARCH_TOOLS } from '@sprqvntrs/llm';
367
+
368
+ // Use web search in structured responses
369
+ const result = await client.createStructuredResponse({
370
+ prompt: 'What are the latest developments in AI?',
371
+ schema: z.object({ summary: z.string() }),
372
+ useWebSearch: true,
373
+ });
374
+ ```
375
+
376
+ ## Advanced Examples
377
+
378
+ ### Multi-Step Processing Pipeline
379
+
380
+ ```typescript
381
+ import { LLM, formatContentToStructure } from '@sprqvntrs/llm';
382
+ import { z } from 'zod';
383
+
384
+ const client = LLM.getClient('anthropic', 'claude-sonnet-4-5-20250929');
385
+
386
+ // Step 1: Generate unstructured content
387
+ const generationResult = await client.createStructuredResponse({
388
+ prompt: 'Write a technical analysis',
389
+ schema: z.object({ analysis: z.string() }),
390
+ });
391
+
392
+ // Step 2: Structure and validate the content
393
+ const schema = z.object({
394
+ title: z.string(),
395
+ keyPoints: z.array(z.string()),
396
+ conclusion: z.string(),
397
+ });
398
+
399
+ const structured = await formatContentToStructure({
400
+ llm: client,
401
+ unstructuredContent: generationResult.analysis,
402
+ schema,
403
+ });
404
+
405
+ console.log(structured.keyPoints);
406
+ ```
407
+
408
+ ### Handling Provider-Specific Features
409
+
410
+ ```typescript
411
+ // Use reasoning effort (OpenAI o1 models only)
412
+ const result = await client.createStructuredResponse({
413
+ prompt: 'Solve this complex problem...',
414
+ schema: z.object({ solution: z.string() }),
415
+ reasoningEffort: 'high', // Only works with OpenAI
416
+ });
417
+
418
+ // Switch to Anthropic with web search
419
+ const anthropic = LLM.getClient('anthropic', 'claude-opus-4-1-20250805');
420
+ const webResult = await anthropic.createStructuredResponse({
421
+ prompt: 'What is the current stock price of...?',
422
+ schema: z.object({ price: z.number() }),
423
+ useWebSearch: true,
424
+ });
425
+ ```
426
+
427
+ ### Error Handling
428
+
429
+ ```typescript
430
+ try {
431
+ const client = LLM.getClient('openai', 'gpt-4o');
432
+
433
+ const result = await client.createStructuredResponse({
434
+ prompt: 'Generate data',
435
+ schema: z.object({ data: z.string() }),
436
+ maxAttempts: 3, // Will retry if validation fails
437
+ });
438
+
439
+ console.log('Success:', result);
440
+ } catch (error) {
441
+ if (error.message.includes('API key')) {
442
+ console.error('Authentication failed');
443
+ } else if (error instanceof z.ZodError) {
444
+ console.error('Validation error:', error.issues);
445
+ } else {
446
+ console.error('Request failed:', error.message);
447
+ }
448
+ }
449
+ ```
450
+
451
+ ## Reasoning Effort Levels
452
+
453
+ The `reasoningEffort` parameter controls how much computational effort the model uses. This is currently supported by OpenAI's reasoning models:
454
+
455
+ | Level | Use Case | Cost | Latency |
456
+ |-------|----------|------|---------|
457
+ | `'low'` | Simple tasks, quick responses | Lower | Fast |
458
+ | `'medium'` | Balanced reasoning for complex problems | Medium | Medium |
459
+ | `'high'` | Complex problem-solving requiring deep reasoning | Higher | Slower |
460
+
461
+ **Note:** Anthropic models ignore this parameter as they don't support explicit reasoning effort control.
462
+
463
+ ## Anthropic-Specific Behavior
464
+
465
+ When using an Anthropic client, the package can automatically format structured outputs using OpenAI if an OpenAI API key is available:
466
+
467
+ 1. **With OpenAI Key Available** (Recommended):
468
+ - Anthropic generates the response
469
+ - OpenAI validates and formats it according to the schema
470
+ - Highest reliability for structured outputs
471
+
472
+ 2. **Without OpenAI Key**:
473
+ - Anthropic attempts direct JSON generation
474
+ - Less reliable but still functional
475
+ - Falls back gracefully with warnings
476
+
477
+ ```typescript
478
+ // Best practice: Provide both keys for optimal formatting
479
+ const client = LLM.getClient('anthropic', 'claude-sonnet-4-5-20250929', {
480
+ apiKey: process.env.ANTHROPIC_API_KEY,
481
+ openaiApiKey: process.env.OPENAI_API_KEY,
482
+ });
483
+ ```
484
+
485
+ ## Batch Processing Strategy
486
+
487
+ The `processBatchWithLLM()` method is optimized for:
488
+ - Parallel processing of independent items
489
+ - Automatic batching to respect API rate limits
490
+ - Memory-efficient chunking of large datasets
491
+
492
+ ```typescript
493
+ // Process 1000 items with batch size of 10
494
+ const results = await client.processBatchWithLLM(
495
+ largeArray,
496
+ async (batch) => {
497
+ return Promise.all(
498
+ batch.map(item =>
499
+ client.createStructuredResponse({ /* ... */ })
500
+ )
501
+ );
502
+ },
503
+ 10 // Process 10 items at a time
504
+ );
505
+ ```
506
+
507
+ ## Caching and Memoization
508
+
509
+ For repeated requests with identical prompts, consider caching:
510
+
511
+ ```typescript
512
+ const cache = new Map<string, any>();
513
+
514
+ async function cachedRequest(prompt: string) {
515
+ if (cache.has(prompt)) {
516
+ return cache.get(prompt);
517
+ }
518
+
519
+ const result = await client.createStructuredResponse({
520
+ prompt,
521
+ schema: z.object({ /* ... */ }),
522
+ });
523
+
524
+ cache.set(prompt, result);
525
+ return result;
526
+ }
527
+ ```
528
+
529
+ ## Troubleshooting
530
+
531
+ ### "API key is not set" Error
532
+
533
+ ```typescript
534
+ // Solution 1: Set environment variables
535
+ export OPENAI_API_KEY="sk-..."
536
+ export ANTHROPIC_API_KEY="sk-ant-..."
537
+
538
+ // Solution 2: Pass keys explicitly
539
+ const client = LLM.getClient('openai', 'gpt-4o', {
540
+ apiKey: 'sk-your-key',
541
+ });
542
+ ```
543
+
544
+ ### Schema Validation Errors
545
+
546
+ ```typescript
547
+ // Enable retries to handle temporary validation issues
548
+ const result = await client.createStructuredResponse({
549
+ prompt: 'Your prompt',
550
+ schema: yourSchema,
551
+ maxAttempts: 3, // Retry up to 3 times
552
+ });
553
+
554
+ // Or use formatContentToStructure for manual control
555
+ const formatted = await formatContentToStructure({
556
+ llm: client,
557
+ unstructuredContent: rawContent,
558
+ schema: yourSchema,
559
+ });
560
+ ```
561
+
562
+ ### Slow Responses
563
+
564
+ ```typescript
565
+ // Monitor execution time
566
+ const result = await client.createStructuredResponse({
567
+ prompt: 'Your prompt',
568
+ schema: yourSchema,
569
+ logExecutionTime: true, // Log warnings for slow requests
570
+ reasoningEffort: 'low', // Use lower reasoning effort if possible
571
+ });
572
+ ```
573
+
574
+ ## Performance Tips
575
+
576
+ 1. **Batch similar requests** using `processBatchWithLLM()`
577
+ 2. **Use appropriate reasoning effort** - higher levels are slower but solve harder problems
578
+ 3. **Enable web search sparingly** - it adds latency for real-time information
579
+ 4. **Cache responses** for repeated identical prompts
580
+ 5. **Use smaller models** (gpt-4o-mini, claude-haiku) for simple tasks
581
+ 6. **Set reasonable maxAttempts** - balance reliability with cost
582
+
583
+ ## API Reference
584
+
585
+ See [LlmClientInterface](src/types/client-interface.ts) for complete interface documentation.
586
+
587
+ ## Raw TypeScript
588
+
589
+ This package ships raw TypeScript (`main` and `types` point at `index.ts`), so a Vite
590
+ consumer (Vite, React Router, Remix) must add the scope to `ssr.noExternal`:
591
+ `ssr: { noExternal: [/^@sprqvntrs\//] }`.
592
+
593
+ ## License
594
+
595
+ MIT
package/index.ts ADDED
@@ -0,0 +1,53 @@
1
+ // Factory class
2
+ export { LLM } from './src/llm';
3
+ export type { LlmProvider, LlmClientOptions } from './src/llm';
4
+
5
+ // Client classes
6
+ export { OpenAIClient } from './src/clients/openai-client';
7
+ export { AnthropicClient } from './src/clients/anthropic-client';
8
+ export { OpenRouterClient } from './src/clients/openrouter-client';
9
+
10
+ // Client configuration types
11
+ export type { OpenAIClientConfig } from './src/clients/openai-client';
12
+ export type { AnthropicClientConfig } from './src/clients/anthropic-client';
13
+ export type { OpenRouterClientConfig } from './src/clients/openrouter-client';
14
+
15
+ // Interface and base types
16
+ export type { LlmClientInterface, BaseLlmClientConfig, BatchProcessOptions, StreamChunk, LlmTokenUsage, LlmUsageCost, ReasoningEffortLevel } from './src/types/client-interface';
17
+
18
+ // Pricing utilities
19
+ export { MODEL_PRICING, calculateUsageCost } from './src/pricing';
20
+ export type { ModelPricing } from './src/pricing';
21
+
22
+ // Model types
23
+ export type { ModelConfig, ProviderModelMap, OpenAIModel, AnthropicModel, OpenRouterModel } from './src/model-types';
24
+
25
+ // Model configurations
26
+ export { DEFAULT_MODELS, REASONING_EFFORT_MAP, ANTHROPIC_MAX_TOKENS, WEB_SEARCH_TOOLS } from './src/models';
27
+
28
+ // Error types and utilities
29
+ export {
30
+ LlmError,
31
+ LlmTimeoutError,
32
+ LlmValidationError,
33
+ LlmApiError,
34
+ LlmConfigurationError,
35
+ LlmOutputTruncatedError,
36
+ LlmJsonParseError,
37
+ generateRequestId,
38
+ isTimeoutError,
39
+ isRetryableError,
40
+ wrapSdkError,
41
+ } from './src/utils/errors';
42
+ export type { LlmErrorContext } from './src/utils/errors';
43
+
44
+ // Helper functions
45
+ export {
46
+ isContentInLanguage,
47
+ formatContentToStructure,
48
+ generateAndFormatWithLanguageCheck,
49
+ } from './src/helpers';
50
+
51
+ // Response normalization utilities
52
+ export { stripJsonArtifacts } from './src/utils/strip-json-artifacts';
53
+ export type { SanitizationResult } from './src/utils/strip-json-artifacts';