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
package/src/commands/chat.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Command } from 'commander'
|
|
|
2
2
|
import chalk from 'chalk'
|
|
3
3
|
import readline from 'readline'
|
|
4
4
|
import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure'
|
|
5
|
-
import { ChatService, ChatMessage } from '../services/chat-service'
|
|
5
|
+
import { ChatService, ChatMessage, ChatCompletionOptions } from '../services/chat-service'
|
|
6
6
|
import { ApiKeyService } from '../services/api-key-service'
|
|
7
7
|
import { AuthService } from '../services/auth-service'
|
|
8
8
|
import { handleError } from '../utils/error-handler'
|
|
@@ -36,7 +36,7 @@ export function registerChatCommands(program: Command): void {
|
|
|
36
36
|
chat
|
|
37
37
|
.command(SUBCOMMANDS.CHAT.RUN)
|
|
38
38
|
.description('Run a chat session with a specified model')
|
|
39
|
-
.argument('[model]', 'Model to use (default:
|
|
39
|
+
.argument('[model]', 'Model to use (default: google/gemma-3-27b-it)')
|
|
40
40
|
.option('-s, --system <message>', 'System message')
|
|
41
41
|
.option('-t, --temperature <temp>', 'Temperature (0-1)', parseFloat)
|
|
42
42
|
.option('-m, --max-tokens <tokens>', 'Maximum tokens to generate', parseInt)
|
|
@@ -45,6 +45,7 @@ export function registerChatCommands(program: Command): void {
|
|
|
45
45
|
'--api-key-id <id>',
|
|
46
46
|
'ID of the API key to use from your saved keys'
|
|
47
47
|
)
|
|
48
|
+
.option('--stream', 'Stream the response')
|
|
48
49
|
.action(async (options) => {
|
|
49
50
|
try {
|
|
50
51
|
const chatService = ChatService.getInstance()
|
|
@@ -52,19 +53,92 @@ export function registerChatCommands(program: Command): void {
|
|
|
52
53
|
// Check if we have an API key or need to get one
|
|
53
54
|
let apiKey = options.apiKey
|
|
54
55
|
let apiKeyId = options.apiKeyId
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
|
|
57
|
+
// Check for environment variable first
|
|
58
|
+
const envApiKey = process.env.BERGET_API_KEY;
|
|
59
|
+
if (envApiKey) {
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.dim(`Using API key from BERGET_API_KEY environment variable`)
|
|
62
|
+
)
|
|
63
|
+
apiKey = envApiKey;
|
|
64
|
+
|
|
65
|
+
// Debug the API key (first few characters only)
|
|
66
|
+
if (process.argv.includes('--debug')) {
|
|
63
67
|
console.log(
|
|
64
|
-
chalk.
|
|
68
|
+
chalk.yellow(`DEBUG: API key from env starts with: ${envApiKey.substring(0, 4)}...`)
|
|
65
69
|
)
|
|
66
70
|
}
|
|
67
71
|
}
|
|
72
|
+
// If API key is already provided via command line, use it
|
|
73
|
+
else if (options.apiKey) {
|
|
74
|
+
console.log(
|
|
75
|
+
chalk.dim(`Using API key from command line argument`)
|
|
76
|
+
)
|
|
77
|
+
apiKey = options.apiKey;
|
|
78
|
+
}
|
|
79
|
+
// If no API key or API key ID provided and no env var, check for default API key
|
|
80
|
+
else if (!apiKey && !apiKeyId) {
|
|
81
|
+
try {
|
|
82
|
+
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
83
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData()
|
|
84
|
+
|
|
85
|
+
if (defaultApiKeyData) {
|
|
86
|
+
apiKeyId = defaultApiKeyData.id
|
|
87
|
+
apiKey = defaultApiKeyData.key
|
|
88
|
+
|
|
89
|
+
if (apiKey) {
|
|
90
|
+
console.log(
|
|
91
|
+
chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)
|
|
92
|
+
)
|
|
93
|
+
} else {
|
|
94
|
+
console.log(
|
|
95
|
+
chalk.yellow(`Default API key "${defaultApiKeyData.name}" exists but the key value is missing.`)
|
|
96
|
+
)
|
|
97
|
+
console.log(
|
|
98
|
+
chalk.yellow(`Try rotating the key with: berget api-keys rotate ${defaultApiKeyData.id}`)
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
// No default API key, prompt the user to create one
|
|
103
|
+
console.log(chalk.yellow('No default API key set.'))
|
|
104
|
+
|
|
105
|
+
// Try to prompt for a default API key
|
|
106
|
+
apiKey = await defaultApiKeyManager.promptForDefaultApiKey()
|
|
107
|
+
|
|
108
|
+
if (!apiKey) {
|
|
109
|
+
console.log(
|
|
110
|
+
chalk.red(
|
|
111
|
+
'Error: An API key is required to use the chat command.'
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
console.log(chalk.yellow('You can:'))
|
|
115
|
+
console.log(
|
|
116
|
+
chalk.yellow(
|
|
117
|
+
'1. Create an API key with: berget api-keys create --name "My Key"'
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
console.log(
|
|
121
|
+
chalk.yellow(
|
|
122
|
+
'2. Set a default API key with: berget api-keys set-default <id>'
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
console.log(
|
|
126
|
+
chalk.yellow(
|
|
127
|
+
'3. Provide an API key with the --api-key option'
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (process.argv.includes('--debug')) {
|
|
135
|
+
console.log(
|
|
136
|
+
chalk.yellow('DEBUG: Error checking default API key:')
|
|
137
|
+
)
|
|
138
|
+
console.log(chalk.yellow(String(error)))
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
68
142
|
|
|
69
143
|
// If no direct API key, try to get one from API key ID
|
|
70
144
|
if (!apiKey && apiKeyId) {
|
|
@@ -106,9 +180,19 @@ export function registerChatCommands(program: Command): void {
|
|
|
106
180
|
}
|
|
107
181
|
}
|
|
108
182
|
} catch (error) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
183
|
+
// Check if this is an authentication error
|
|
184
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
185
|
+
const isAuthError = errorMessage.includes('Unauthorized') ||
|
|
186
|
+
errorMessage.includes('Authentication failed') ||
|
|
187
|
+
errorMessage.includes('AUTH_FAILED');
|
|
188
|
+
|
|
189
|
+
if (isAuthError) {
|
|
190
|
+
console.log(chalk.yellow('Authentication required. Please run `berget auth login` first.'));
|
|
191
|
+
} else {
|
|
192
|
+
console.error(chalk.red('Error fetching API key:'));
|
|
193
|
+
console.error(error);
|
|
194
|
+
}
|
|
195
|
+
console.log(chalk.yellow('Using default authentication instead.'));
|
|
112
196
|
}
|
|
113
197
|
}
|
|
114
198
|
|
|
@@ -171,14 +255,50 @@ export function registerChatCommands(program: Command): void {
|
|
|
171
255
|
|
|
172
256
|
try {
|
|
173
257
|
// Call the API
|
|
174
|
-
const
|
|
175
|
-
model: options.args?.[0] || '
|
|
258
|
+
const completionOptions: ChatCompletionOptions = {
|
|
259
|
+
model: options.args?.[0] || 'google/gemma-3-27b-it',
|
|
176
260
|
messages: messages,
|
|
177
261
|
temperature:
|
|
178
262
|
options.temperature !== undefined ? options.temperature : 0.7,
|
|
179
263
|
max_tokens: options.maxTokens || 4096,
|
|
180
|
-
|
|
181
|
-
}
|
|
264
|
+
stream: options.stream || false
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Only add apiKey if it actually exists
|
|
268
|
+
if (apiKey) {
|
|
269
|
+
completionOptions.apiKey = apiKey
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Add streaming support
|
|
273
|
+
if (options.stream) {
|
|
274
|
+
let assistantResponse = ''
|
|
275
|
+
process.stdout.write(chalk.blue('Assistant: '))
|
|
276
|
+
|
|
277
|
+
completionOptions.onChunk = (chunk: any) => {
|
|
278
|
+
if (chunk.choices && chunk.choices[0] && chunk.choices[0].delta && chunk.choices[0].delta.content) {
|
|
279
|
+
const content = chunk.choices[0].delta.content
|
|
280
|
+
process.stdout.write(content)
|
|
281
|
+
assistantResponse += content
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
await chatService.createCompletion(completionOptions)
|
|
286
|
+
console.log('\n')
|
|
287
|
+
|
|
288
|
+
// Add assistant response to messages
|
|
289
|
+
messages.push({
|
|
290
|
+
role: 'assistant',
|
|
291
|
+
content: assistantResponse
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
// Continue the conversation
|
|
295
|
+
askQuestion()
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const response = await chatService.createCompletion(
|
|
300
|
+
completionOptions
|
|
301
|
+
)
|
|
182
302
|
|
|
183
303
|
// Debug output
|
|
184
304
|
if (program.opts().debug) {
|
|
@@ -252,12 +372,12 @@ export function registerChatCommands(program: Command): void {
|
|
|
252
372
|
// If no API key or API key ID provided, check for default API key
|
|
253
373
|
if (!apiKey && !apiKeyId) {
|
|
254
374
|
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
255
|
-
const
|
|
375
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData()
|
|
256
376
|
|
|
257
|
-
if (
|
|
258
|
-
apiKeyId =
|
|
377
|
+
if (defaultApiKeyData) {
|
|
378
|
+
apiKeyId = defaultApiKeyData.id
|
|
259
379
|
console.log(
|
|
260
|
-
chalk.dim(`Using default API key: ${
|
|
380
|
+
chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)
|
|
261
381
|
)
|
|
262
382
|
}
|
|
263
383
|
}
|
|
@@ -33,10 +33,10 @@ export interface ApiKeyResponse {
|
|
|
33
33
|
export class ApiKeyService {
|
|
34
34
|
private static instance: ApiKeyService
|
|
35
35
|
private client = createAuthenticatedClient()
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
// Command group name for this service
|
|
38
38
|
public static readonly COMMAND_GROUP = COMMAND_GROUPS.API_KEYS
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
// Subcommands for this service
|
|
41
41
|
public static readonly COMMANDS = SUBCOMMANDS.API_KEYS
|
|
42
42
|
|
|
@@ -56,18 +56,7 @@ export class ApiKeyService {
|
|
|
56
56
|
public async list(): Promise<ApiKey[]> {
|
|
57
57
|
try {
|
|
58
58
|
const { data, error } = await this.client.GET('/v1/api-keys')
|
|
59
|
-
if (error)
|
|
60
|
-
// Check if this is an authentication error
|
|
61
|
-
const errorObj = typeof error === 'string' ? JSON.parse(error) : error;
|
|
62
|
-
if (errorObj.status === 401) {
|
|
63
|
-
throw new Error(JSON.stringify({
|
|
64
|
-
error: "Authentication failed. Your session may have expired.",
|
|
65
|
-
code: "AUTH_FAILED",
|
|
66
|
-
details: "Please run 'berget login' to authenticate again."
|
|
67
|
-
}))
|
|
68
|
-
}
|
|
69
|
-
throw new Error(JSON.stringify(error))
|
|
70
|
-
}
|
|
59
|
+
if (error) throw error
|
|
71
60
|
return data || []
|
|
72
61
|
} catch (error) {
|
|
73
62
|
handleError('Failed to list API keys', error)
|
|
@@ -82,7 +71,7 @@ export class ApiKeyService {
|
|
|
82
71
|
public async create(options: CreateApiKeyOptions): Promise<ApiKeyResponse> {
|
|
83
72
|
try {
|
|
84
73
|
const { data, error } = await this.client.POST('/v1/api-keys', {
|
|
85
|
-
body: options
|
|
74
|
+
body: options,
|
|
86
75
|
})
|
|
87
76
|
if (error) throw new Error(JSON.stringify(error))
|
|
88
77
|
return data!
|
|
@@ -99,7 +88,7 @@ export class ApiKeyService {
|
|
|
99
88
|
public async delete(id: string): Promise<boolean> {
|
|
100
89
|
try {
|
|
101
90
|
const { error } = await this.client.DELETE('/v1/api-keys/{id}', {
|
|
102
|
-
params: { path: { id } }
|
|
91
|
+
params: { path: { id } },
|
|
103
92
|
})
|
|
104
93
|
if (error) throw new Error(JSON.stringify(error))
|
|
105
94
|
return true
|
|
@@ -115,9 +104,12 @@ export class ApiKeyService {
|
|
|
115
104
|
*/
|
|
116
105
|
public async rotate(id: string): Promise<ApiKeyResponse> {
|
|
117
106
|
try {
|
|
118
|
-
const { data, error } = await this.client.PUT(
|
|
119
|
-
|
|
120
|
-
|
|
107
|
+
const { data, error } = await this.client.PUT(
|
|
108
|
+
'/v1/api-keys/{id}/rotate',
|
|
109
|
+
{
|
|
110
|
+
params: { path: { id } },
|
|
111
|
+
}
|
|
112
|
+
)
|
|
121
113
|
if (error) throw new Error(JSON.stringify(error))
|
|
122
114
|
return data!
|
|
123
115
|
} catch (error) {
|
|
@@ -133,7 +125,7 @@ export class ApiKeyService {
|
|
|
133
125
|
public async describe(id: string): Promise<any> {
|
|
134
126
|
try {
|
|
135
127
|
const { data, error } = await this.client.GET('/v1/api-keys/{id}/usage', {
|
|
136
|
-
params: { path: { id } }
|
|
128
|
+
params: { path: { id } },
|
|
137
129
|
})
|
|
138
130
|
if (error) throw new Error(JSON.stringify(error))
|
|
139
131
|
return data
|