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.
package/-27b-it ADDED
File without changes
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "berget",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "berget": "dist/index.js"
@@ -19,6 +19,8 @@
19
19
  "license": "MIT",
20
20
  "description": "This is a cli command for interacting with the AI infrastructure provider Berget",
21
21
  "devDependencies": {
22
+ "@types/marked": "^5.0.2",
23
+ "@types/marked-terminal": "^6.1.1",
22
24
  "@types/node": "^20.11.20",
23
25
  "tsx": "^4.19.3",
24
26
  "typescript": "^5.3.3"
@@ -27,6 +29,8 @@
27
29
  "chalk": "^4.1.2",
28
30
  "commander": "^12.0.0",
29
31
  "fs-extra": "^11.3.0",
32
+ "marked": "^9.1.6",
33
+ "marked-terminal": "^6.2.0",
30
34
  "open": "^9.1.0",
31
35
  "openapi-fetch": "^0.9.1",
32
36
  "openapi-typescript": "^6.7.4",
@@ -12,21 +12,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.createAuthenticatedClient = exports.clearAuthToken = exports.saveAuthToken = exports.getAuthToken = exports.apiClient = void 0;
15
+ exports.createAuthenticatedClient = exports.clearAuthToken = exports.saveAuthToken = exports.getAuthToken = exports.apiClient = exports.API_BASE_URL = void 0;
16
16
  const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
17
17
  const chalk_1 = __importDefault(require("chalk"));
18
18
  const token_manager_1 = require("./utils/token-manager");
19
+ const logger_1 = require("./utils/logger");
19
20
  // API Base URL
20
21
  // Use --local flag to test against local API
21
22
  const isLocalMode = process.argv.includes('--local');
22
- const API_BASE_URL = process.env.BERGET_API_URL ||
23
+ exports.API_BASE_URL = process.env.BERGET_API_URL ||
23
24
  (isLocalMode ? 'http://localhost:3000' : 'https://api.berget.ai');
24
- if (isLocalMode && !process.env.BERGET_API_URL && process.argv.includes('--debug')) {
25
- console.log(chalk_1.default.yellow('Using local API endpoint: http://localhost:3000'));
25
+ if (isLocalMode && !process.env.BERGET_API_URL) {
26
+ logger_1.logger.debug('Using local API endpoint: http://localhost:3000');
26
27
  }
27
28
  // Create a typed client for the Berget API
28
29
  exports.apiClient = (0, openapi_fetch_1.default)({
29
- baseUrl: API_BASE_URL,
30
+ baseUrl: exports.API_BASE_URL,
30
31
  headers: {
31
32
  'Content-Type': 'application/json',
32
33
  Accept: 'application/json',
@@ -51,12 +52,12 @@ exports.clearAuthToken = clearAuthToken;
51
52
  // Create an authenticated client with refresh token support
52
53
  const createAuthenticatedClient = () => {
53
54
  const tokenManager = token_manager_1.TokenManager.getInstance();
54
- if (!tokenManager.getAccessToken() && process.argv.includes('--debug')) {
55
- console.warn(chalk_1.default.yellow('No authentication token found. Please run `berget auth login` first.'));
55
+ if (!tokenManager.getAccessToken()) {
56
+ logger_1.logger.debug('No authentication token found. Please run `berget auth login` first.');
56
57
  }
57
58
  // Create the base client
58
59
  const client = (0, openapi_fetch_1.default)({
59
- baseUrl: API_BASE_URL,
60
+ baseUrl: exports.API_BASE_URL,
60
61
  headers: tokenManager.getAccessToken()
61
62
  ? {
62
63
  Authorization: `Bearer ${tokenManager.getAccessToken()}`,
@@ -75,13 +76,14 @@ const createAuthenticatedClient = () => {
75
76
  if (typeof target[prop] === 'function' &&
76
77
  ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(String(prop))) {
77
78
  return (...args) => __awaiter(this, void 0, void 0, function* () {
78
- var _a, _b;
79
+ var _a, _b, _c, _d;
79
80
  // Check if token is expired before making the request
80
81
  if (tokenManager.isTokenExpired() && tokenManager.getRefreshToken()) {
81
82
  yield refreshAccessToken(tokenManager);
82
83
  }
83
84
  // Update the Authorization header with the current token
84
- if (tokenManager.getAccessToken()) {
85
+ if (!((_b = (_a = args[1]) === null || _a === void 0 ? void 0 : _a.headers) === null || _b === void 0 ? void 0 : _b.Authorization) &&
86
+ tokenManager.getAccessToken()) {
85
87
  if (!args[1])
86
88
  args[1] = {};
87
89
  if (!args[1].headers)
@@ -94,11 +96,9 @@ const createAuthenticatedClient = () => {
94
96
  result = yield target[prop](...args);
95
97
  }
96
98
  catch (requestError) {
97
- if (process.argv.includes('--debug')) {
98
- console.log(chalk_1.default.red(`DEBUG: Request error: ${requestError instanceof Error
99
- ? requestError.message
100
- : String(requestError)}`));
101
- }
99
+ logger_1.logger.debug(`Request error: ${requestError instanceof Error
100
+ ? requestError.message
101
+ : String(requestError)}`);
102
102
  return {
103
103
  error: {
104
104
  message: `Request failed: ${requestError instanceof Error
@@ -113,7 +113,8 @@ const createAuthenticatedClient = () => {
113
113
  let isAuthError = false;
114
114
  try {
115
115
  // Standard 401 Unauthorized
116
- if (typeof result.error === 'object' && result.error.status === 401) {
116
+ if (typeof result.error === 'object' &&
117
+ result.error.status === 401) {
117
118
  isAuthError = true;
118
119
  }
119
120
  // OAuth specific errors
@@ -121,8 +122,8 @@ const createAuthenticatedClient = () => {
121
122
  (result.error.error.code === 'invalid_token' ||
122
123
  result.error.error.code === 'token_expired' ||
123
124
  result.error.error.message === 'Invalid API key' ||
124
- ((_a = result.error.error.message) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes('token')) ||
125
- ((_b = result.error.error.message) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('unauthorized')))) {
125
+ ((_c = result.error.error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('token')) ||
126
+ ((_d = result.error.error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('unauthorized')))) {
126
127
  isAuthError = true;
127
128
  }
128
129
  // Message-based detection as fallback
@@ -143,15 +144,11 @@ const createAuthenticatedClient = () => {
143
144
  }
144
145
  }
145
146
  if (isAuthError && tokenManager.getRefreshToken()) {
146
- if (process.argv.includes('--debug')) {
147
- console.log(chalk_1.default.yellow('DEBUG: Auth error detected, attempting token refresh'));
148
- console.log(chalk_1.default.yellow(`DEBUG: Error details: ${JSON.stringify(result.error, null, 2)}`));
149
- }
147
+ logger_1.logger.debug('Auth error detected, attempting token refresh');
148
+ logger_1.logger.debug(`Error details: ${JSON.stringify(result.error, null, 2)}`);
150
149
  const refreshed = yield refreshAccessToken(tokenManager);
151
150
  if (refreshed) {
152
- if (process.argv.includes('--debug')) {
153
- console.log(chalk_1.default.green('DEBUG: Token refreshed successfully, retrying request'));
154
- }
151
+ logger_1.logger.debug('Token refreshed successfully, retrying request');
155
152
  // Update the Authorization header with the new token
156
153
  if (!args[1])
157
154
  args[1] = {};
@@ -162,12 +159,11 @@ const createAuthenticatedClient = () => {
162
159
  return yield target[prop](...args);
163
160
  }
164
161
  else {
165
- if (process.argv.includes('--debug')) {
166
- console.log(chalk_1.default.red('DEBUG: Token refresh failed'));
167
- }
162
+ logger_1.logger.debug('Token refresh failed');
168
163
  // Add a more helpful error message for users
169
164
  if (typeof result.error === 'object') {
170
- result.error.userMessage = 'Your session has expired. Please run `berget auth login` to log in again.';
165
+ result.error.userMessage =
166
+ 'Your session has expired. Please run `berget auth login` to log in again.';
171
167
  }
172
168
  }
173
169
  }
@@ -188,12 +184,10 @@ function refreshAccessToken(tokenManager) {
188
184
  const refreshToken = tokenManager.getRefreshToken();
189
185
  if (!refreshToken)
190
186
  return false;
191
- if (process.argv.includes('--debug')) {
192
- console.log(chalk_1.default.yellow('DEBUG: Attempting to refresh access token'));
193
- }
187
+ logger_1.logger.debug('Attempting to refresh access token');
194
188
  // Use fetch directly since this endpoint might not be in the OpenAPI spec
195
189
  try {
196
- const response = yield fetch(`${API_BASE_URL}/v1/auth/refresh`, {
190
+ const response = yield fetch(`${exports.API_BASE_URL}/v1/auth/refresh`, {
197
191
  method: 'POST',
198
192
  headers: {
199
193
  'Content-Type': 'application/json',
@@ -203,9 +197,7 @@ function refreshAccessToken(tokenManager) {
203
197
  });
204
198
  // Handle HTTP errors
205
199
  if (!response.ok) {
206
- if (process.argv.includes('--debug')) {
207
- console.log(chalk_1.default.yellow(`DEBUG: Token refresh error: HTTP ${response.status} ${response.statusText}`));
208
- }
200
+ logger_1.logger.debug(`Token refresh error: HTTP ${response.status} ${response.statusText}`);
209
201
  // Check if the refresh token itself is expired or invalid
210
202
  if (response.status === 401 || response.status === 403) {
211
203
  console.warn(chalk_1.default.yellow('Your refresh token has expired. Please run `berget auth login` again.'));
@@ -229,21 +221,19 @@ function refreshAccessToken(tokenManager) {
229
221
  console.warn(chalk_1.default.yellow('Invalid token response. Please run `berget auth login` again.'));
230
222
  return false;
231
223
  }
232
- if (process.argv.includes('--debug')) {
233
- console.log(chalk_1.default.green('DEBUG: Token refreshed successfully'));
234
- }
224
+ logger_1.logger.debug('Token refreshed successfully');
235
225
  // Update the token
236
226
  tokenManager.updateAccessToken(data.token, data.expires_in || 3600);
237
227
  // If a new refresh token was provided, update that too
238
228
  if (data.refresh_token) {
239
229
  tokenManager.setTokens(data.token, data.refresh_token, data.expires_in || 3600);
240
- if (process.argv.includes('--debug')) {
241
- console.log(chalk_1.default.green('DEBUG: Refresh token also updated'));
242
- }
230
+ logger_1.logger.debug('Refresh token also updated');
243
231
  }
244
232
  }
245
233
  catch (fetchError) {
246
- console.warn(chalk_1.default.yellow(`Failed to refresh token: ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`));
234
+ console.warn(chalk_1.default.yellow(`Failed to refresh token: ${fetchError instanceof Error
235
+ ? fetchError.message
236
+ : String(fetchError)}`));
247
237
  return false;
248
238
  }
249
239
  return true;
@@ -21,6 +21,7 @@ const api_key_service_1 = require("../services/api-key-service");
21
21
  const auth_service_1 = require("../services/auth-service");
22
22
  const error_handler_1 = require("../utils/error-handler");
23
23
  const default_api_key_1 = require("../utils/default-api-key");
24
+ const markdown_renderer_1 = require("../utils/markdown-renderer");
24
25
  /**
25
26
  * Helper function to get user confirmation
26
27
  */
@@ -54,6 +55,7 @@ function registerChatCommands(program) {
54
55
  .option('-m, --max-tokens <tokens>', 'Maximum tokens to generate', parseInt)
55
56
  .option('-k, --api-key <key>', 'API key to use for this chat session')
56
57
  .option('--api-key-id <id>', 'ID of the API key to use from your saved keys')
58
+ .option('--stream', 'Stream the response')
57
59
  .action((options) => __awaiter(this, void 0, void 0, function* () {
58
60
  try {
59
61
  const chatService = chat_service_1.ChatService.getInstance();
@@ -65,6 +67,15 @@ function registerChatCommands(program) {
65
67
  if (envApiKey) {
66
68
  console.log(chalk_1.default.dim(`Using API key from BERGET_API_KEY environment variable`));
67
69
  apiKey = envApiKey;
70
+ // Debug the API key (first few characters only)
71
+ if (process.argv.includes('--debug')) {
72
+ console.log(chalk_1.default.yellow(`DEBUG: API key from env starts with: ${envApiKey.substring(0, 4)}...`));
73
+ }
74
+ }
75
+ // If API key is already provided via command line, use it
76
+ else if (options.apiKey) {
77
+ console.log(chalk_1.default.dim(`Using API key from command line argument`));
78
+ apiKey = options.apiKey;
68
79
  }
69
80
  // If no API key or API key ID provided and no env var, check for default API key
70
81
  else if (!apiKey && !apiKeyId) {
@@ -190,33 +201,41 @@ function registerChatCommands(program) {
190
201
  });
191
202
  try {
192
203
  // Call the API
193
- console.log(chalk_1.default.yellow('DEBUG: Preparing completion options'));
194
204
  const completionOptions = {
195
205
  model: ((_a = options.args) === null || _a === void 0 ? void 0 : _a[0]) || 'google/gemma-3-27b-it',
196
206
  messages: messages,
197
207
  temperature: options.temperature !== undefined ? options.temperature : 0.7,
198
208
  max_tokens: options.maxTokens || 4096,
209
+ stream: options.stream || false
199
210
  };
200
211
  // Only add apiKey if it actually exists
201
212
  if (apiKey) {
202
213
  completionOptions.apiKey = apiKey;
203
- console.log(chalk_1.default.yellow('DEBUG: Using API key from command options or default'));
204
214
  }
205
- else {
206
- console.log(chalk_1.default.yellow('DEBUG: No API key available in chat command'));
207
- // If we got this far with defaultApiKeyData but no apiKey, there's a problem
208
- const defaultApiKeyManager = default_api_key_1.DefaultApiKeyManager.getInstance();
209
- if (defaultApiKeyManager.getDefaultApiKeyData()) {
210
- console.log(chalk_1.default.yellow('DEBUG: Default API key data exists but key is missing'));
211
- }
215
+ // Add streaming support
216
+ if (options.stream) {
217
+ let assistantResponse = '';
218
+ console.log(chalk_1.default.blue('Assistant: '));
219
+ // For streaming, we'll collect the response and render it at the end
220
+ // since markdown needs the complete text to render properly
221
+ completionOptions.onChunk = (chunk) => {
222
+ if (chunk.choices && chunk.choices[0] && chunk.choices[0].delta && chunk.choices[0].delta.content) {
223
+ const content = chunk.choices[0].delta.content;
224
+ process.stdout.write(content);
225
+ assistantResponse += content;
226
+ }
227
+ };
228
+ yield chatService.createCompletion(completionOptions);
229
+ console.log('\n');
230
+ // Add assistant response to messages
231
+ messages.push({
232
+ role: 'assistant',
233
+ content: assistantResponse
234
+ });
235
+ // Continue the conversation
236
+ askQuestion();
237
+ return;
212
238
  }
213
- // Debug output
214
- console.log(chalk_1.default.yellow('DEBUG: Completion options:'));
215
- console.log(chalk_1.default.yellow(JSON.stringify(Object.assign(Object.assign({}, completionOptions), { apiKey: completionOptions.apiKey ? '***' : undefined, messages: completionOptions.messages.map((m) => ({
216
- role: m.role,
217
- content: m.content.length > 50 ? m.content.substring(0, 50) + '...' : m.content
218
- })) }), null, 2)));
219
- console.log(chalk_1.default.yellow('DEBUG: Calling chatService.createCompletion'));
220
239
  const response = yield chatService.createCompletion(completionOptions);
221
240
  // Debug output
222
241
  if (program.opts().debug) {
@@ -240,7 +259,14 @@ function registerChatCommands(program) {
240
259
  content: assistantMessage,
241
260
  });
242
261
  // Display the response
243
- console.log(chalk_1.default.blue('Assistant: ') + assistantMessage);
262
+ console.log(chalk_1.default.blue('Assistant: '));
263
+ // Check if the response contains markdown and render it if it does
264
+ if ((0, markdown_renderer_1.containsMarkdown)(assistantMessage)) {
265
+ console.log((0, markdown_renderer_1.renderMarkdown)(assistantMessage));
266
+ }
267
+ else {
268
+ console.log(assistantMessage);
269
+ }
244
270
  console.log(); // Empty line for better readability
245
271
  // Continue the conversation
246
272
  askQuestion();
@@ -317,11 +343,12 @@ function registerChatCommands(program) {
317
343
  }
318
344
  console.log(chalk_1.default.bold('Available Chat Models:'));
319
345
  console.log(chalk_1.default.dim('─'.repeat(70)));
320
- console.log(chalk_1.default.dim('MODEL ID'.padEnd(30)) +
321
- chalk_1.default.dim('OWNER'.padEnd(25)) +
346
+ console.log(chalk_1.default.dim('MODEL ID'.padEnd(40)) +
322
347
  chalk_1.default.dim('CAPABILITIES'));
323
348
  console.log(chalk_1.default.dim('─'.repeat(70)));
324
- models.data.forEach((model) => {
349
+ // Filter to only show active models
350
+ const activeModels = models.data.filter((model) => model.active === true);
351
+ activeModels.forEach((model) => {
325
352
  const capabilities = [];
326
353
  if (model.capabilities.vision)
327
354
  capabilities.push('vision');
@@ -329,8 +356,9 @@ function registerChatCommands(program) {
329
356
  capabilities.push('function_calling');
330
357
  if (model.capabilities.json_mode)
331
358
  capabilities.push('json_mode');
332
- console.log(model.id.padEnd(30) +
333
- model.owned_by.padEnd(25) +
359
+ // Format model ID in Huggingface compatible format (owner/model)
360
+ const modelId = `${model.owned_by.toLowerCase()}/${model.id}`.padEnd(40);
361
+ console.log(modelId +
334
362
  capabilities.join(', '));
335
363
  });
336
364
  }
@@ -44,7 +44,7 @@ function registerModelCommands(program) {
44
44
  throw new Error(JSON.stringify(error));
45
45
  response = data;
46
46
  console.log('Available Models:');
47
- console.log('ID OWNED BY CAPABILITIES');
47
+ console.log('ID OWNED BY CAPABILITIES');
48
48
  // Ensure response has the expected structure
49
49
  const modelData = response;
50
50
  if (modelData.data) {
@@ -56,7 +56,7 @@ function registerModelCommands(program) {
56
56
  capabilities.push('function_calling');
57
57
  if (model.capabilities.json_mode)
58
58
  capabilities.push('json_mode');
59
- console.log(`${model.id.padEnd(24)} ${model.owned_by.padEnd(25)} ${capabilities.join(', ')}`);
59
+ console.log(`${model.root.padEnd(50)} ${model.owned_by.padEnd(24)} ${capabilities.join(', ')}`);
60
60
  });
61
61
  }
62
62
  }