@contentgrowth/llm-service 0.8.3 → 0.8.5

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.
@@ -0,0 +1,529 @@
1
+ import OpenAI from 'openai';
2
+ import * as _google_genai from '@google/genai';
3
+ import { GoogleGenAI } from '@google/genai';
4
+
5
+ declare namespace FINISH_REASONS {
6
+ let COMPLETED: string;
7
+ let TRUNCATED: string;
8
+ let CONTENT_FILTER: string;
9
+ let TOOL_CALL: string;
10
+ let UNKNOWN: string;
11
+ }
12
+ /**
13
+ * Abstract base class for LLM Providers.
14
+ * Defines the standard interface that all providers must implement.
15
+ */
16
+ declare class BaseLLMProvider {
17
+ constructor(config: any);
18
+ config: any;
19
+ /**
20
+ * Normalize provider-specific finish reason to standard value.
21
+ * Override in subclass if provider uses different values.
22
+ * @param {string} providerReason - The provider's native finish reason
23
+ * @returns {string} Standardized finish reason from FINISH_REASONS
24
+ */
25
+ normalizeFinishReason(providerReason: string): string;
26
+ /**
27
+ * Simple chat interface for single-turn conversations
28
+ * @param {string} userMessage
29
+ * @param {string} systemPrompt
30
+ * @param {Object} options
31
+ */
32
+ chat(userMessage: string, systemPrompt: string, options: any): Promise<void>;
33
+ /**
34
+ * Advanced chat completion with tool support
35
+ * @param {Array} messages
36
+ * @param {string} systemPrompt
37
+ * @param {Array} tools
38
+ * @param {Object} options - Generation options (responseFormat, temperature, etc.)
39
+ */
40
+ chatCompletion(messages: any[], systemPrompt: string, tools: any[], options?: any): Promise<void>;
41
+ /**
42
+ * Execute tools requested by the LLM
43
+ * @param {Array} toolCalls
44
+ * @param {Array} messages
45
+ * @param {string} tenantId
46
+ * @param {Object} toolImplementations
47
+ * @param {Object} env
48
+ */
49
+ executeTools(toolCalls: any[], messages: any[], tenantId: string, toolImplementations: any, env: any): Promise<void>;
50
+ /**
51
+ * Generate image
52
+ * Subclasses should override this method.
53
+ * Model can be overridden via options.model, otherwise uses config.models.image
54
+ * @param {string} prompt - Text description of the image
55
+ * @param {string} systemPrompt - System instructions for generation
56
+ * @param {Object} options - Generation options (aspectRatio, images, model, etc.)
57
+ * @returns {Promise<{imageData: string, mimeType: string}>}
58
+ */
59
+ imageGeneration(prompt: string, systemPrompt: string, options?: any): Promise<{
60
+ imageData: string;
61
+ mimeType: string;
62
+ }>;
63
+ /**
64
+ * Start video generation (returns operation name for polling)
65
+ * @param {string} prompt
66
+ * @param {Array} images
67
+ * @param {string} modelName
68
+ * @param {string} systemPrompt
69
+ * @param {Object} options
70
+ * @returns {Promise<{operationName: string}>}
71
+ */
72
+ startVideoGeneration(prompt: string, images: any[], modelName: string, systemPrompt: string, options: any): Promise<{
73
+ operationName: string;
74
+ }>;
75
+ /**
76
+ * Get video generation status (poll operation)
77
+ * @param {string} operationName
78
+ * @returns {Promise<{done: boolean, progress: number, state: string, videoUri?: string, error?: object}>}
79
+ */
80
+ getVideoGenerationStatus(operationName: string): Promise<{
81
+ done: boolean;
82
+ progress: number;
83
+ state: string;
84
+ videoUri?: string;
85
+ error?: object;
86
+ }>;
87
+ /**
88
+ * Helper to get the last 6 digits of the API key for logging.
89
+ * @returns {string} "..." + last 6 chars, or "not_set"
90
+ */
91
+ _getMaskedApiKey(): string;
92
+ }
93
+
94
+ declare class OpenAIProvider extends BaseLLMProvider {
95
+ client: OpenAI;
96
+ models: any;
97
+ defaultModel: any;
98
+ chat(userMessage: any, systemPrompt?: string, options?: {}): Promise<{
99
+ text: string;
100
+ }>;
101
+ chatCompletion(messages: any, systemPrompt: any, tools?: any, options?: {}): Promise<{
102
+ parsedContent?: any;
103
+ content: string;
104
+ tool_calls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[];
105
+ finishReason: string;
106
+ _rawFinishReason: "content_filter" | "stop" | "length" | "tool_calls" | "function_call";
107
+ _responseFormat: any;
108
+ }>;
109
+ _chatCompletionWithModel(messages: any, systemPrompt: any, tools: any, modelName: any, maxTokens: any, temperature: any, options?: {}): Promise<{
110
+ parsedContent?: any;
111
+ content: string;
112
+ tool_calls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[];
113
+ finishReason: string;
114
+ _rawFinishReason: "content_filter" | "stop" | "length" | "tool_calls" | "function_call";
115
+ _responseFormat: any;
116
+ }>;
117
+ _buildResponseFormat(options: any): {
118
+ type: string;
119
+ json_schema: {
120
+ name: any;
121
+ strict: any;
122
+ schema: any;
123
+ };
124
+ } | {
125
+ type: string;
126
+ json_schema?: undefined;
127
+ };
128
+ _shouldAutoParse(options: any): boolean;
129
+ _safeJsonParse(content: any): any;
130
+ executeTools(tool_calls: any, messages: any, tenantId: any, toolImplementations: any, env: any): Promise<void>;
131
+ _getModelForTier(tier: any): any;
132
+ videoGeneration(prompt: any, images: any, modelName: any, systemPrompt: any, options?: {}): Promise<void>;
133
+ startDeepResearch(prompt: any, options?: {}): Promise<void>;
134
+ getDeepResearchStatus(operationId: any): Promise<void>;
135
+ }
136
+
137
+ declare class GeminiProvider extends BaseLLMProvider {
138
+ client: GoogleGenAI;
139
+ models: any;
140
+ defaultModel: any;
141
+ _pendingOperations: Map<any, any>;
142
+ chat(userMessage: any, systemPrompt?: string, options?: {}): Promise<{
143
+ text: string;
144
+ }>;
145
+ chatCompletion(messages: any, systemPrompt: any, tools?: any, options?: {}): Promise<{
146
+ parsedContent?: any;
147
+ content: string;
148
+ thought_signature: any;
149
+ tool_calls: {
150
+ type: string;
151
+ function: _google_genai.FunctionCall;
152
+ thought_signature: any;
153
+ }[];
154
+ finishReason: string;
155
+ _rawFinishReason: _google_genai.FinishReason;
156
+ _responseFormat: any;
157
+ }>;
158
+ _chatCompletionWithModel(messages: any, systemPrompt: any, tools: any, modelName: any, maxTokens: any, temperature: any, options?: {}): Promise<{
159
+ parsedContent?: any;
160
+ content: string;
161
+ thought_signature: any;
162
+ tool_calls: {
163
+ type: string;
164
+ function: _google_genai.FunctionCall;
165
+ thought_signature: any;
166
+ }[];
167
+ finishReason: string;
168
+ _rawFinishReason: _google_genai.FinishReason;
169
+ _responseFormat: any;
170
+ }>;
171
+ _buildGenerationConfig(options: any, maxTokens: any, temperature: any): {
172
+ temperature: any;
173
+ maxOutputTokens: any;
174
+ };
175
+ _convertToGeminiSchema(jsonSchema: any): {
176
+ type: string;
177
+ };
178
+ _shouldAutoParse(options: any): boolean;
179
+ _safeJsonParse(content: any): any;
180
+ executeTools(tool_calls: any, messages: any, tenantId: any, toolImplementations: any, env: any): Promise<void>;
181
+ imageGeneration(prompt: any, systemPrompt: any, options?: {}): Promise<{
182
+ imageData: string;
183
+ mimeType: string;
184
+ thought_signature: any;
185
+ }>;
186
+ _getModelForTier(tier: any): any;
187
+ startVideoGeneration(prompt: any, images: any, modelName: any, systemPrompt: any, options?: {}): Promise<{
188
+ operationName: string;
189
+ }>;
190
+ getVideoGenerationStatus(operationName: any): Promise<{
191
+ done: any;
192
+ progress: any;
193
+ state: any;
194
+ }>;
195
+ startDeepResearch(prompt: any, options?: {}): Promise<{
196
+ operationId: string;
197
+ }>;
198
+ getDeepResearchStatus(operationId: any): Promise<{
199
+ state: any;
200
+ done: boolean;
201
+ error: any;
202
+ }>;
203
+ }
204
+
205
+ /**
206
+ * Create a Hono handler for speech transcription.
207
+ *
208
+ * @param {Hono} app - Hono app or router instance to attach the endpoint to
209
+ * @param {Function} getConfig - Async function that returns transcription config from context
210
+ * Should return: { provider: 'openai'|'generic', apiKey: string, endpoint?: string, model?: string }
211
+ *
212
+ * @example
213
+ * // Mount in your Hono app:
214
+ * import { Hono } from 'hono';
215
+ * import { createSpeechHandler } from '@contentgrowth/llm-service';
216
+ *
217
+ * const speechHandler = new Hono();
218
+ * createSpeechHandler(speechHandler, async (c) => ({
219
+ * provider: 'openai',
220
+ * apiKey: c.env.OPENAI_API_KEY,
221
+ * }));
222
+ *
223
+ * app.route('/api/speech', speechHandler);
224
+ */
225
+ declare function createSpeechHandler(app: Hono, getConfig: Function): Hono;
226
+
227
+ /**
228
+ * LLM Service Module
229
+ *
230
+ * This module provides a unified interface for interacting with different LLM providers.
231
+ * It now supports BYOK (Bring Your Own Key) via Tenant Configuration.
232
+ */
233
+ declare class LLMService {
234
+ constructor(env: any, toolImplementations?: {});
235
+ env: any;
236
+ toolImplementations: {};
237
+ providerCache: Map<any, any>;
238
+ _getProvider(tenantId: any): Promise<any>;
239
+ /**
240
+ * Check if LLM service is configured for a tenant (or system default)
241
+ */
242
+ isConfigured(tenantId: any): Promise<boolean>;
243
+ /**
244
+ * Simple chat interface for single-turn conversations
245
+ */
246
+ chat(userMessage: any, tenantId: any, systemPrompt?: string, options?: {}): Promise<any>;
247
+ /**
248
+ * Interact with LLM for generation
249
+ *
250
+ * Intelligent signature detection supports:
251
+ * - chatCompletion(messages, tenantId, systemPrompt)
252
+ * - chatCompletion(messages, tenantId, systemPrompt, tools)
253
+ * - chatCompletion(messages, tenantId, systemPrompt, options)
254
+ * - chatCompletion(messages, tenantId, systemPrompt, tools, options)
255
+ *
256
+ * @param {Array} messages - Conversation messages
257
+ * @param {string} tenantId - Tenant identifier
258
+ * @param {string} systemPrompt - System instructions
259
+ * @param {Array|Object} toolsOrOptions - Tools array or options object
260
+ * @param {Object} optionsParam - Options object (if tools provided)
261
+ * @returns {Object} Response with content, tool_calls, and optionally parsedContent
262
+ */
263
+ chatCompletion(messages: any[], tenantId: string, systemPrompt: string, toolsOrOptions?: any[] | any, optionsParam?: any): any;
264
+ /**
265
+ * Helper to intelligently detect tools vs options parameters
266
+ * @private
267
+ */
268
+ private _parseToolsAndOptions;
269
+ /**
270
+ * Convenience method for JSON-only responses
271
+ * Automatically enables JSON mode and returns parsed object
272
+ *
273
+ * @param {Array} messages - Conversation messages
274
+ * @param {string} tenantId - Tenant identifier
275
+ * @param {string} systemPrompt - System instructions
276
+ * @param {Object} schema - Optional JSON schema for validation
277
+ * @param {Array} tools - Optional tools array
278
+ * @returns {Object} Parsed JSON object
279
+ * @throws {LLMServiceException} If JSON parsing fails
280
+ */
281
+ chatCompletionJson(messages: any[], tenantId: string, systemPrompt: string, schema?: any, tools?: any[]): any;
282
+ chatWithTools(messages: any, tenantId: any, systemPrompt: any, tools?: any[], options?: {}): Promise<{
283
+ content: any;
284
+ parsedContent: any;
285
+ toolCalls: any;
286
+ finishReason: any;
287
+ _rawFinishReason: any;
288
+ }>;
289
+ /**
290
+ * Generate a video (async wrapper with polling - backward compatibility)
291
+ */
292
+ videoGeneration(prompt: any, images: any, tenantId: any, modelName: any, systemPrompt: any, options?: {}): Promise<{
293
+ content: any;
294
+ videoUri: any;
295
+ }>;
296
+ /**
297
+ * Start video generation (returns operation name for polling)
298
+ */
299
+ startVideoGeneration(prompt: any, images: any, tenantId: any, modelName: any, systemPrompt: any, options?: {}): Promise<any>;
300
+ /**
301
+ * Get video generation status
302
+ */
303
+ getVideoGenerationStatus(operationName: any, tenantId: any): Promise<any>;
304
+ /**
305
+ * Generate an image
306
+ * Falls back to system keys if tenant doesn't have image capability enabled
307
+ * @param {string} prompt - Text description of the image
308
+ * @param {string} tenantId - Tenant identifier
309
+ * @param {string} systemPrompt - System instructions for generation
310
+ * @param {Object} options - Generation options (aspectRatio, images, etc.)
311
+ */
312
+ imageGeneration(prompt: string, tenantId: string, systemPrompt: string, options?: any): Promise<any>;
313
+ /**
314
+ * Start a Deep Research task
315
+ * @param {string} prompt - Research prompt/query
316
+ * @param {string} tenantId - Tenant identifier
317
+ * @param {Object} options - Options (agentId, etc.)
318
+ * @returns {Promise<{operationId: string}>}
319
+ */
320
+ startDeepResearch(prompt: string, tenantId: string, options?: any): Promise<{
321
+ operationId: string;
322
+ }>;
323
+ /**
324
+ * Get status of a Deep Research task
325
+ * @param {string} operationId - ID returned from startDeepResearch
326
+ * @param {string} tenantId - Tenant identifier
327
+ * @returns {Promise<{state: string, content?: string, citations?: any[]}>}
328
+ */
329
+ getDeepResearchStatus(operationId: string, tenantId: string): Promise<{
330
+ state: string;
331
+ content?: string;
332
+ citations?: any[];
333
+ }>;
334
+ }
335
+ declare class LLMServiceException extends Error {
336
+ constructor(message: any, statusCode?: number, details?: any);
337
+ statusCode: number;
338
+ details: any;
339
+ }
340
+
341
+ /**
342
+ * Abstract base class for Config Providers.
343
+ */
344
+ declare class BaseConfigProvider$1 {
345
+ /**
346
+ * Retrieve configuration for a specific tenant.
347
+ * @param {string} tenantId
348
+ * @param {Object} env
349
+ * @returns {Promise<Object>} Configuration object
350
+ */
351
+ getConfig(tenantId: string, env: any): Promise<any>;
352
+ }
353
+ /**
354
+ * Default implementation using Cloudflare KV and Durable Objects.
355
+ */
356
+ declare class DefaultConfigProvider extends BaseConfigProvider$1 {
357
+ getConfig(tenantId: any, env: any): Promise<{
358
+ provider: any;
359
+ apiKey: any;
360
+ models: any;
361
+ temperature: number;
362
+ maxTokens: number;
363
+ }>;
364
+ _loadFromTenantDO(tenantId: any, env: any): Promise<any>;
365
+ _buildTenantConfig(tenantConfig: any, env: any): {
366
+ provider: any;
367
+ apiKey: any;
368
+ models: any;
369
+ temperature: number;
370
+ maxTokens: number;
371
+ capabilities: any;
372
+ isTenantOwned: boolean;
373
+ };
374
+ _getSystemConfig(env: any): {
375
+ provider: any;
376
+ apiKey: any;
377
+ models: any;
378
+ temperature: number;
379
+ maxTokens: number;
380
+ };
381
+ }
382
+
383
+ declare namespace MODEL_CONFIGS {
384
+ namespace openai {
385
+ let _default: string;
386
+ export { _default as default };
387
+ export let edge: string;
388
+ export let fast: string;
389
+ export let cost: string;
390
+ export let free: string;
391
+ }
392
+ namespace gemini {
393
+ let _default_1: string;
394
+ export { _default_1 as default };
395
+ let edge_1: string;
396
+ export { edge_1 as edge };
397
+ let fast_1: string;
398
+ export { fast_1 as fast };
399
+ let cost_1: string;
400
+ export { cost_1 as cost };
401
+ let free_1: string;
402
+ export { free_1 as free };
403
+ export let video: string;
404
+ export let image: string;
405
+ }
406
+ }
407
+ declare class ConfigManager {
408
+ static _provider: DefaultConfigProvider;
409
+ /**
410
+ * Set a custom configuration provider.
411
+ * @param {BaseConfigProvider} provider
412
+ */
413
+ static setConfigProvider(provider: BaseConfigProvider): void;
414
+ static getConfig(tenantId: any, env: any): Promise<{
415
+ provider: any;
416
+ apiKey: any;
417
+ models: any;
418
+ temperature: number;
419
+ maxTokens: number;
420
+ }>;
421
+ }
422
+
423
+ /**
424
+ * Extracts and parses JSON from a text response (e.g., from an LLM).
425
+ * Handles JSON in markdown code blocks or plain JSON objects.
426
+ *
427
+ * TODO: improveme for better performance
428
+ *
429
+ * @param {string} text - The text containing JSON
430
+ * @returns {object|null} - The parsed JSON object, or null if no valid JSON found
431
+ */
432
+ declare function extractJsonFromResponse(text: string): object | null;
433
+ /**
434
+ * Generic helper to separate conversational text from a structured JSON payload.
435
+ * Supports both "Text + JSON" and "JSON + Text" patterns.
436
+ *
437
+ * @param {string} input - The full response string
438
+ * @returns {{text: string, json: object|null}}
439
+ */
440
+ declare function extractTextAndJson(input: string): {
441
+ text: string;
442
+ json: object | null;
443
+ };
444
+
445
+ /**
446
+ * Error Handling Utility for LLM Service
447
+ * Provides centralized error parsing and user-friendly message generation.
448
+ * Returns plain objects - framework-specific response handling is done by consumers.
449
+ */
450
+ /**
451
+ * Parse an error and return a standardized error response object.
452
+ * Detects specific error types like service overload, rate limits, and input issues.
453
+ *
454
+ * @param {Error} error - The caught error
455
+ * @param {string} operation - The operation being performed (e.g., 'generate image', 'edit article')
456
+ * @param {string} context - Context for logging (e.g., 'image_generation', 'ai_edit')
457
+ * @returns {{ message: string, error: string, retryable: boolean, statusCode: number }}
458
+ */
459
+ declare function handleApiError(error: Error, operation?: string, context?: string): {
460
+ message: string;
461
+ error: string;
462
+ retryable: boolean;
463
+ statusCode: number;
464
+ };
465
+ /**
466
+ * Sanitize error messages to prevent leaking technical details.
467
+ * Returns an Error with a clean error code that can be handled by the API layer.
468
+ * Use this when you want to throw an error rather than return a JSON response.
469
+ *
470
+ * @param {Error} error - The original error
471
+ * @param {string} context - Context of where error occurred (e.g., 'image_generation', 'ai_edit')
472
+ * @returns {Error} - Sanitized error with clean message code
473
+ */
474
+ declare function sanitizeError(error: Error, context?: string): Error;
475
+
476
+ /**
477
+ * Transcription Service - Separate from LLM Service
478
+ * Handles audio-to-text transcription using various providers.
479
+ *
480
+ * Supported providers:
481
+ * - 'openai': OpenAI Whisper API
482
+ * - 'generic': Any Whisper-compatible endpoint (Grok, self-hosted, etc.)
483
+ */
484
+ declare class TranscriptionService {
485
+ /**
486
+ * @param {Object} config
487
+ * @param {string} config.provider - 'openai' | 'generic'
488
+ * @param {string} config.apiKey - API key for the provider
489
+ * @param {string} [config.endpoint] - Custom endpoint URL (required for 'generic')
490
+ * @param {string} [config.model] - Model to use (default: 'whisper-1')
491
+ */
492
+ constructor(config: {
493
+ provider: string;
494
+ apiKey: string;
495
+ endpoint?: string;
496
+ model?: string;
497
+ });
498
+ provider: string;
499
+ apiKey: string;
500
+ endpoint: string;
501
+ model: string;
502
+ client: OpenAI;
503
+ /**
504
+ * Transcribe audio to text
505
+ * @param {File|Blob} audioFile - Audio file to transcribe
506
+ * @param {Object} options - Transcription options
507
+ * @param {string} [options.language] - Language hint (ISO-639-1 code)
508
+ * @param {string} [options.model] - Override default model
509
+ * @returns {Promise<{text: string}>}
510
+ */
511
+ transcribe(audioFile: File | Blob, options?: {
512
+ language?: string;
513
+ model?: string;
514
+ }): Promise<{
515
+ text: string;
516
+ }>;
517
+ _transcribeOpenAI(audioFile: any, model: any, language: any): Promise<{
518
+ text: string;
519
+ }>;
520
+ _transcribeGeneric(audioFile: any, model: any, language: any): Promise<{
521
+ text: any;
522
+ }>;
523
+ }
524
+ declare class TranscriptionServiceException extends Error {
525
+ constructor(message: any, statusCode?: number);
526
+ statusCode: number;
527
+ }
528
+
529
+ export { BaseConfigProvider$1 as BaseConfigProvider, ConfigManager, DefaultConfigProvider, FINISH_REASONS, GeminiProvider, LLMService, LLMServiceException, MODEL_CONFIGS, OpenAIProvider, TranscriptionService, TranscriptionServiceException, createSpeechHandler, extractJsonFromResponse, extractTextAndJson, handleApiError, sanitizeError };