berget 1.2.0 → 1.3.1

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.
@@ -1,6 +1,5 @@
1
- import { createAuthenticatedClient } from '../client'
2
- import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure'
3
- import chalk from 'chalk'
1
+ import { createAuthenticatedClient, API_BASE_URL } from '../client'
2
+ import { logger } from '../utils/logger'
4
3
 
5
4
  export interface ChatMessage {
6
5
  role: 'system' | 'user' | 'assistant'
@@ -8,13 +7,14 @@ export interface ChatMessage {
8
7
  }
9
8
 
10
9
  export interface ChatCompletionOptions {
11
- model: string
10
+ model?: string
12
11
  messages: ChatMessage[]
13
12
  temperature?: number
14
13
  max_tokens?: number
15
14
  stream?: boolean
16
15
  top_p?: number
17
16
  apiKey?: string
17
+ onChunk?: (chunk: any) => void
18
18
  }
19
19
 
20
20
  /**
@@ -24,14 +24,14 @@ export interface ChatCompletionOptions {
24
24
  export class ChatService {
25
25
  private static instance: ChatService
26
26
  private client = createAuthenticatedClient()
27
-
27
+
28
28
  // Command group name for this service
29
29
  public static readonly COMMAND_GROUP = 'chat'
30
-
30
+
31
31
  // Subcommands for this service
32
32
  public static readonly COMMANDS = {
33
33
  RUN: 'run',
34
- LIST: 'list'
34
+ LIST: 'list',
35
35
  }
36
36
 
37
37
  private constructor() {}
@@ -49,202 +49,403 @@ export class ChatService {
49
49
  */
50
50
  public async createCompletion(options: ChatCompletionOptions): Promise<any> {
51
51
  try {
52
- console.log(chalk.yellow('DEBUG: Starting createCompletion method'))
53
-
54
- // Check if options is defined
55
- if (!options) {
56
- console.log(chalk.red('ERROR: options is undefined'))
57
- throw new Error('Chat completion options are undefined')
58
- }
59
-
60
- // Log the raw options object
61
- console.log(chalk.yellow('DEBUG: Raw options:'), typeof options, options ? 'defined' : 'undefined')
62
-
63
- const headers: Record<string, string> = {}
64
-
65
- // Check if debug is enabled
66
- const isDebug = process.argv.includes('--debug')
67
-
68
- if (isDebug) {
69
- console.log(chalk.yellow('DEBUG: Starting createCompletion with options:'))
70
- try {
71
- console.log(chalk.yellow(JSON.stringify({
72
- ...options,
73
- apiKey: options.apiKey ? '***' : undefined,
74
- messages: options.messages ? `${options.messages.length} messages` : undefined
75
- }, null, 2)))
76
- } catch (error) {
77
- console.log(chalk.red('ERROR: Failed to stringify options:'), error)
78
- }
52
+ logger.debug('Starting createCompletion method')
53
+
54
+ // Initialize options if undefined
55
+ const optionsCopy = options ? { ...options } : { messages: [] }
56
+
57
+ // Check if messages are defined
58
+ if (!optionsCopy.messages || !Array.isArray(optionsCopy.messages)) {
59
+ logger.error('messages is undefined or not an array')
60
+ optionsCopy.messages = []
79
61
  }
80
-
81
- // Create a copy of options to avoid modifying the original
82
- const optionsCopy = { ...options }
83
-
84
- if (isDebug) {
85
- console.log(chalk.yellow('DEBUG: Checking for API key'))
86
- console.log(chalk.yellow(`DEBUG: optionsCopy.apiKey exists: ${!!optionsCopy.apiKey}`))
62
+
63
+ // Log the options object
64
+ logger.debug('Starting createCompletion with options:')
65
+ try {
66
+ logger.debug(
67
+ JSON.stringify(
68
+ {
69
+ ...optionsCopy,
70
+ apiKey: optionsCopy.apiKey ? '***' : undefined,
71
+ messages: optionsCopy.messages
72
+ ? `${optionsCopy.messages.length} messages`
73
+ : '0 messages',
74
+ },
75
+ null,
76
+ 2
77
+ )
78
+ )
79
+ } catch (error) {
80
+ logger.error('Failed to stringify options:', error)
87
81
  }
88
-
82
+
83
+ const headers: Record<string, string> = {}
84
+
89
85
  // Check for environment variables first - prioritize this over everything else
90
- const envApiKey = process.env.BERGET_API_KEY;
86
+ const envApiKey = process.env.BERGET_API_KEY
91
87
  if (envApiKey) {
92
- if (isDebug) {
93
- console.log(chalk.yellow('DEBUG: Using API key from BERGET_API_KEY environment variable'));
94
- }
95
- optionsCopy.apiKey = envApiKey;
96
- }
88
+ logger.debug('Using API key from BERGET_API_KEY environment variable')
89
+ optionsCopy.apiKey = envApiKey
90
+ // Skip the default API key logic if we already have a key
91
+ return this.executeCompletion(optionsCopy, headers)
92
+ }
93
+ // If API key is already provided, use it directly
94
+ else if (optionsCopy.apiKey) {
95
+ logger.debug('Using API key provided in options')
96
+ // Skip the default API key logic if we already have a key
97
+ return this.executeCompletion(optionsCopy, headers)
98
+ }
97
99
  // Only try to get the default API key if no API key is provided and no env var is set
98
- else if (!optionsCopy.apiKey) {
99
- if (isDebug) {
100
- console.log(chalk.yellow('DEBUG: No API key provided, trying to get default'))
101
- }
102
-
100
+ else {
101
+ logger.debug('No API key provided, trying to get default')
102
+
103
103
  try {
104
104
  // Import the DefaultApiKeyManager directly
105
- if (isDebug) {
106
- console.log(chalk.yellow('DEBUG: Importing DefaultApiKeyManager'))
107
- }
108
-
109
- const DefaultApiKeyManager = (await import('../utils/default-api-key')).DefaultApiKeyManager;
110
- const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
111
-
112
- if (isDebug) {
113
- console.log(chalk.yellow('DEBUG: Got DefaultApiKeyManager instance'))
114
- }
115
-
105
+ logger.debug('Importing DefaultApiKeyManager')
106
+
107
+ const DefaultApiKeyManager = (
108
+ await import('../utils/default-api-key')
109
+ ).DefaultApiKeyManager
110
+ const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
111
+
112
+ logger.debug('Got DefaultApiKeyManager instance')
113
+
116
114
  // Try to get the default API key
117
- if (isDebug) {
118
- console.log(chalk.yellow('DEBUG: Calling promptForDefaultApiKey'))
119
- }
120
-
121
- const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
122
- const apiKey = defaultApiKeyData?.key || await defaultApiKeyManager.promptForDefaultApiKey();
123
-
124
- if (isDebug) {
125
- console.log(chalk.yellow(`DEBUG: Default API key data exists: ${!!defaultApiKeyData}`))
126
- console.log(chalk.yellow(`DEBUG: promptForDefaultApiKey returned: ${apiKey ? 'a key' : 'null'}`))
127
- }
128
-
115
+ logger.debug('Calling promptForDefaultApiKey')
116
+
117
+ const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData()
118
+ const apiKey =
119
+ defaultApiKeyData?.key ||
120
+ (await defaultApiKeyManager.promptForDefaultApiKey())
121
+
122
+ logger.debug(`Default API key data exists: ${!!defaultApiKeyData}`)
123
+ logger.debug(
124
+ `promptForDefaultApiKey returned: ${apiKey ? 'a key' : 'null'}`
125
+ )
126
+
129
127
  if (apiKey) {
130
- if (isDebug) {
131
- console.log(chalk.yellow('DEBUG: Using API key from default API key manager'));
132
- }
133
- optionsCopy.apiKey = apiKey;
128
+ logger.debug('Using API key from default API key manager')
129
+ optionsCopy.apiKey = apiKey
134
130
  } else {
135
- console.log(chalk.yellow('No API key available. You need to either:'));
136
- console.log(chalk.yellow('1. Create an API key with: berget api-keys create --name "My Key"'));
137
- console.log(chalk.yellow('2. Set a default API key with: berget api-keys set-default <id>'));
138
- console.log(chalk.yellow('3. Provide an API key with the --api-key option'));
139
- console.log(chalk.yellow('4. Set the BERGET_API_KEY environment variable'));
140
- console.log(chalk.yellow('\nExample:'));
141
- console.log(chalk.yellow(' export BERGET_API_KEY=your_api_key_here'));
142
- console.log(chalk.yellow(' # or for a single command:'));
143
- console.log(chalk.yellow(' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it'));
144
- throw new Error('No API key provided and no default API key set');
131
+ logger.warn('No API key available. You need to either:')
132
+ logger.warn(
133
+ '1. Create an API key with: berget api-keys create --name "My Key"'
134
+ )
135
+ logger.warn(
136
+ '2. Set a default API key with: berget api-keys set-default <id>'
137
+ )
138
+ logger.warn('3. Provide an API key with the --api-key option')
139
+ logger.warn('4. Set the BERGET_API_KEY environment variable')
140
+ logger.warn('\nExample:')
141
+ logger.warn(' export BERGET_API_KEY=your_api_key_here')
142
+ logger.warn(' # or for a single command:')
143
+ logger.warn(
144
+ ' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it'
145
+ )
146
+ throw new Error('No API key provided and no default API key set')
145
147
  }
146
-
148
+
147
149
  // Set the API key in the options
148
- if (isDebug) {
149
- console.log(chalk.yellow('DEBUG: Setting API key in options'))
150
- }
151
-
150
+ logger.debug('Setting API key in options')
151
+
152
152
  // Only set the API key if it's not null
153
153
  if (apiKey) {
154
- optionsCopy.apiKey = apiKey;
154
+ optionsCopy.apiKey = apiKey
155
155
  }
156
156
  } catch (error) {
157
- console.log(chalk.red('Error getting API key:'))
157
+ logger.error('Error getting API key:')
158
158
  if (error instanceof Error) {
159
- console.log(chalk.red(error.message))
159
+ logger.error(error.message)
160
160
  }
161
- console.log(chalk.yellow('Please create an API key with: berget api-keys create --name "My Key"'))
161
+ logger.warn(
162
+ 'Please create an API key with: berget api-keys create --name "My Key"'
163
+ )
162
164
  throw new Error('Failed to get API key')
163
165
  }
164
166
  }
165
-
166
- if (isDebug) {
167
- console.log(chalk.yellow('DEBUG: Chat completion options:'))
168
- console.log(chalk.yellow(JSON.stringify({
169
- ...optionsCopy,
170
- apiKey: optionsCopy.apiKey ? '***' : undefined // Hide the actual API key in debug output
171
- }, null, 2)))
172
- }
173
-
174
- // If an API key is provided, use it for this request
175
- if (optionsCopy.apiKey) {
176
- headers['Authorization'] = `Bearer ${optionsCopy.apiKey}`
177
- // Remove apiKey from options before sending to API
178
- const { apiKey, ...requestOptions } = optionsCopy
179
-
180
- if (isDebug) {
181
- console.log(chalk.yellow('DEBUG: Using provided API key'))
182
- console.log(chalk.yellow('DEBUG: Request options:'))
183
- console.log(chalk.yellow(JSON.stringify(requestOptions, null, 2)))
184
- }
185
-
186
- try {
187
- const response = await this.client.POST('/v1/chat/completions', {
188
- body: requestOptions,
189
- headers
190
- })
191
-
192
- // Check if response has an error property
193
- const responseAny = response as any;
194
- if (responseAny && responseAny.error)
195
- throw new Error(JSON.stringify(responseAny.error))
196
-
197
- if (isDebug) {
198
- console.log(chalk.yellow('DEBUG: API response:'))
199
- console.log(chalk.yellow(JSON.stringify(response, null, 2)))
200
-
201
- // Output the complete response data for debugging
202
- console.log(chalk.yellow('DEBUG: Complete response data:'))
203
- console.log(chalk.yellow(JSON.stringify(response.data, null, 2)))
204
- }
205
-
206
- return response.data
207
- } catch (requestError) {
208
- if (process.argv.includes('--debug')) {
209
- console.log(chalk.red(`DEBUG: Request error: ${requestError instanceof Error ? requestError.message : String(requestError)}`))
210
- }
211
- throw requestError
212
- }
213
- } else {
214
- // We've exhausted all options for getting an API key
215
- console.log(chalk.yellow('No API key available. You need to either:'));
216
- console.log(chalk.yellow('1. Create an API key with: berget api-keys create --name "My Key"'));
217
- console.log(chalk.yellow('2. Set a default API key with: berget api-keys set-default <id>'));
218
- console.log(chalk.yellow('3. Provide an API key with the --api-key option'));
219
- console.log(chalk.yellow('4. Set the BERGET_API_KEY environment variable'));
220
- console.log(chalk.yellow('\nExample:'));
221
- console.log(chalk.yellow(' export BERGET_API_KEY=your_api_key_here'));
222
- console.log(chalk.yellow(' # or for a single command:'));
223
- console.log(chalk.yellow(' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it'));
224
- throw new Error('No API key available. Please provide an API key or set a default API key.');
167
+
168
+ // Set default model if not provided
169
+ if (!optionsCopy.model) {
170
+ logger.debug('No model specified, using default: google/gemma-3-27b-it')
171
+ optionsCopy.model = 'google/gemma-3-27b-it'
225
172
  }
173
+
174
+ logger.debug('Chat completion options:')
175
+ logger.debug(
176
+ JSON.stringify(
177
+ {
178
+ ...optionsCopy,
179
+ apiKey: optionsCopy.apiKey ? '***' : undefined, // Hide the actual API key in debug output
180
+ },
181
+ null,
182
+ 2
183
+ )
184
+ )
185
+
186
+ return this.executeCompletion(optionsCopy, headers)
226
187
  } catch (error) {
227
188
  // Improved error handling
228
- let errorMessage = 'Failed to create chat completion';
229
-
189
+ let errorMessage = 'Failed to create chat completion'
190
+
230
191
  if (error instanceof Error) {
231
192
  try {
232
193
  // Try to parse the error message as JSON
233
- const parsedError = JSON.parse(error.message);
194
+ const parsedError = JSON.parse(error.message)
234
195
  if (parsedError.error && parsedError.error.message) {
235
- errorMessage = `Chat error: ${parsedError.error.message}`;
196
+ errorMessage = `Chat error: ${parsedError.error.message}`
236
197
  }
237
198
  } catch (e) {
238
199
  // If parsing fails, use the original error message
239
- errorMessage = `Chat error: ${error.message}`;
200
+ errorMessage = `Chat error: ${error.message}`
240
201
  }
241
202
  }
242
-
243
- console.error(chalk.red(errorMessage));
244
- throw new Error(errorMessage);
203
+
204
+ logger.error(errorMessage)
205
+ throw new Error(errorMessage)
245
206
  }
246
207
  }
247
-
208
+
209
+ /**
210
+ * Execute the completion request with the provided options
211
+ * @param options The completion options
212
+ * @param headers Additional headers to include
213
+ * @returns The completion response
214
+ */
215
+ private async executeCompletion(
216
+ options: ChatCompletionOptions,
217
+ headers: Record<string, string> = {}
218
+ ): Promise<any> {
219
+ try {
220
+ // If an API key is provided, use it for this request
221
+ if (options.apiKey) {
222
+ // API keys should be sent directly, not with Bearer prefix
223
+ headers['Authorization'] = options.apiKey
224
+ }
225
+
226
+ // Remove apiKey and onChunk from options before sending to API
227
+ const { apiKey, onChunk, ...requestOptions } = options
228
+
229
+ logger.debug('Request options:')
230
+ logger.debug(
231
+ JSON.stringify(
232
+ {
233
+ ...requestOptions,
234
+ messages: requestOptions.messages
235
+ ? `${requestOptions.messages.length} messages`
236
+ : '0 messages',
237
+ },
238
+ null,
239
+ 2
240
+ )
241
+ )
242
+
243
+ // Handle streaming responses differently
244
+ if (requestOptions.stream && onChunk) {
245
+ return await this.handleStreamingResponse(
246
+ { ...requestOptions, onChunk },
247
+ headers
248
+ )
249
+ } else {
250
+ // Ensure model is always defined for the API call
251
+ const requestBody = {
252
+ ...requestOptions,
253
+ model: requestOptions.model || 'google/gemma-3-27b-it',
254
+ }
255
+
256
+ // Debug the headers being sent
257
+ logger.debug('Headers being sent:')
258
+ logger.debug(JSON.stringify(headers, null, 2))
259
+
260
+ const response = await this.client.POST('/v1/chat/completions', {
261
+ body: requestBody,
262
+ headers,
263
+ })
264
+
265
+ // Check if response has an error property
266
+ const responseAny = response as any
267
+ if (responseAny && responseAny.error)
268
+ throw new Error(JSON.stringify(responseAny.error))
269
+
270
+ logger.debug('API response:')
271
+ logger.debug(JSON.stringify(response, null, 2))
272
+
273
+ // Output the complete response data for debugging
274
+ logger.debug('Complete response data:')
275
+ logger.debug(JSON.stringify(response.data, null, 2))
276
+
277
+ return response.data
278
+ }
279
+ } catch (requestError) {
280
+ logger.debug(
281
+ `Request error: ${
282
+ requestError instanceof Error
283
+ ? requestError.message
284
+ : String(requestError)
285
+ }`
286
+ )
287
+ throw requestError
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Handle the case when no API key is available
293
+ */
294
+ private handleNoApiKey(): never {
295
+ // We've exhausted all options for getting an API key
296
+ logger.warn('No API key available. You need to either:')
297
+ logger.warn(
298
+ '1. Create an API key with: berget api-keys create --name "My Key"'
299
+ )
300
+ logger.warn(
301
+ '2. Set a default API key with: berget api-keys set-default <id>'
302
+ )
303
+ logger.warn('3. Provide an API key with the --api-key option')
304
+ logger.warn('4. Set the BERGET_API_KEY environment variable')
305
+ logger.warn('\nExample:')
306
+ logger.warn(' export BERGET_API_KEY=your_api_key_here')
307
+ logger.warn(' # or for a single command:')
308
+ logger.warn(
309
+ ' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it'
310
+ )
311
+ throw new Error(
312
+ 'No API key available. Please provide an API key or set a default API key.'
313
+ )
314
+ }
315
+
316
+ /**
317
+ * Handle streaming response from the API
318
+ * @param options Request options
319
+ * @param headers Request headers
320
+ * @returns A promise that resolves when the stream is complete
321
+ */
322
+ private async handleStreamingResponse(
323
+ options: any,
324
+ headers: Record<string, string>
325
+ ): Promise<any> {
326
+ logger.debug('Handling streaming response')
327
+
328
+ // Create URL with query parameters
329
+ const url = new URL(`${API_BASE_URL}/v1/chat/completions`)
330
+
331
+ // Debug the headers and options
332
+ logger.debug('Streaming headers:')
333
+ logger.debug(JSON.stringify(headers, null, 2))
334
+
335
+ logger.debug('Streaming options:')
336
+ logger.debug(
337
+ JSON.stringify(
338
+ {
339
+ ...options,
340
+ onChunk: options.onChunk ? 'function present' : 'no function',
341
+ },
342
+ null,
343
+ 2
344
+ )
345
+ )
346
+
347
+ try {
348
+ // Make fetch request directly to handle streaming
349
+ const response = await fetch(url.toString(), {
350
+ method: 'POST',
351
+ headers: {
352
+ 'Content-Type': 'application/json',
353
+ Accept: 'text/event-stream',
354
+ ...headers,
355
+ },
356
+ body: JSON.stringify(options),
357
+ })
358
+
359
+ if (!response.ok) {
360
+ const errorText = await response.text()
361
+ logger.error(
362
+ `Stream request failed: ${response.status} ${response.statusText}`
363
+ )
364
+ logger.debug(`Error response: ${errorText}`)
365
+ throw new Error(
366
+ `Stream request failed: ${response.status} ${response.statusText}`
367
+ )
368
+ }
369
+
370
+ if (!response.body) {
371
+ throw new Error('No response body received')
372
+ }
373
+
374
+ // Process the stream
375
+ const reader = response.body.getReader()
376
+ const decoder = new TextDecoder()
377
+ let fullContent = ''
378
+ let fullResponse: any = null
379
+
380
+ while (true) {
381
+ const { done, value } = await reader.read()
382
+ if (done) break
383
+
384
+ const chunk = decoder.decode(value, { stream: true })
385
+ logger.debug(`Received chunk: ${chunk.length} bytes`)
386
+
387
+ // Process the chunk - it may contain multiple SSE events
388
+ const lines = chunk.split('\n')
389
+ for (const line of lines) {
390
+ if (line.startsWith('data:')) {
391
+ const jsonData = line.slice(5).trim()
392
+
393
+ // Skip empty data or [DONE] marker
394
+ if (jsonData === '' || jsonData === '[DONE]') continue
395
+
396
+ try {
397
+ const parsedData = JSON.parse(jsonData)
398
+
399
+ // Call the onChunk callback with the parsed data
400
+ if (options.onChunk) {
401
+ options.onChunk(parsedData)
402
+ }
403
+
404
+ // Keep track of the full response
405
+ if (!fullResponse) {
406
+ fullResponse = parsedData
407
+ } else if (
408
+ parsedData.choices &&
409
+ parsedData.choices[0] &&
410
+ parsedData.choices[0].delta
411
+ ) {
412
+ // Accumulate content for the full response
413
+ if (parsedData.choices[0].delta.content) {
414
+ fullContent += parsedData.choices[0].delta.content
415
+ }
416
+ }
417
+ } catch (e) {
418
+ logger.error(`Error parsing chunk: ${e}`)
419
+ logger.debug(`Problematic chunk: ${jsonData}`)
420
+ }
421
+ }
422
+ }
423
+ }
424
+
425
+ // Construct the final response object similar to non-streaming response
426
+ if (fullResponse) {
427
+ if (fullContent) {
428
+ fullResponse.choices[0].message = {
429
+ role: 'assistant',
430
+ content: fullContent,
431
+ }
432
+ }
433
+ return fullResponse
434
+ }
435
+
436
+ return {
437
+ choices: [{ message: { role: 'assistant', content: fullContent } }],
438
+ }
439
+ } catch (error) {
440
+ logger.error(
441
+ `Streaming error: ${
442
+ error instanceof Error ? error.message : String(error)
443
+ }`
444
+ )
445
+ throw error
446
+ }
447
+ }
448
+
248
449
  /**
249
450
  * List available models
250
451
  * Command: berget chat list
@@ -252,14 +453,14 @@ export class ChatService {
252
453
  public async listModels(apiKey?: string): Promise<any> {
253
454
  try {
254
455
  // Check for environment variable first, then fallback to provided API key
255
- const envApiKey = process.env.BERGET_API_KEY;
256
- const effectiveApiKey = envApiKey || apiKey;
257
-
456
+ const envApiKey = process.env.BERGET_API_KEY
457
+ const effectiveApiKey = envApiKey || apiKey
458
+
258
459
  if (effectiveApiKey) {
259
460
  const headers = {
260
- 'Authorization': `Bearer ${effectiveApiKey}`
461
+ Authorization: effectiveApiKey,
261
462
  }
262
-
463
+
263
464
  const { data, error } = await this.client.GET('/v1/models', { headers })
264
465
  if (error) throw new Error(JSON.stringify(error))
265
466
  return data
@@ -270,26 +471,27 @@ export class ChatService {
270
471
  }
271
472
  } catch (error) {
272
473
  // Improved error handling
273
- let errorMessage = 'Failed to list models';
274
-
474
+ let errorMessage = 'Failed to list models'
475
+
275
476
  if (error instanceof Error) {
276
477
  try {
277
478
  // Try to parse the error message as JSON
278
- const parsedError = JSON.parse(error.message);
479
+ const parsedError = JSON.parse(error.message)
279
480
  if (parsedError.error) {
280
- errorMessage = `Models error: ${typeof parsedError.error === 'string' ?
281
- parsedError.error :
282
- (parsedError.error.message || JSON.stringify(parsedError.error))}`;
481
+ errorMessage = `Models error: ${
482
+ typeof parsedError.error === 'string'
483
+ ? parsedError.error
484
+ : parsedError.error.message || JSON.stringify(parsedError.error)
485
+ }`
283
486
  }
284
487
  } catch (e) {
285
488
  // If parsing fails, use the original error message
286
- errorMessage = `Models error: ${error.message}`;
489
+ errorMessage = `Models error: ${error.message}`
287
490
  }
288
491
  }
289
-
290
- console.error(chalk.red(errorMessage));
291
- throw new Error(errorMessage);
492
+
493
+ logger.error(errorMessage)
494
+ throw new Error(errorMessage)
292
495
  }
293
496
  }
294
-
295
497
  }