hazo_llm_api 1.0.3 → 1.0.4

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 (151) hide show
  1. package/README.md +4 -4
  2. package/package.json +1 -1
  3. package/techdoc.md +2 -2
  4. package/dist/components/hazo_llm_prompt_config/hazo_llm_prompt_config.d.ts +0 -16
  5. package/dist/components/hazo_llm_prompt_config/hazo_llm_prompt_config.d.ts.map +0 -1
  6. package/dist/components/hazo_llm_prompt_config/hazo_llm_prompt_config.js +0 -258
  7. package/dist/components/hazo_llm_prompt_config/hazo_llm_prompt_config.js.map +0 -1
  8. package/dist/components/hazo_llm_prompt_config/index.d.ts +0 -8
  9. package/dist/components/hazo_llm_prompt_config/index.d.ts.map +0 -1
  10. package/dist/components/hazo_llm_prompt_config/index.js +0 -7
  11. package/dist/components/hazo_llm_prompt_config/index.js.map +0 -1
  12. package/dist/components/hazo_llm_prompt_config/types.d.ts +0 -74
  13. package/dist/components/hazo_llm_prompt_config/types.d.ts.map +0 -1
  14. package/dist/components/hazo_llm_prompt_config/types.js +0 -8
  15. package/dist/components/hazo_llm_prompt_config/types.js.map +0 -1
  16. package/dist/components/index.d.ts +0 -7
  17. package/dist/components/index.d.ts.map +0 -1
  18. package/dist/components/index.js +0 -7
  19. package/dist/components/index.js.map +0 -1
  20. package/dist/components/layout/index.d.ts +0 -7
  21. package/dist/components/layout/index.d.ts.map +0 -1
  22. package/dist/components/layout/index.js +0 -7
  23. package/dist/components/layout/index.js.map +0 -1
  24. package/dist/components/layout/layout.d.ts +0 -21
  25. package/dist/components/layout/layout.d.ts.map +0 -1
  26. package/dist/components/layout/layout.js +0 -18
  27. package/dist/components/layout/layout.js.map +0 -1
  28. package/dist/index.d.ts +0 -15
  29. package/dist/index.d.ts.map +0 -1
  30. package/dist/index.js +0 -21
  31. package/dist/index.js.map +0 -1
  32. package/dist/lib/config/config_parser.d.ts +0 -131
  33. package/dist/lib/config/config_parser.d.ts.map +0 -1
  34. package/dist/lib/config/config_parser.js +0 -297
  35. package/dist/lib/config/config_parser.js.map +0 -1
  36. package/dist/lib/config/index.d.ts +0 -8
  37. package/dist/lib/config/index.d.ts.map +0 -1
  38. package/dist/lib/config/index.js +0 -22
  39. package/dist/lib/config/index.js.map +0 -1
  40. package/dist/lib/config/provider_loader.d.ts +0 -113
  41. package/dist/lib/config/provider_loader.d.ts.map +0 -1
  42. package/dist/lib/config/provider_loader.js +0 -169
  43. package/dist/lib/config/provider_loader.js.map +0 -1
  44. package/dist/lib/database/index.d.ts +0 -8
  45. package/dist/lib/database/index.d.ts.map +0 -1
  46. package/dist/lib/database/index.js +0 -10
  47. package/dist/lib/database/index.js.map +0 -1
  48. package/dist/lib/database/init_database.d.ts +0 -118
  49. package/dist/lib/database/init_database.d.ts.map +0 -1
  50. package/dist/lib/database/init_database.js +0 -524
  51. package/dist/lib/database/init_database.js.map +0 -1
  52. package/dist/lib/database/utils.d.ts +0 -50
  53. package/dist/lib/database/utils.d.ts.map +0 -1
  54. package/dist/lib/database/utils.js +0 -78
  55. package/dist/lib/database/utils.js.map +0 -1
  56. package/dist/lib/index.d.ts +0 -14
  57. package/dist/lib/index.d.ts.map +0 -1
  58. package/dist/lib/index.js +0 -17
  59. package/dist/lib/index.js.map +0 -1
  60. package/dist/lib/llm_api/hazo_llm_image_image.d.ts +0 -26
  61. package/dist/lib/llm_api/hazo_llm_image_image.d.ts.map +0 -1
  62. package/dist/lib/llm_api/hazo_llm_image_image.js +0 -94
  63. package/dist/lib/llm_api/hazo_llm_image_image.js.map +0 -1
  64. package/dist/lib/llm_api/hazo_llm_image_image_text.d.ts +0 -26
  65. package/dist/lib/llm_api/hazo_llm_image_image_text.d.ts.map +0 -1
  66. package/dist/lib/llm_api/hazo_llm_image_image_text.js +0 -222
  67. package/dist/lib/llm_api/hazo_llm_image_image_text.js.map +0 -1
  68. package/dist/lib/llm_api/hazo_llm_image_text.d.ts +0 -20
  69. package/dist/lib/llm_api/hazo_llm_image_text.d.ts.map +0 -1
  70. package/dist/lib/llm_api/hazo_llm_image_text.js +0 -78
  71. package/dist/lib/llm_api/hazo_llm_image_text.js.map +0 -1
  72. package/dist/lib/llm_api/hazo_llm_text_image.d.ts +0 -20
  73. package/dist/lib/llm_api/hazo_llm_text_image.d.ts.map +0 -1
  74. package/dist/lib/llm_api/hazo_llm_text_image.js +0 -69
  75. package/dist/lib/llm_api/hazo_llm_text_image.js.map +0 -1
  76. package/dist/lib/llm_api/hazo_llm_text_image_text.d.ts +0 -26
  77. package/dist/lib/llm_api/hazo_llm_text_image_text.d.ts.map +0 -1
  78. package/dist/lib/llm_api/hazo_llm_text_image_text.js +0 -154
  79. package/dist/lib/llm_api/hazo_llm_text_image_text.js.map +0 -1
  80. package/dist/lib/llm_api/hazo_llm_text_text.d.ts +0 -20
  81. package/dist/lib/llm_api/hazo_llm_text_text.d.ts.map +0 -1
  82. package/dist/lib/llm_api/hazo_llm_text_text.js +0 -91
  83. package/dist/lib/llm_api/hazo_llm_text_text.js.map +0 -1
  84. package/dist/lib/llm_api/index.d.ts +0 -191
  85. package/dist/lib/llm_api/index.d.ts.map +0 -1
  86. package/dist/lib/llm_api/index.js +0 -1168
  87. package/dist/lib/llm_api/index.js.map +0 -1
  88. package/dist/lib/llm_api/provider_helper.d.ts +0 -163
  89. package/dist/lib/llm_api/provider_helper.d.ts.map +0 -1
  90. package/dist/lib/llm_api/provider_helper.js +0 -346
  91. package/dist/lib/llm_api/provider_helper.js.map +0 -1
  92. package/dist/lib/llm_api/types.d.ts +0 -525
  93. package/dist/lib/llm_api/types.d.ts.map +0 -1
  94. package/dist/lib/llm_api/types.js +0 -49
  95. package/dist/lib/llm_api/types.js.map +0 -1
  96. package/dist/lib/prompts/get_prompt.d.ts +0 -50
  97. package/dist/lib/prompts/get_prompt.d.ts.map +0 -1
  98. package/dist/lib/prompts/get_prompt.js +0 -232
  99. package/dist/lib/prompts/get_prompt.js.map +0 -1
  100. package/dist/lib/prompts/index.d.ts +0 -9
  101. package/dist/lib/prompts/index.d.ts.map +0 -1
  102. package/dist/lib/prompts/index.js +0 -9
  103. package/dist/lib/prompts/index.js.map +0 -1
  104. package/dist/lib/prompts/prompt_cache.d.ts +0 -151
  105. package/dist/lib/prompts/prompt_cache.d.ts.map +0 -1
  106. package/dist/lib/prompts/prompt_cache.js +0 -276
  107. package/dist/lib/prompts/prompt_cache.js.map +0 -1
  108. package/dist/lib/prompts/substitute_variables.d.ts +0 -38
  109. package/dist/lib/prompts/substitute_variables.d.ts.map +0 -1
  110. package/dist/lib/prompts/substitute_variables.js +0 -175
  111. package/dist/lib/prompts/substitute_variables.js.map +0 -1
  112. package/dist/lib/providers/gemini/gemini_client.d.ts +0 -25
  113. package/dist/lib/providers/gemini/gemini_client.d.ts.map +0 -1
  114. package/dist/lib/providers/gemini/gemini_client.js +0 -235
  115. package/dist/lib/providers/gemini/gemini_client.js.map +0 -1
  116. package/dist/lib/providers/gemini/gemini_provider.d.ts +0 -111
  117. package/dist/lib/providers/gemini/gemini_provider.d.ts.map +0 -1
  118. package/dist/lib/providers/gemini/gemini_provider.js +0 -431
  119. package/dist/lib/providers/gemini/gemini_provider.js.map +0 -1
  120. package/dist/lib/providers/gemini/index.d.ts +0 -8
  121. package/dist/lib/providers/gemini/index.d.ts.map +0 -1
  122. package/dist/lib/providers/gemini/index.js +0 -8
  123. package/dist/lib/providers/gemini/index.js.map +0 -1
  124. package/dist/lib/providers/index.d.ts +0 -8
  125. package/dist/lib/providers/index.d.ts.map +0 -1
  126. package/dist/lib/providers/index.js +0 -8
  127. package/dist/lib/providers/index.js.map +0 -1
  128. package/dist/lib/providers/qwen/index.d.ts +0 -8
  129. package/dist/lib/providers/qwen/index.d.ts.map +0 -1
  130. package/dist/lib/providers/qwen/index.js +0 -8
  131. package/dist/lib/providers/qwen/index.js.map +0 -1
  132. package/dist/lib/providers/qwen/qwen_client.d.ts +0 -154
  133. package/dist/lib/providers/qwen/qwen_client.d.ts.map +0 -1
  134. package/dist/lib/providers/qwen/qwen_client.js +0 -1002
  135. package/dist/lib/providers/qwen/qwen_client.js.map +0 -1
  136. package/dist/lib/providers/qwen/qwen_provider.d.ts +0 -139
  137. package/dist/lib/providers/qwen/qwen_provider.d.ts.map +0 -1
  138. package/dist/lib/providers/qwen/qwen_provider.js +0 -304
  139. package/dist/lib/providers/qwen/qwen_provider.js.map +0 -1
  140. package/dist/lib/providers/registry.d.ts +0 -66
  141. package/dist/lib/providers/registry.d.ts.map +0 -1
  142. package/dist/lib/providers/registry.js +0 -158
  143. package/dist/lib/providers/registry.js.map +0 -1
  144. package/dist/lib/providers/types.d.ts +0 -145
  145. package/dist/lib/providers/types.d.ts.map +0 -1
  146. package/dist/lib/providers/types.js +0 -37
  147. package/dist/lib/providers/types.js.map +0 -1
  148. package/dist/server.d.ts +0 -26
  149. package/dist/server.d.ts.map +0 -1
  150. package/dist/server.js +0 -49
  151. package/dist/server.js.map +0 -1
