berget 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/-27b-it +0 -0
- package/dist/index.js +47 -1
- package/dist/package.json +35 -0
- package/dist/src/client.js +55 -48
- package/dist/src/commands/api-keys.js +13 -7
- package/dist/src/commands/chat.js +100 -18
- package/dist/src/services/api-key-service.js +6 -16
- package/dist/src/services/chat-service.js +284 -56
- package/dist/src/utils/default-api-key.js +115 -6
- package/dist/src/utils/error-handler.js +4 -4
- package/dist/src/utils/logger.js +160 -0
- package/dist/src/utils/token-manager.js +6 -9
- package/index.ts +52 -1
- package/package.json +3 -2
- package/src/client.ts +83 -81
- package/src/commands/api-keys.ts +17 -7
- package/src/commands/chat.ts +142 -22
- package/src/services/api-key-service.ts +12 -20
- package/src/services/chat-service.ts +407 -87
- package/src/types/api.d.ts +203 -9
- package/src/types/json.d.ts +4 -0
- package/src/utils/default-api-key.ts +124 -6
- package/src/utils/error-handler.ts +4 -4
- package/src/utils/logger.ts +159 -0
- package/src/utils/token-manager.ts +6 -5
- package/tsconfig.json +1 -1
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -19,13 +42,10 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
19
42
|
}
|
|
20
43
|
return t;
|
|
21
44
|
};
|
|
22
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
-
};
|
|
25
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
46
|
exports.ChatService = void 0;
|
|
27
47
|
const client_1 = require("../client");
|
|
28
|
-
const
|
|
48
|
+
const logger_1 = require("../utils/logger");
|
|
29
49
|
/**
|
|
30
50
|
* Service for interacting with the chat API
|
|
31
51
|
* Command group: chat
|
|
@@ -47,57 +67,95 @@ class ChatService {
|
|
|
47
67
|
createCompletion(options) {
|
|
48
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
49
69
|
try {
|
|
70
|
+
logger_1.logger.debug('Starting createCompletion method');
|
|
71
|
+
// Initialize options if undefined
|
|
72
|
+
const optionsCopy = options ? Object.assign({}, options) : { messages: [] };
|
|
73
|
+
// Check if messages are defined
|
|
74
|
+
if (!optionsCopy.messages || !Array.isArray(optionsCopy.messages)) {
|
|
75
|
+
logger_1.logger.error('messages is undefined or not an array');
|
|
76
|
+
optionsCopy.messages = [];
|
|
77
|
+
}
|
|
78
|
+
// Log the options object
|
|
79
|
+
logger_1.logger.debug('Starting createCompletion with options:');
|
|
80
|
+
try {
|
|
81
|
+
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, optionsCopy), { apiKey: optionsCopy.apiKey ? '***' : undefined, messages: optionsCopy.messages
|
|
82
|
+
? `${optionsCopy.messages.length} messages`
|
|
83
|
+
: '0 messages' }), null, 2));
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
logger_1.logger.error('Failed to stringify options:', error);
|
|
87
|
+
}
|
|
50
88
|
const headers = {};
|
|
51
|
-
// Check
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
89
|
+
// Check for environment variables first - prioritize this over everything else
|
|
90
|
+
const envApiKey = process.env.BERGET_API_KEY;
|
|
91
|
+
if (envApiKey) {
|
|
92
|
+
logger_1.logger.debug('Using API key from BERGET_API_KEY environment variable');
|
|
93
|
+
optionsCopy.apiKey = envApiKey;
|
|
94
|
+
// Skip the default API key logic if we already have a key
|
|
95
|
+
return this.executeCompletion(optionsCopy, headers);
|
|
56
96
|
}
|
|
57
|
-
// If
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
if (isDebug) {
|
|
63
|
-
console.log(chalk_1.default.yellow('DEBUG: Using provided API key'));
|
|
64
|
-
console.log(chalk_1.default.yellow('DEBUG: Request options:'));
|
|
65
|
-
console.log(chalk_1.default.yellow(JSON.stringify(requestOptions, null, 2)));
|
|
66
|
-
}
|
|
67
|
-
const { data, error } = yield this.client.POST('/v1/chat/completions', {
|
|
68
|
-
body: requestOptions,
|
|
69
|
-
headers
|
|
70
|
-
});
|
|
71
|
-
if (isDebug) {
|
|
72
|
-
console.log(chalk_1.default.yellow('DEBUG: API response:'));
|
|
73
|
-
console.log(chalk_1.default.yellow(JSON.stringify({ data, error }, null, 2)));
|
|
74
|
-
// Output the complete response data for debugging
|
|
75
|
-
console.log(chalk_1.default.yellow('DEBUG: Complete response data:'));
|
|
76
|
-
console.log(chalk_1.default.yellow(JSON.stringify(data, null, 2)));
|
|
77
|
-
}
|
|
78
|
-
if (error)
|
|
79
|
-
throw new Error(JSON.stringify(error));
|
|
80
|
-
return data;
|
|
97
|
+
// If API key is already provided, use it directly
|
|
98
|
+
else if (optionsCopy.apiKey) {
|
|
99
|
+
logger_1.logger.debug('Using API key provided in options');
|
|
100
|
+
// Skip the default API key logic if we already have a key
|
|
101
|
+
return this.executeCompletion(optionsCopy, headers);
|
|
81
102
|
}
|
|
103
|
+
// Only try to get the default API key if no API key is provided and no env var is set
|
|
82
104
|
else {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
logger_1.logger.debug('No API key provided, trying to get default');
|
|
106
|
+
try {
|
|
107
|
+
// Import the DefaultApiKeyManager directly
|
|
108
|
+
logger_1.logger.debug('Importing DefaultApiKeyManager');
|
|
109
|
+
const DefaultApiKeyManager = (yield Promise.resolve().then(() => __importStar(require('../utils/default-api-key')))).DefaultApiKeyManager;
|
|
110
|
+
const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
|
|
111
|
+
logger_1.logger.debug('Got DefaultApiKeyManager instance');
|
|
112
|
+
// Try to get the default API key
|
|
113
|
+
logger_1.logger.debug('Calling promptForDefaultApiKey');
|
|
114
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
|
|
115
|
+
const apiKey = (defaultApiKeyData === null || defaultApiKeyData === void 0 ? void 0 : defaultApiKeyData.key) ||
|
|
116
|
+
(yield defaultApiKeyManager.promptForDefaultApiKey());
|
|
117
|
+
logger_1.logger.debug(`Default API key data exists: ${!!defaultApiKeyData}`);
|
|
118
|
+
logger_1.logger.debug(`promptForDefaultApiKey returned: ${apiKey ? 'a key' : 'null'}`);
|
|
119
|
+
if (apiKey) {
|
|
120
|
+
logger_1.logger.debug('Using API key from default API key manager');
|
|
121
|
+
optionsCopy.apiKey = apiKey;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
logger_1.logger.warn('No API key available. You need to either:');
|
|
125
|
+
logger_1.logger.warn('1. Create an API key with: berget api-keys create --name "My Key"');
|
|
126
|
+
logger_1.logger.warn('2. Set a default API key with: berget api-keys set-default <id>');
|
|
127
|
+
logger_1.logger.warn('3. Provide an API key with the --api-key option');
|
|
128
|
+
logger_1.logger.warn('4. Set the BERGET_API_KEY environment variable');
|
|
129
|
+
logger_1.logger.warn('\nExample:');
|
|
130
|
+
logger_1.logger.warn(' export BERGET_API_KEY=your_api_key_here');
|
|
131
|
+
logger_1.logger.warn(' # or for a single command:');
|
|
132
|
+
logger_1.logger.warn(' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it');
|
|
133
|
+
throw new Error('No API key provided and no default API key set');
|
|
134
|
+
}
|
|
135
|
+
// Set the API key in the options
|
|
136
|
+
logger_1.logger.debug('Setting API key in options');
|
|
137
|
+
// Only set the API key if it's not null
|
|
138
|
+
if (apiKey) {
|
|
139
|
+
optionsCopy.apiKey = apiKey;
|
|
140
|
+
}
|
|
86
141
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
console.log(chalk_1.default.yellow('DEBUG: Complete response data:'));
|
|
95
|
-
console.log(chalk_1.default.yellow(JSON.stringify(data, null, 2)));
|
|
142
|
+
catch (error) {
|
|
143
|
+
logger_1.logger.error('Error getting API key:');
|
|
144
|
+
if (error instanceof Error) {
|
|
145
|
+
logger_1.logger.error(error.message);
|
|
146
|
+
}
|
|
147
|
+
logger_1.logger.warn('Please create an API key with: berget api-keys create --name "My Key"');
|
|
148
|
+
throw new Error('Failed to get API key');
|
|
96
149
|
}
|
|
97
|
-
if (error)
|
|
98
|
-
throw new Error(JSON.stringify(error));
|
|
99
|
-
return data;
|
|
100
150
|
}
|
|
151
|
+
// Set default model if not provided
|
|
152
|
+
if (!optionsCopy.model) {
|
|
153
|
+
logger_1.logger.debug('No model specified, using default: google/gemma-3-27b-it');
|
|
154
|
+
optionsCopy.model = 'google/gemma-3-27b-it';
|
|
155
|
+
}
|
|
156
|
+
logger_1.logger.debug('Chat completion options:');
|
|
157
|
+
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, optionsCopy), { apiKey: optionsCopy.apiKey ? '***' : undefined }), null, 2));
|
|
158
|
+
return this.executeCompletion(optionsCopy, headers);
|
|
101
159
|
}
|
|
102
160
|
catch (error) {
|
|
103
161
|
// Improved error handling
|
|
@@ -115,11 +173,178 @@ class ChatService {
|
|
|
115
173
|
errorMessage = `Chat error: ${error.message}`;
|
|
116
174
|
}
|
|
117
175
|
}
|
|
118
|
-
|
|
176
|
+
logger_1.logger.error(errorMessage);
|
|
119
177
|
throw new Error(errorMessage);
|
|
120
178
|
}
|
|
121
179
|
});
|
|
122
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Execute the completion request with the provided options
|
|
183
|
+
* @param options The completion options
|
|
184
|
+
* @param headers Additional headers to include
|
|
185
|
+
* @returns The completion response
|
|
186
|
+
*/
|
|
187
|
+
executeCompletion(options, headers = {}) {
|
|
188
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
+
try {
|
|
190
|
+
// If an API key is provided, use it for this request
|
|
191
|
+
if (options.apiKey) {
|
|
192
|
+
// API keys should be sent directly, not with Bearer prefix
|
|
193
|
+
headers['Authorization'] = options.apiKey;
|
|
194
|
+
}
|
|
195
|
+
// Remove apiKey and onChunk from options before sending to API
|
|
196
|
+
const { apiKey, onChunk } = options, requestOptions = __rest(options, ["apiKey", "onChunk"]);
|
|
197
|
+
logger_1.logger.debug('Request options:');
|
|
198
|
+
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, requestOptions), { messages: requestOptions.messages
|
|
199
|
+
? `${requestOptions.messages.length} messages`
|
|
200
|
+
: '0 messages' }), null, 2));
|
|
201
|
+
// Handle streaming responses differently
|
|
202
|
+
if (requestOptions.stream && onChunk) {
|
|
203
|
+
return yield this.handleStreamingResponse(Object.assign(Object.assign({}, requestOptions), { onChunk }), headers);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
// Ensure model is always defined for the API call
|
|
207
|
+
const requestBody = Object.assign(Object.assign({}, requestOptions), { model: requestOptions.model || 'google/gemma-3-27b-it' });
|
|
208
|
+
// Debug the headers being sent
|
|
209
|
+
logger_1.logger.debug('Headers being sent:');
|
|
210
|
+
logger_1.logger.debug(JSON.stringify(headers, null, 2));
|
|
211
|
+
const response = yield this.client.POST('/v1/chat/completions', {
|
|
212
|
+
body: requestBody,
|
|
213
|
+
headers,
|
|
214
|
+
});
|
|
215
|
+
// Check if response has an error property
|
|
216
|
+
const responseAny = response;
|
|
217
|
+
if (responseAny && responseAny.error)
|
|
218
|
+
throw new Error(JSON.stringify(responseAny.error));
|
|
219
|
+
logger_1.logger.debug('API response:');
|
|
220
|
+
logger_1.logger.debug(JSON.stringify(response, null, 2));
|
|
221
|
+
// Output the complete response data for debugging
|
|
222
|
+
logger_1.logger.debug('Complete response data:');
|
|
223
|
+
logger_1.logger.debug(JSON.stringify(response.data, null, 2));
|
|
224
|
+
return response.data;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch (requestError) {
|
|
228
|
+
logger_1.logger.debug(`Request error: ${requestError instanceof Error
|
|
229
|
+
? requestError.message
|
|
230
|
+
: String(requestError)}`);
|
|
231
|
+
throw requestError;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Handle the case when no API key is available
|
|
237
|
+
*/
|
|
238
|
+
handleNoApiKey() {
|
|
239
|
+
// We've exhausted all options for getting an API key
|
|
240
|
+
logger_1.logger.warn('No API key available. You need to either:');
|
|
241
|
+
logger_1.logger.warn('1. Create an API key with: berget api-keys create --name "My Key"');
|
|
242
|
+
logger_1.logger.warn('2. Set a default API key with: berget api-keys set-default <id>');
|
|
243
|
+
logger_1.logger.warn('3. Provide an API key with the --api-key option');
|
|
244
|
+
logger_1.logger.warn('4. Set the BERGET_API_KEY environment variable');
|
|
245
|
+
logger_1.logger.warn('\nExample:');
|
|
246
|
+
logger_1.logger.warn(' export BERGET_API_KEY=your_api_key_here');
|
|
247
|
+
logger_1.logger.warn(' # or for a single command:');
|
|
248
|
+
logger_1.logger.warn(' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it');
|
|
249
|
+
throw new Error('No API key available. Please provide an API key or set a default API key.');
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Handle streaming response from the API
|
|
253
|
+
* @param options Request options
|
|
254
|
+
* @param headers Request headers
|
|
255
|
+
* @returns A promise that resolves when the stream is complete
|
|
256
|
+
*/
|
|
257
|
+
handleStreamingResponse(options, headers) {
|
|
258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
259
|
+
logger_1.logger.debug('Handling streaming response');
|
|
260
|
+
// Create URL with query parameters
|
|
261
|
+
const url = new URL(`${client_1.API_BASE_URL}/v1/chat/completions`);
|
|
262
|
+
// Debug the headers and options
|
|
263
|
+
logger_1.logger.debug('Streaming headers:');
|
|
264
|
+
logger_1.logger.debug(JSON.stringify(headers, null, 2));
|
|
265
|
+
logger_1.logger.debug('Streaming options:');
|
|
266
|
+
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, options), { onChunk: options.onChunk ? 'function present' : 'no function' }), null, 2));
|
|
267
|
+
try {
|
|
268
|
+
// Make fetch request directly to handle streaming
|
|
269
|
+
const response = yield fetch(url.toString(), {
|
|
270
|
+
method: 'POST',
|
|
271
|
+
headers: Object.assign({ 'Content-Type': 'application/json', Accept: 'text/event-stream' }, headers),
|
|
272
|
+
body: JSON.stringify(options),
|
|
273
|
+
});
|
|
274
|
+
if (!response.ok) {
|
|
275
|
+
const errorText = yield response.text();
|
|
276
|
+
logger_1.logger.error(`Stream request failed: ${response.status} ${response.statusText}`);
|
|
277
|
+
logger_1.logger.debug(`Error response: ${errorText}`);
|
|
278
|
+
throw new Error(`Stream request failed: ${response.status} ${response.statusText}`);
|
|
279
|
+
}
|
|
280
|
+
if (!response.body) {
|
|
281
|
+
throw new Error('No response body received');
|
|
282
|
+
}
|
|
283
|
+
// Process the stream
|
|
284
|
+
const reader = response.body.getReader();
|
|
285
|
+
const decoder = new TextDecoder();
|
|
286
|
+
let fullContent = '';
|
|
287
|
+
let fullResponse = null;
|
|
288
|
+
while (true) {
|
|
289
|
+
const { done, value } = yield reader.read();
|
|
290
|
+
if (done)
|
|
291
|
+
break;
|
|
292
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
293
|
+
logger_1.logger.debug(`Received chunk: ${chunk.length} bytes`);
|
|
294
|
+
// Process the chunk - it may contain multiple SSE events
|
|
295
|
+
const lines = chunk.split('\n');
|
|
296
|
+
for (const line of lines) {
|
|
297
|
+
if (line.startsWith('data:')) {
|
|
298
|
+
const jsonData = line.slice(5).trim();
|
|
299
|
+
// Skip empty data or [DONE] marker
|
|
300
|
+
if (jsonData === '' || jsonData === '[DONE]')
|
|
301
|
+
continue;
|
|
302
|
+
try {
|
|
303
|
+
const parsedData = JSON.parse(jsonData);
|
|
304
|
+
// Call the onChunk callback with the parsed data
|
|
305
|
+
if (options.onChunk) {
|
|
306
|
+
options.onChunk(parsedData);
|
|
307
|
+
}
|
|
308
|
+
// Keep track of the full response
|
|
309
|
+
if (!fullResponse) {
|
|
310
|
+
fullResponse = parsedData;
|
|
311
|
+
}
|
|
312
|
+
else if (parsedData.choices &&
|
|
313
|
+
parsedData.choices[0] &&
|
|
314
|
+
parsedData.choices[0].delta) {
|
|
315
|
+
// Accumulate content for the full response
|
|
316
|
+
if (parsedData.choices[0].delta.content) {
|
|
317
|
+
fullContent += parsedData.choices[0].delta.content;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (e) {
|
|
322
|
+
logger_1.logger.error(`Error parsing chunk: ${e}`);
|
|
323
|
+
logger_1.logger.debug(`Problematic chunk: ${jsonData}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Construct the final response object similar to non-streaming response
|
|
329
|
+
if (fullResponse) {
|
|
330
|
+
if (fullContent) {
|
|
331
|
+
fullResponse.choices[0].message = {
|
|
332
|
+
role: 'assistant',
|
|
333
|
+
content: fullContent,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
return fullResponse;
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
choices: [{ message: { role: 'assistant', content: fullContent } }],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
logger_1.logger.error(`Streaming error: ${error instanceof Error ? error.message : String(error)}`);
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
123
348
|
/**
|
|
124
349
|
* List available models
|
|
125
350
|
* Command: berget chat list
|
|
@@ -127,9 +352,12 @@ class ChatService {
|
|
|
127
352
|
listModels(apiKey) {
|
|
128
353
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
354
|
try {
|
|
130
|
-
|
|
355
|
+
// Check for environment variable first, then fallback to provided API key
|
|
356
|
+
const envApiKey = process.env.BERGET_API_KEY;
|
|
357
|
+
const effectiveApiKey = envApiKey || apiKey;
|
|
358
|
+
if (effectiveApiKey) {
|
|
131
359
|
const headers = {
|
|
132
|
-
|
|
360
|
+
Authorization: effectiveApiKey,
|
|
133
361
|
};
|
|
134
362
|
const { data, error } = yield this.client.GET('/v1/models', { headers });
|
|
135
363
|
if (error)
|
|
@@ -151,9 +379,9 @@ class ChatService {
|
|
|
151
379
|
// Try to parse the error message as JSON
|
|
152
380
|
const parsedError = JSON.parse(error.message);
|
|
153
381
|
if (parsedError.error) {
|
|
154
|
-
errorMessage = `Models error: ${typeof parsedError.error === 'string'
|
|
155
|
-
parsedError.error
|
|
156
|
-
|
|
382
|
+
errorMessage = `Models error: ${typeof parsedError.error === 'string'
|
|
383
|
+
? parsedError.error
|
|
384
|
+
: parsedError.error.message || JSON.stringify(parsedError.error)}`;
|
|
157
385
|
}
|
|
158
386
|
}
|
|
159
387
|
catch (e) {
|
|
@@ -161,7 +389,7 @@ class ChatService {
|
|
|
161
389
|
errorMessage = `Models error: ${error.message}`;
|
|
162
390
|
}
|
|
163
391
|
}
|
|
164
|
-
|
|
392
|
+
logger_1.logger.error(errorMessage);
|
|
165
393
|
throw new Error(errorMessage);
|
|
166
394
|
}
|
|
167
395
|
});
|
|
@@ -173,5 +401,5 @@ ChatService.COMMAND_GROUP = 'chat';
|
|
|
173
401
|
// Subcommands for this service
|
|
174
402
|
ChatService.COMMANDS = {
|
|
175
403
|
RUN: 'run',
|
|
176
|
-
LIST: 'list'
|
|
404
|
+
LIST: 'list',
|
|
177
405
|
};
|
|
@@ -22,6 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
25
34
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
36
|
};
|
|
@@ -30,7 +39,9 @@ exports.DefaultApiKeyManager = void 0;
|
|
|
30
39
|
const fs = __importStar(require("fs"));
|
|
31
40
|
const path = __importStar(require("path"));
|
|
32
41
|
const os = __importStar(require("os"));
|
|
33
|
-
const
|
|
42
|
+
const api_key_service_1 = require("../services/api-key-service");
|
|
43
|
+
const readline_1 = __importDefault(require("readline"));
|
|
44
|
+
const logger_1 = require("./logger");
|
|
34
45
|
/**
|
|
35
46
|
* Manages the default API key for chat commands
|
|
36
47
|
*/
|
|
@@ -62,7 +73,7 @@ class DefaultApiKeyManager {
|
|
|
62
73
|
}
|
|
63
74
|
}
|
|
64
75
|
catch (error) {
|
|
65
|
-
|
|
76
|
+
logger_1.logger.debug('Failed to load default API key configuration');
|
|
66
77
|
this.defaultApiKey = null;
|
|
67
78
|
}
|
|
68
79
|
}
|
|
@@ -84,20 +95,27 @@ class DefaultApiKeyManager {
|
|
|
84
95
|
}
|
|
85
96
|
}
|
|
86
97
|
catch (error) {
|
|
87
|
-
|
|
98
|
+
logger_1.logger.debug('Failed to save default API key configuration');
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
/**
|
|
91
102
|
* Set the default API key
|
|
92
103
|
*/
|
|
93
|
-
setDefaultApiKey(id, name, prefix) {
|
|
94
|
-
this.defaultApiKey = { id, name, prefix };
|
|
104
|
+
setDefaultApiKey(id, name, prefix, key) {
|
|
105
|
+
this.defaultApiKey = { id, name, prefix, key };
|
|
95
106
|
this.saveConfig();
|
|
96
107
|
}
|
|
97
108
|
/**
|
|
98
|
-
* Get the default API key
|
|
109
|
+
* Get the default API key string
|
|
99
110
|
*/
|
|
100
111
|
getDefaultApiKey() {
|
|
112
|
+
var _a;
|
|
113
|
+
return ((_a = this.defaultApiKey) === null || _a === void 0 ? void 0 : _a.key) || null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the default API key data object
|
|
117
|
+
*/
|
|
118
|
+
getDefaultApiKeyData() {
|
|
101
119
|
return this.defaultApiKey;
|
|
102
120
|
}
|
|
103
121
|
/**
|
|
@@ -107,5 +125,96 @@ class DefaultApiKeyManager {
|
|
|
107
125
|
this.defaultApiKey = null;
|
|
108
126
|
this.saveConfig();
|
|
109
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Prompts the user to select a default API key if none is set
|
|
130
|
+
* @returns The selected API key or null if none was selected
|
|
131
|
+
*/
|
|
132
|
+
promptForDefaultApiKey() {
|
|
133
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
try {
|
|
135
|
+
logger_1.logger.debug('promptForDefaultApiKey called');
|
|
136
|
+
// If we already have a default API key, return it
|
|
137
|
+
if (this.defaultApiKey) {
|
|
138
|
+
logger_1.logger.debug('Using existing default API key');
|
|
139
|
+
return this.defaultApiKey.key;
|
|
140
|
+
}
|
|
141
|
+
logger_1.logger.debug('No default API key found, getting ApiKeyService');
|
|
142
|
+
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
143
|
+
// Get all API keys
|
|
144
|
+
let apiKeys;
|
|
145
|
+
try {
|
|
146
|
+
logger_1.logger.debug('Calling apiKeyService.list()');
|
|
147
|
+
apiKeys = yield apiKeyService.list();
|
|
148
|
+
logger_1.logger.debug(`Got ${apiKeys ? apiKeys.length : 0} API keys`);
|
|
149
|
+
if (!apiKeys || apiKeys.length === 0) {
|
|
150
|
+
logger_1.logger.warn('No API keys found. Create one with:');
|
|
151
|
+
logger_1.logger.info(' berget api-keys create --name "My Key"');
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
// Check if this is an authentication error
|
|
157
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
158
|
+
const isAuthError = errorMessage.includes('Unauthorized') ||
|
|
159
|
+
errorMessage.includes('Authentication failed') ||
|
|
160
|
+
errorMessage.includes('AUTH_FAILED');
|
|
161
|
+
if (isAuthError) {
|
|
162
|
+
logger_1.logger.warn('Authentication required. Please run `berget auth login` first.');
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
logger_1.logger.error('Error fetching API keys:');
|
|
166
|
+
if (error instanceof Error) {
|
|
167
|
+
logger_1.logger.error(error.message);
|
|
168
|
+
logger_1.logger.debug(`API key list error: ${error.message}`);
|
|
169
|
+
logger_1.logger.debug(`Stack: ${error.stack}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
logger_1.logger.info('Select an API key to use as default:');
|
|
175
|
+
// Display available API keys
|
|
176
|
+
apiKeys.forEach((key, index) => {
|
|
177
|
+
logger_1.logger.log(` ${index + 1}. ${key.name} (${key.prefix}...)`);
|
|
178
|
+
});
|
|
179
|
+
// Create readline interface for user input
|
|
180
|
+
const rl = readline_1.default.createInterface({
|
|
181
|
+
input: process.stdin,
|
|
182
|
+
output: process.stdout
|
|
183
|
+
});
|
|
184
|
+
// Prompt for selection
|
|
185
|
+
const selection = yield new Promise((resolve) => {
|
|
186
|
+
rl.question('Enter number (or press Enter to cancel): ', (answer) => {
|
|
187
|
+
rl.close();
|
|
188
|
+
const num = parseInt(answer.trim(), 10);
|
|
189
|
+
if (isNaN(num) || num < 1 || num > apiKeys.length) {
|
|
190
|
+
resolve(-1); // Invalid selection
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
resolve(num - 1); // Convert to zero-based index
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
if (selection === -1) {
|
|
198
|
+
logger_1.logger.warn('No API key selected');
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
const selectedKey = apiKeys[selection];
|
|
202
|
+
// Create a new API key with the selected name
|
|
203
|
+
const newKey = yield apiKeyService.create({
|
|
204
|
+
name: `CLI Default (copy of ${selectedKey.name})`,
|
|
205
|
+
description: 'Created automatically by the Berget CLI for default use'
|
|
206
|
+
});
|
|
207
|
+
// Save the new key as default
|
|
208
|
+
this.setDefaultApiKey(newKey.id.toString(), newKey.name, newKey.key.substring(0, 8), // Use first 8 chars as prefix
|
|
209
|
+
newKey.key);
|
|
210
|
+
logger_1.logger.success(`✓ Default API key set to: ${newKey.name}`);
|
|
211
|
+
return newKey.key;
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
logger_1.logger.error('Failed to set default API key:', error);
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
110
219
|
}
|
|
111
220
|
exports.DefaultApiKeyManager = DefaultApiKeyManager;
|
|
@@ -35,11 +35,11 @@ function handleError(message, error) {
|
|
|
35
35
|
console.error(chalk_1.default.dim(`Details: ${error.message}`));
|
|
36
36
|
}
|
|
37
37
|
// Check for authentication errors
|
|
38
|
-
if ((typeof error === 'string' && error.includes('Unauthorized')) ||
|
|
39
|
-
(error && error.message && error.message.includes('Unauthorized')) ||
|
|
40
|
-
(error && error.code && error.code === 401)) {
|
|
38
|
+
if ((typeof error === 'string' && (error.includes('Unauthorized') || error.includes('Authentication failed'))) ||
|
|
39
|
+
(error && error.message && (error.message.includes('Unauthorized') || error.message.includes('Authentication failed'))) ||
|
|
40
|
+
(error && error.code && (error.code === 401 || error.code === 'AUTH_FAILED'))) {
|
|
41
41
|
console.error(chalk_1.default.yellow('\nYou need to be logged in to use this command.'));
|
|
42
|
-
console.error(chalk_1.default.yellow('Run `berget login` to authenticate.'));
|
|
42
|
+
console.error(chalk_1.default.yellow('Run `berget auth login` to authenticate.'));
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
exports.handleError = handleError;
|