@@ -1,1168 +0,0 @@
1
- /**
2
- * LLM API Module
3
- *
4
- * Main entry point for the LLM API functionality.
5
- * Provides initialization and specialized LLM functions:
6
- * - hazo_llm_text_text: Text input → Text output
7
- * - hazo_llm_image_text: Image input → Text output
8
- * - hazo_llm_text_image: Text input → Image output
9
- * - hazo_llm_image_image: Image input → Image output
10
- * - hazo_llm_text_image_text: Text → Image → Text (chained)
11
- * - hazo_llm_image_image_text: Images → Image → Text (chained)
12
- *
13
- * Database is auto-initialized on module import using config defaults.
14
- */
15
- import { LLM_ERROR_CODES } from './types.js';
16
- import { initialize_database, get_database } from '../database/init_database.js';
17
- import { hazo_llm_text_text as hazo_llm_text_text_internal } from './hazo_llm_text_text.js';
18
- import { hazo_llm_image_text as hazo_llm_image_text_internal } from './hazo_llm_image_text.js';
19
- import { hazo_llm_text_image as hazo_llm_text_image_internal } from './hazo_llm_text_image.js';
20
- import { hazo_llm_image_image as hazo_llm_image_image_internal } from './hazo_llm_image_image.js';
21
- import { hazo_llm_text_image_text as hazo_llm_text_image_text_internal } from './hazo_llm_text_image_text.js';
22
- import { hazo_llm_image_image_text as hazo_llm_image_image_text_internal } from './hazo_llm_image_image_text.js';
23
- import { register_provider, set_enabled_llms, set_primary_llm, get_primary_llm, get_registered_providers, get_provider, } from '../providers/registry.js';
24
- import { GeminiProvider } from '../providers/gemini/index.js';
25
- import { QwenProvider } from '../providers/qwen/index.js';
26
- import { SERVICE_TYPES } from '../providers/types.js';
27
- import * as fs from 'fs';
28
- import * as path from 'path';
29
- import * as ini from 'ini';
30
- // =============================================================================
31
- // Module State
32
- // =============================================================================
33
- let initialized = false;
34
- let db_auto_initialized = false;
35
- let current_config = null;
36
- // =============================================================================
37
- // Default Logger
38
- // =============================================================================
39
- /**
40
- * Default console logger used when no custom logger is provided
41
- * Can be used directly or as a fallback in functions
42
- */
43
- export const default_logger = {
44
- error: (message, meta) => {
45
- console.error(`[HAZO_LLM_API ERROR] ${message}`, meta ? JSON.stringify(meta, null, 2) : '');
46
- },
47
- info: (message, meta) => {
48
- console.log(`[HAZO_LLM_API INFO] ${message}`, meta ? JSON.stringify(meta, null, 2) : '');
49
- },
50
- warn: (message, meta) => {
51
- console.warn(`[HAZO_LLM_API WARN] ${message}`, meta ? JSON.stringify(meta, null, 2) : '');
52
- },
53
- debug: (message, meta) => {
54
- console.debug(`[HAZO_LLM_API DEBUG] ${message}`, meta ? JSON.stringify(meta, null, 2) : '');
55
- },
56
- };
57
- /**
58
- * Stored logger instance - set during initialization
59
- */
60
- let stored_logger = default_logger;
61
- /**
62
- * Stored hooks instance - set during initialization
63
- */
64
- let stored_hooks = {};
65
- /**
66
- * Get the current logger instance
67
- * Returns the stored logger (set during initialization) or default logger
68
- *
69
- * @returns Current logger instance
70
- *
71
- * @example
72
- * ```typescript
73
- * import { get_logger } from 'hazo_llm_api/server';
74
- *
75
- * const logger = get_logger();
76
- * logger.info('My message');
77
- * ```
78
- */
79
- export function get_logger() {
80
- return stored_logger;
81
- }
82
- /**
83
- * Set the logger instance
84
- * Called internally during initialization, but can also be called directly
85
- *
86
- * @param logger - Logger instance to use
87
- */
88
- export function set_logger(logger) {
89
- stored_logger = logger;
90
- }
91
- /**
92
- * Get the current hooks configuration
93
- *
94
- * @returns Current hooks configuration
95
- */
96
- export function get_hooks() {
97
- return stored_hooks;
98
- }
99
- /**
100
- * Set the hooks configuration
101
- * Called internally during initialization, but can also be called directly
102
- *
103
- * @param hooks - Hooks configuration to use
104
- */
105
- export function set_hooks(hooks) {
106
- stored_hooks = hooks;
107
- }
108
- // =============================================================================
109
- // Config Reader
110
- // =============================================================================
111
- /**
112
- * Find the config file path
113
- * Searches in current directory and parent directories
114
- * @returns The path to the config file or null if not found
115
- */
116
- function find_config_file() {
117
- const config_filename = 'hazo_llm_api_config.ini';
118
- // Search paths: current dir, parent dir, grandparent dir
119
- const search_paths = [
120
- path.join(process.cwd(), config_filename),
121
- path.join(process.cwd(), '..', config_filename),
122
- path.join(process.cwd(), '..', '..', config_filename),
123
- ];
124
- for (const config_path of search_paths) {
125
- try {
126
- if (fs.existsSync(config_path)) {
127
- return config_path;
128
- }
129
- }
130
- catch {
131
- // Continue to next path
132
- }
133
- }
134
- return null;
135
- }
136
- /**
137
- * Read sqlite_path from hazo_llm_api_config.ini file
138
- * Searches in current directory and parent directories
139
- */
140
- function get_sqlite_path_from_config() {
141
- const default_path = 'prompt_library.sqlite';
142
- const config_path = find_config_file();
143
- if (config_path) {
144
- try {
145
- const config_content = fs.readFileSync(config_path, 'utf-8');
146
- const config = ini.parse(config_content);
147
- const sqlite_path = config.llm?.sqlite_path;
148
- if (sqlite_path) {
149
- default_logger.debug('Found sqlite_path in config', {
150
- file: 'index.ts',
151
- line: 137,
152
- data: { config_path, sqlite_path },
153
- });
154
- return sqlite_path;
155
- }
156
- }
157
- catch {
158
- // Use default
159
- }
160
- }
161
- default_logger.debug('Using default sqlite_path', {
162
- file: 'index.ts',
163
- line: 150,
164
- data: { default_path },
165
- });
166
- return default_path;
167
- }
168
- /**
169
- * Parse a generation config section from the ini file
170
- * Only includes parameters that are explicitly set (not commented out)
171
- * @param section - The parsed ini section object
172
- * @returns GeminiGenerationConfig or undefined if no params set
173
- */
174
- function parse_generation_config(section) {
175
- if (!section) {
176
- return undefined;
177
- }
178
- const config = {};
179
- let has_params = false;
180
- // Parse temperature (number)
181
- if (section.temperature !== undefined) {
182
- const temp = parseFloat(section.temperature);
183
- if (!isNaN(temp)) {
184
- config.temperature = temp;
185
- has_params = true;
186
- }
187
- }
188
- // Parse maxOutputTokens / max_output_tokens (number)
189
- const max_tokens = section.maxOutputTokens || section.max_output_tokens;
190
- if (max_tokens !== undefined) {
191
- const tokens = parseInt(max_tokens, 10);
192
- if (!isNaN(tokens)) {
193
- config.max_output_tokens = tokens;
194
- has_params = true;
195
- }
196
- }
197
- // Parse topP / top_p (number)
198
- const top_p = section.topP || section.top_p;
199
- if (top_p !== undefined) {
200
- const p = parseFloat(top_p);
201
- if (!isNaN(p)) {
202
- config.top_p = p;
203
- has_params = true;
204
- }
205
- }
206
- // Parse topK / top_k (number)
207
- const top_k = section.topK || section.top_k;
208
- if (top_k !== undefined) {
209
- const k = parseInt(top_k, 10);
210
- if (!isNaN(k)) {
211
- config.top_k = k;
212
- has_params = true;
213
- }
214
- }
215
- // Parse candidateCount / candidate_count (number)
216
- const candidate_count = section.candidateCount || section.candidate_count;
217
- if (candidate_count !== undefined) {
218
- const count = parseInt(candidate_count, 10);
219
- if (!isNaN(count)) {
220
- config.candidate_count = count;
221
- has_params = true;
222
- }
223
- }
224
- // Parse stopSequences / stop_sequences (JSON array string)
225
- const stop_sequences = section.stopSequences || section.stop_sequences;
226
- if (stop_sequences !== undefined) {
227
- try {
228
- const sequences = JSON.parse(stop_sequences);
229
- if (Array.isArray(sequences) && sequences.length > 0) {
230
- config.stop_sequences = sequences;
231
- has_params = true;
232
- }
233
- }
234
- catch {
235
- // Invalid JSON, skip
236
- }
237
- }
238
- // Parse responseMimeType / response_mime_type (string)
239
- const response_mime_type = section.responseMimeType || section.response_mime_type;
240
- if (response_mime_type !== undefined) {
241
- config.response_mime_type = response_mime_type;
242
- has_params = true;
243
- }
244
- return has_params ? config : undefined;
245
- }
246
- /**
247
- * Parse generation config from a section with optional prefix
248
- * Supports prefixed configs like "text_temperature" or "image_temperature"
249
- * @param section - The parsed ini section object
250
- * @param prefix - Optional prefix to filter keys (e.g., "text_" or "image_")
251
- * @returns GeminiGenerationConfig or undefined if no params set
252
- */
253
- function parse_prefixed_generation_config(section, prefix) {
254
- if (!section) {
255
- return undefined;
256
- }
257
- const config = {};
258
- let has_params = false;
259
- // Helper to get value with or without prefix
260
- const get_value = (key) => {
261
- if (prefix) {
262
- return section[`${prefix}${key}`];
263
- }
264
- return section[key];
265
- };
266
- // Parse temperature (number)
267
- const temp = get_value('temperature');
268
- if (temp !== undefined) {
269
- const temp_val = parseFloat(temp);
270
- if (!isNaN(temp_val)) {
271
- config.temperature = temp_val;
272
- has_params = true;
273
- }
274
- }
275
- // Parse maxOutputTokens (number)
276
- const max_tokens = get_value('maxOutputTokens') || get_value('max_output_tokens');
277
- if (max_tokens !== undefined) {
278
- const tokens = parseInt(max_tokens, 10);
279
- if (!isNaN(tokens)) {
280
- config.max_output_tokens = tokens;
281
- has_params = true;
282
- }
283
- }
284
- // Parse topP (number)
285
- const top_p = get_value('topP') || get_value('top_p');
286
- if (top_p !== undefined) {
287
- const p = parseFloat(top_p);
288
- if (!isNaN(p)) {
289
- config.top_p = p;
290
- has_params = true;
291
- }
292
- }
293
- // Parse topK (number)
294
- const top_k = get_value('topK') || get_value('top_k');
295
- if (top_k !== undefined) {
296
- const k = parseInt(top_k, 10);
297
- if (!isNaN(k)) {
298
- config.top_k = k;
299
- has_params = true;
300
- }
301
- }
302
- // Parse candidateCount (number)
303
- const candidate_count = get_value('candidateCount') || get_value('candidate_count');
304
- if (candidate_count !== undefined) {
305
- const count = parseInt(candidate_count, 10);
306
- if (!isNaN(count)) {
307
- config.candidate_count = count;
308
- has_params = true;
309
- }
310
- }
311
- // Parse stopSequences (JSON array string)
312
- const stop_sequences = get_value('stopSequences') || get_value('stop_sequences');
313
- if (stop_sequences !== undefined) {
314
- try {
315
- const sequences = JSON.parse(stop_sequences);
316
- if (Array.isArray(sequences) && sequences.length > 0) {
317
- config.stop_sequences = sequences;
318
- has_params = true;
319
- }
320
- }
321
- catch {
322
- // Invalid JSON, skip
323
- }
324
- }
325
- // Parse responseMimeType (string)
326
- const response_mime_type = get_value('responseMimeType') || get_value('response_mime_type');
327
- if (response_mime_type !== undefined) {
328
- config.response_mime_type = response_mime_type;
329
- has_params = true;
330
- }
331
- return has_params ? config : undefined;
332
- }
333
- /**
334
- * Parse capabilities from config value (JSON array or comma-separated)
335
- * @param value - Capabilities value from config
336
- * @returns Array of ServiceType or empty array
337
- */
338
- function parse_capabilities(value) {
339
- if (!value) {
340
- return [];
341
- }
342
- try {
343
- // Try parsing as JSON array first
344
- const parsed = JSON.parse(value);
345
- if (Array.isArray(parsed)) {
346
- return parsed.filter(cap => Object.values(SERVICE_TYPES).includes(cap));
347
- }
348
- }
349
- catch {
350
- // Not JSON, try comma-separated
351
- const caps = value.split(',').map(c => c.trim()).filter(Boolean);
352
- return caps.filter(cap => Object.values(SERVICE_TYPES).includes(cap));
353
- }
354
- return [];
355
- }
356
- /**
357
- * Parse enabled_llms from config (JSON array or comma-separated)
358
- * @param value - Enabled LLMs value from config
359
- * @returns Array of LLM names
360
- */
361
- function parse_enabled_llms(value) {
362
- if (!value) {
363
- return ['gemini']; // Default to gemini
364
- }
365
- try {
366
- // Try parsing as JSON array first
367
- const parsed = JSON.parse(value);
368
- if (Array.isArray(parsed)) {
369
- return parsed.filter((name) => typeof name === 'string' && name.length > 0);
370
- }
371
- }
372
- catch {
373
- // Not JSON, try comma-separated
374
- return value.split(',').map(name => name.trim()).filter(Boolean);
375
- }
376
- return [];
377
- }
378
- /**
379
- * Load API key from environment variable
380
- * @param provider_name - Provider name (e.g., "gemini")
381
- * @returns API key or undefined if not found
382
- */
383
- function load_api_key_from_env(provider_name) {
384
- // Try provider-specific env var: GEMINI_API_KEY, OPENAI_API_KEY, etc.
385
- const env_var_name = `${provider_name.toUpperCase()}_API_KEY`;
386
- return process.env[env_var_name];
387
- }
388
- /**
389
- * Read LLM global config from [llm] section
390
- * @returns Object with enabled_llms and primary_llm
391
- */
392
- function get_llm_global_config() {
393
- const config_path = find_config_file();
394
- const default_enabled = ['gemini'];
395
- const default_primary = 'gemini';
396
- const default_sqlite = 'prompt_library.sqlite';
397
- if (!config_path) {
398
- return {
399
- enabled_llms: default_enabled,
400
- primary_llm: default_primary,
401
- sqlite_path: default_sqlite,
402
- };
403
- }
404
- try {
405
- const config_content = fs.readFileSync(config_path, 'utf-8');
406
- const config = ini.parse(config_content);
407
- const llm_section = config.llm || {};
408
- const enabled_llms = parse_enabled_llms(llm_section.enabled_llms);
409
- const primary_llm = llm_section.primary_llm || default_primary;
410
- const sqlite_path = llm_section.sqlite_path || default_sqlite;
411
- return {
412
- enabled_llms: enabled_llms.length > 0 ? enabled_llms : default_enabled,
413
- primary_llm,
414
- sqlite_path,
415
- };
416
- }
417
- catch {
418
- return {
419
- enabled_llms: default_enabled,
420
- primary_llm: default_primary,
421
- sqlite_path: default_sqlite,
422
- };
423
- }
424
- }
425
- /**
426
- * Load and initialize Gemini provider from config
427
- * @param logger - Logger instance
428
- * @returns GeminiProvider instance or null if config invalid
429
- */
430
- function load_gemini_provider_from_config(logger) {
431
- const config_path = find_config_file();
432
- if (!config_path) {
433
- logger.warn('Config file not found, cannot load Gemini provider', {
434
- file: 'index.ts',
435
- line: 340,
436
- });
437
- return null;
438
- }
439
- try {
440
- const config_content = fs.readFileSync(config_path, 'utf-8');
441
- const config = ini.parse(config_content);
442
- const gemini_section = config.llm_gemini || {};
443
- // Support custom env var name via api_key_env config option
444
- const env_var_name = gemini_section.api_key_env || 'GEMINI_API_KEY';
445
- const api_key = process.env[env_var_name];
446
- if (!api_key) {
447
- logger.error(`${env_var_name} not found in environment variables`, {
448
- file: 'index.ts',
449
- line: 352,
450
- data: { config_path, env_var_name },
451
- });
452
- return null;
453
- }
454
- // Parse capabilities
455
- const capabilities = parse_capabilities(gemini_section.capabilities);
456
- // Parse generation configs with prefixes
457
- const text_config = parse_prefixed_generation_config(gemini_section, 'text_');
458
- const image_config = parse_prefixed_generation_config(gemini_section, 'image_');
459
- const provider_config = {
460
- api_key,
461
- api_url: gemini_section.api_url,
462
- api_url_image: gemini_section.api_url_image,
463
- model_text_text: gemini_section.model_text_text,
464
- model_image_text: gemini_section.model_image_text,
465
- model_text_image: gemini_section.model_text_image,
466
- model_image_image: gemini_section.model_image_image,
467
- text_config,
468
- image_config,
469
- capabilities: capabilities.length > 0 ? capabilities : undefined,
470
- logger,
471
- };
472
- return new GeminiProvider(provider_config);
473
- }
474
- catch (error) {
475
- const error_message = error instanceof Error ? error.message : String(error);
476
- logger.error('Failed to load Gemini provider from config', {
477
- file: 'index.ts',
478
- line: 378,
479
- data: { error: error_message, config_path },
480
- });
481
- return null;
482
- }
483
- }
484
- /**
485
- * Parse Qwen generation config from a section with optional prefix
486
- * Supports prefixed configs like "text_temperature" or "image_temperature"
487
- * @param section - The parsed ini section object
488
- * @param prefix - Optional prefix to filter keys (e.g., "text_" or "image_")
489
- * @returns QwenGenerationConfig or undefined if no params set
490
- */
491
- function parse_prefixed_qwen_generation_config(section, prefix) {
492
- if (!section) {
493
- return undefined;
494
- }
495
- const config = {};
496
- let has_params = false;
497
- // Helper to get value with or without prefix
498
- const get_value = (key) => {
499
- if (prefix) {
500
- return section[`${prefix}${key}`];
501
- }
502
- return section[key];
503
- };
504
- // Parse temperature (number)
505
- const temp = get_value('temperature');
506
- if (temp !== undefined) {
507
- const temp_val = parseFloat(temp);
508
- if (!isNaN(temp_val)) {
509
- config.temperature = temp_val;
510
- has_params = true;
511
- }
512
- }
513
- // Parse max_tokens (number)
514
- const max_tokens = get_value('max_tokens');
515
- if (max_tokens !== undefined) {
516
- const tokens = parseInt(max_tokens, 10);
517
- if (!isNaN(tokens)) {
518
- config.max_tokens = tokens;
519
- has_params = true;
520
- }
521
- }
522
- // Parse top_p (number)
523
- const top_p = get_value('top_p');
524
- if (top_p !== undefined) {
525
- const p = parseFloat(top_p);
526
- if (!isNaN(p)) {
527
- config.top_p = p;
528
- has_params = true;
529
- }
530
- }
531
- // Parse top_k (number)
532
- const top_k = get_value('top_k');
533
- if (top_k !== undefined) {
534
- const k = parseInt(top_k, 10);
535
- if (!isNaN(k)) {
536
- config.top_k = k;
537
- has_params = true;
538
- }
539
- }
540
- // Parse n (number)
541
- const n = get_value('n');
542
- if (n !== undefined) {
543
- const n_val = parseInt(n, 10);
544
- if (!isNaN(n_val)) {
545
- config.n = n_val;
546
- has_params = true;
547
- }
548
- }
549
- // Parse stop (JSON array string)
550
- const stop = get_value('stop');
551
- if (stop !== undefined) {
552
- try {
553
- const sequences = JSON.parse(stop);
554
- if (Array.isArray(sequences) && sequences.length > 0) {
555
- config.stop = sequences;
556
- has_params = true;
557
- }
558
- }
559
- catch {
560
- // Invalid JSON, skip
561
- }
562
- }
563
- // Parse presence_penalty (number)
564
- const presence_penalty = get_value('presence_penalty');
565
- if (presence_penalty !== undefined) {
566
- const penalty = parseFloat(presence_penalty);
567
- if (!isNaN(penalty)) {
568
- config.presence_penalty = penalty;
569
- has_params = true;
570
- }
571
- }
572
- // Parse frequency_penalty (number)
573
- const frequency_penalty = get_value('frequency_penalty');
574
- if (frequency_penalty !== undefined) {
575
- const penalty = parseFloat(frequency_penalty);
576
- if (!isNaN(penalty)) {
577
- config.frequency_penalty = penalty;
578
- has_params = true;
579
- }
580
- }
581
- return has_params ? config : undefined;
582
- }
583
- /**
584
- * Load and initialize Qwen provider from config
585
- * @param logger - Logger instance
586
- * @returns QwenProvider instance or null if config invalid
587
- */
588
- function load_qwen_provider_from_config(logger) {
589
- const config_path = find_config_file();
590
- if (!config_path) {
591
- logger.warn('Config file not found, cannot load Qwen provider', {
592
- file: 'index.ts',
593
- line: 500,
594
- });
595
- return null;
596
- }
597
- try {
598
- const config_content = fs.readFileSync(config_path, 'utf-8');
599
- const config = ini.parse(config_content);
600
- const qwen_section = config.llm_qwen || {};
601
- // Support custom env var name via api_key_env config option
602
- const env_var_name = qwen_section.api_key_env || 'QWEN_API_KEY';
603
- const api_key = process.env[env_var_name];
604
- if (!api_key) {
605
- logger.error(`${env_var_name} not found in environment variables`, {
606
- file: 'index.ts',
607
- line: 512,
608
- data: { config_path, env_var_name },
609
- });
610
- return null;
611
- }
612
- // Parse capabilities
613
- const capabilities = parse_capabilities(qwen_section.capabilities);
614
- // Parse generation configs with prefixes
615
- const text_config = parse_prefixed_qwen_generation_config(qwen_section, 'text_');
616
- const image_config = parse_prefixed_qwen_generation_config(qwen_section, 'image_');
617
- const provider_config = {
618
- api_key,
619
- api_url: qwen_section.api_url,
620
- model_text_text: qwen_section.model_text_text,
621
- model_image_text: qwen_section.model_image_text,
622
- model_text_image: qwen_section.model_text_image,
623
- model_image_image: qwen_section.model_image_image,
624
- api_url_text_text: qwen_section.api_url_text_text,
625
- api_url_image_text: qwen_section.api_url_image_text,
626
- api_url_text_image: qwen_section.api_url_text_image,
627
- api_url_image_image: qwen_section.api_url_image_image,
628
- system_instruction: qwen_section.system_instruction,
629
- text_config,
630
- image_config,
631
- capabilities: capabilities.length > 0 ? capabilities : undefined,
632
- logger,
633
- };
634
- return new QwenProvider(provider_config);
635
- }
636
- catch (error) {
637
- const error_message = error instanceof Error ? error.message : String(error);
638
- logger.error('Failed to load Qwen provider from config', {
639
- file: 'index.ts',
640
- line: 543,
641
- data: { error: error_message, config_path },
642
- });
643
- return null;
644
- }
645
- }
646
- /**
647
- * Load and register all enabled providers from config file
648
- * @param logger - Logger instance
649
- */
650
- function load_and_register_providers(logger) {
651
- const global_config = get_llm_global_config();
652
- // Set enabled LLMs and primary LLM in registry
653
- set_enabled_llms(global_config.enabled_llms);
654
- set_primary_llm(global_config.primary_llm);
655
- logger.info('Loading LLM providers from config', {
656
- file: 'index.ts',
657
- line: 395,
658
- data: {
659
- enabled_llms: global_config.enabled_llms,
660
- primary_llm: global_config.primary_llm,
661
- },
662
- });
663
- // Load each enabled provider
664
- for (const llm_name of global_config.enabled_llms) {
665
- if (llm_name.toLowerCase() === 'gemini') {
666
- const provider = load_gemini_provider_from_config(logger);
667
- if (provider) {
668
- register_provider(provider);
669
- logger.info('Registered Gemini provider', {
670
- file: 'index.ts',
671
- line: 636,
672
- data: {
673
- capabilities: Array.from(provider.get_capabilities()),
674
- },
675
- });
676
- }
677
- else {
678
- logger.warn('Gemini provider is enabled in config but failed to load. Check GEMINI_API_KEY in environment variables.', {
679
- file: 'index.ts',
680
- line: 716,
681
- data: { llm_name: llm_name.toLowerCase() },
682
- });
683
- }
684
- }
685
- else if (llm_name.toLowerCase() === 'qwen') {
686
- const provider = load_qwen_provider_from_config(logger);
687
- if (provider) {
688
- register_provider(provider);
689
- logger.info('Registered Qwen provider', {
690
- file: 'index.ts',
691
- line: 646,
692
- data: {
693
- capabilities: Array.from(provider.get_capabilities()),
694
- },
695
- });
696
- }
697
- else {
698
- logger.warn('Qwen provider is enabled in config but failed to load. Check QWEN_API_KEY in environment variables.', {
699
- file: 'index.ts',
700
- line: 728,
701
- data: { llm_name: llm_name.toLowerCase() },
702
- });
703
- }
704
- }
705
- // Future: Add other providers here (OpenAI, Anthropic, etc.)
706
- }
707
- }
708
- // =============================================================================
709
- // Auto-initialization on Import
710
- // =============================================================================
711
- /**
712
- * Auto-initialize database when module is imported
713
- * Uses config file defaults, does not require API key
714
- */
715
- async function auto_initialize_database() {
716
- if (db_auto_initialized) {
717
- return;
718
- }
719
- const file_name = 'index.ts (llm_api)';
720
- try {
721
- const sqlite_path = get_sqlite_path_from_config();
722
- default_logger.info('Auto-initializing database on module import', {
723
- file: file_name,
724
- line: 110,
725
- data: { sqlite_path },
726
- });
727
- await initialize_database(sqlite_path, default_logger);
728
- db_auto_initialized = true;
729
- default_logger.info('Database auto-initialized successfully', {
730
- file: file_name,
731
- line: 118,
732
- data: { sqlite_path },
733
- });
734
- }
735
- catch (error) {
736
- const error_message = error instanceof Error ? error.message : String(error);
737
- default_logger.error('Failed to auto-initialize database', {
738
- file: file_name,
739
- line: 124,
740
- data: { error: error_message },
741
- });
742
- // Don't throw - allow manual initialization later
743
- }
744
- }
745
- // Trigger auto-initialization when module is imported
746
- // Using void to handle the promise without blocking
747
- void auto_initialize_database();
748
- // =============================================================================
749
- // Initialization Function
750
- // =============================================================================
751
- /**
752
- * Initialize the LLM API with the given configuration
753
- * Creates/connects to the database and prepares the client for use
754
- *
755
- * @param config - Configuration options for the LLM API (all fields optional)
756
- * @returns Initialized LLM API client
757
- *
758
- * @example
759
- * ```typescript
760
- * // Minimal initialization (uses defaults)
761
- * const api = await initialize_llm_api({});
762
- *
763
- * // With custom logger
764
- * const api = await initialize_llm_api({ logger: myLogger });
765
- *
766
- * // With custom database path
767
- * const api = await initialize_llm_api({ sqlite_path: '~/data/prompts.db' });
768
- * ```
769
- */
770
- export async function initialize_llm_api(config = {}) {
771
- const file_name = 'index.ts (llm_api)';
772
- // Use provided logger or default
773
- const logger = config.logger || default_logger;
774
- // Store the logger for use by other functions
775
- set_logger(logger);
776
- // Store hooks if provided
777
- if (config.hooks) {
778
- set_hooks(config.hooks);
779
- }
780
- // Get global config from file
781
- const global_config = get_llm_global_config();
782
- // Use provided sqlite_path or fall back to config file value
783
- const sqlite_path = config.sqlite_path || global_config.sqlite_path;
784
- // Load and register providers from config file
785
- load_and_register_providers(logger);
786
- // Validate that primary_llm is enabled
787
- const primary_llm_name = get_primary_llm();
788
- if (!primary_llm_name) {
789
- const error_msg = 'No primary LLM configured. Set primary_llm in [llm] section of config file.';
790
- logger.error(error_msg, {
791
- file: file_name,
792
- line: 615,
793
- });
794
- throw new Error(error_msg);
795
- }
796
- logger.info('Initializing LLM API', {
797
- file: file_name,
798
- line: 620,
799
- data: {
800
- sqlite_path,
801
- enabled_llms: global_config.enabled_llms,
802
- primary_llm: primary_llm_name,
803
- },
804
- });
805
- // Set final config
806
- const final_config = {
807
- logger,
808
- sqlite_path,
809
- hooks: config.hooks,
810
- };
811
- // Initialize the database (async)
812
- try {
813
- await initialize_database(sqlite_path, logger);
814
- initialized = true;
815
- current_config = final_config;
816
- logger.info('LLM API initialized successfully', {
817
- file: file_name,
818
- line: 645,
819
- data: {
820
- primary_llm: primary_llm_name,
821
- registered_providers: get_registered_providers(),
822
- },
823
- });
824
- }
825
- catch (error) {
826
- const error_message = error instanceof Error ? error.message : String(error);
827
- logger.error('Failed to initialize LLM API', {
828
- file: file_name,
829
- line: 653,
830
- data: { error: error_message },
831
- });
832
- throw error;
833
- }
834
- // Create and return the client instance
835
- const client = {
836
- config: final_config,
837
- db_initialized: initialized,
838
- hazo_llm_text_text: async (params, llm) => {
839
- return hazo_llm_text_text(params, llm);
840
- },
841
- hazo_llm_image_text: async (params, llm) => {
842
- return hazo_llm_image_text(params, llm);
843
- },
844
- hazo_llm_text_image: async (params, llm) => {
845
- return hazo_llm_text_image(params, llm);
846
- },
847
- hazo_llm_image_image: async (params, llm) => {
848
- return hazo_llm_image_image(params, llm);
849
- },
850
- hazo_llm_text_image_text: async (params, llm) => {
851
- return hazo_llm_text_image_text(params, llm);
852
- },
853
- hazo_llm_image_image_text: async (params, llm) => {
854
- return hazo_llm_image_image_text(params, llm);
855
- },
856
- };
857
- return client;
858
- }
859
- // =============================================================================
860
- // Module Level Functions
861
- // =============================================================================
862
- /**
863
- * Helper to check full LLM API initialization (required for LLM calls)
864
- * Ensures logger is always present in returned config
865
- */
866
- function check_initialized() {
867
- if (!initialized || !current_config) {
868
- throw new Error('LLM API not initialized. Call initialize_llm_api first.');
869
- }
870
- // Ensure logger is always present
871
- return {
872
- ...current_config,
873
- logger: current_config.logger || get_logger(),
874
- };
875
- }
876
- /**
877
- * Check if database has been initialized (either auto or manual)
878
- * @returns true if database is ready for use
879
- */
880
- export function is_database_ready() {
881
- return db_auto_initialized || initialized;
882
- }
883
- /**
884
- * Wait for auto-initialization to complete
885
- * Useful if you need to ensure database is ready before operations
886
- */
887
- export async function ensure_database_ready() {
888
- if (db_auto_initialized || initialized) {
889
- return true;
890
- }
891
- // If not yet initialized, trigger it now
892
- await auto_initialize_database();
893
- return db_auto_initialized;
894
- }
895
- /**
896
- * Text input → Text output
897
- * Standard text generation using LLM
898
- *
899
- * @param params - Text input parameters
900
- * @param llm - Optional LLM provider name (uses primary LLM if not specified). Use LLM_PROVIDERS constants for type safety.
901
- * @returns LLM response with generated text
902
- *
903
- * @example
904
- * ```typescript
905
- * import { hazo_llm_text_text, LLM_PROVIDERS } from 'hazo_llm_api/server';
906
- *
907
- * const response = await hazo_llm_text_text({ prompt: 'Hello' }, LLM_PROVIDERS.GEMINI);
908
- * ```
909
- */
910
- export async function hazo_llm_text_text(params, llm) {
911
- try {
912
- const config = check_initialized();
913
- const db = get_database();
914
- return hazo_llm_text_text_internal(params, db, config, llm);
915
- }
916
- catch (error) {
917
- return { success: false, error: error instanceof Error ? error.message : String(error) };
918
- }
919
- }
920
- /**
921
- * Image input → Text output
922
- * Analyze an image and get text description
923
- *
924
- * @param params - Image input parameters
925
- * @param llm - Optional LLM provider name (uses primary LLM if not specified). Use LLM_PROVIDERS constants for type safety.
926
- * @returns LLM response with text description
927
- */
928
- export async function hazo_llm_image_text(params, llm) {
929
- try {
930
- const config = check_initialized();
931
- const db = get_database();
932
- return hazo_llm_image_text_internal(params, db, config, llm);
933
- }
934
- catch (error) {
935
- return { success: false, error: error instanceof Error ? error.message : String(error) };
936
- }
937
- }
938
- /**
939
- * Text input → Image output
940
- * Generate an image from text description
941
- *
942
- * @param params - Text input parameters for image generation
943
- * @param llm - Optional LLM provider name (uses primary LLM if not specified). Use LLM_PROVIDERS constants for type safety.
944
- * @returns LLM response with generated image
945
- */
946
- export async function hazo_llm_text_image(params, llm) {
947
- try {
948
- const config = check_initialized();
949
- const db = get_database();
950
- return hazo_llm_text_image_internal(params, db, config, llm);
951
- }
952
- catch (error) {
953
- return { success: false, error: error instanceof Error ? error.message : String(error) };
954
- }
955
- }
956
- /**
957
- * Image input → Image output
958
- * Transform/edit an image based on instructions
959
- *
960
- * @param params - Image input parameters with transformation instructions
961
- * @param llm - Optional LLM provider name (uses primary LLM if not specified). Use LLM_PROVIDERS constants for type safety.
962
- * @returns LLM response with transformed image
963
- */
964
- export async function hazo_llm_image_image(params, llm) {
965
- try {
966
- const config = check_initialized();
967
- const db = get_database();
968
- return hazo_llm_image_image_internal(params, db, config, llm);
969
- }
970
- catch (error) {
971
- return { success: false, error: error instanceof Error ? error.message : String(error) };
972
- }
973
- }
974
- /**
975
- * Text → Image → Text (Chained)
976
- * Generate an image from prompt_image, then analyze it with prompt_text
977
- *
978
- * @param params - Parameters with two prompts: one for image gen, one for analysis
979
- * @param llm - Optional LLM provider name (uses primary LLM if not specified). Use LLM_PROVIDERS constants for type safety.
980
- * @returns LLM response with generated image and analysis text
981
- */
982
- export async function hazo_llm_text_image_text(params, llm) {
983
- try {
984
- const config = check_initialized();
985
- const db = get_database();
986
- return hazo_llm_text_image_text_internal(params, db, config, llm);
987
- }
988
- catch (error) {
989
- return { success: false, error: error instanceof Error ? error.message : String(error) };
990
- }
991
- }
992
- /**
993
- * Images → Image → Text (Chained)
994
- * Chain multiple image transformations, then describe the final result
995
- *
996
- * @param params - Parameters with images, prompts, and description prompt
997
- * @param llm - Optional LLM provider name (uses primary LLM if not specified). Use LLM_PROVIDERS constants for type safety.
998
- * @returns LLM response with final image and description text
999
- */
1000
- export async function hazo_llm_image_image_text(params, llm) {
1001
- try {
1002
- const config = check_initialized();
1003
- const db = get_database();
1004
- return hazo_llm_image_image_text_internal(params, db, config, llm);
1005
- }
1006
- catch (error) {
1007
- return { success: false, error: error instanceof Error ? error.message : String(error) };
1008
- }
1009
- }
1010
- // =============================================================================
1011
- // Streaming Functions
1012
- // =============================================================================
1013
- /**
1014
- * Text input → Text output (Streaming)
1015
- * Generate text from a prompt with streaming response
1016
- *
1017
- * @param params - Text input parameters
1018
- * @param llm - Optional LLM provider name (uses primary LLM if not specified)
1019
- * @returns Async generator yielding text chunks
1020
- *
1021
- * @example
1022
- * ```typescript
1023
- * const stream = await hazo_llm_text_text_stream({ prompt: 'Tell me a story' });
1024
- *
1025
- * for await (const chunk of stream) {
1026
- * if (chunk.error) {
1027
- * console.error(chunk.error);
1028
- * break;
1029
- * }
1030
- * process.stdout.write(chunk.text);
1031
- * if (chunk.done) break;
1032
- * }
1033
- * ```
1034
- */
1035
- export async function* hazo_llm_text_text_stream(params, llm) {
1036
- try {
1037
- const config = check_initialized();
1038
- const logger = config.logger || get_logger();
1039
- // Get provider
1040
- const provider = get_provider(llm, logger);
1041
- if (!provider) {
1042
- yield {
1043
- text: '',
1044
- done: true,
1045
- error: `Provider "${llm || 'primary'}" not found`,
1046
- error_info: {
1047
- code: LLM_ERROR_CODES.PROVIDER_NOT_FOUND,
1048
- message: `Provider "${llm || 'primary'}" not found`,
1049
- retryable: false,
1050
- },
1051
- };
1052
- return;
1053
- }
1054
- // Check if provider supports streaming
1055
- if (!provider.text_text_stream) {
1056
- yield {
1057
- text: '',
1058
- done: true,
1059
- error: `Provider "${provider.get_name()}" does not support streaming`,
1060
- error_info: {
1061
- code: LLM_ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
1062
- message: `Provider "${provider.get_name()}" does not support streaming for text_text`,
1063
- retryable: false,
1064
- },
1065
- };
1066
- return;
1067
- }
1068
- // Call streaming method
1069
- const stream = await provider.text_text_stream(params, logger);
1070
- yield* stream;
1071
- }
1072
- catch (error) {
1073
- const error_message = error instanceof Error ? error.message : String(error);
1074
- yield {
1075
- text: '',
1076
- done: true,
1077
- error: error_message,
1078
- error_info: {
1079
- code: LLM_ERROR_CODES.UNKNOWN,
1080
- message: error_message,
1081
- retryable: false,
1082
- },
1083
- };
1084
- }
1085
- }
1086
- /**
1087
- * Image input → Text output (Streaming)
1088
- * Analyze an image and stream text description
1089
- *
1090
- * @param params - Image input parameters
1091
- * @param llm - Optional LLM provider name (uses primary LLM if not specified)
1092
- * @returns Async generator yielding text chunks
1093
- */
1094
- export async function* hazo_llm_image_text_stream(params, llm) {
1095
- try {
1096
- const config = check_initialized();
1097
- const logger = config.logger || get_logger();
1098
- // Get provider
1099
- const provider = get_provider(llm, logger);
1100
- if (!provider) {
1101
- yield {
1102
- text: '',
1103
- done: true,
1104
- error: `Provider "${llm || 'primary'}" not found`,
1105
- error_info: {
1106
- code: LLM_ERROR_CODES.PROVIDER_NOT_FOUND,
1107
- message: `Provider "${llm || 'primary'}" not found`,
1108
- retryable: false,
1109
- },
1110
- };
1111
- return;
1112
- }
1113
- // Check if provider supports streaming
1114
- if (!provider.image_text_stream) {
1115
- yield {
1116
- text: '',
1117
- done: true,
1118
- error: `Provider "${provider.get_name()}" does not support streaming`,
1119
- error_info: {
1120
- code: LLM_ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
1121
- message: `Provider "${provider.get_name()}" does not support streaming for image_text`,
1122
- retryable: false,
1123
- },
1124
- };
1125
- return;
1126
- }
1127
- // Call streaming method
1128
- const stream = await provider.image_text_stream(params, logger);
1129
- yield* stream;
1130
- }
1131
- catch (error) {
1132
- const error_message = error instanceof Error ? error.message : String(error);
1133
- yield {
1134
- text: '',
1135
- done: true,
1136
- error: error_message,
1137
- error_info: {
1138
- code: LLM_ERROR_CODES.UNKNOWN,
1139
- message: error_message,
1140
- retryable: false,
1141
- },
1142
- };
1143
- }
1144
- }
1145
- // =============================================================================
1146
- // Utility Functions
1147
- // =============================================================================
1148
- /**
1149
- * Check if the LLM API has been initialized
1150
- * @returns true if initialized
1151
- */
1152
- export function is_initialized() {
1153
- return initialized;
1154
- }
1155
- /**
1156
- * Get the current configuration (without sensitive logger)
1157
- * @returns Current configuration or null if not initialized
1158
- */
1159
- export function get_current_config() {
1160
- if (!current_config) {
1161
- return null;
1162
- }
1163
- return {
1164
- sqlite_path: current_config.sqlite_path,
1165
- hooks: current_config.hooks,
1166
- };
1167
- }
1168
- //# sourceMappingURL=index.js.map