berget 2.2.6 → 2.2.8
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/.github/workflows/publish.yml +2 -2
- package/.github/workflows/test.yml +10 -4
- package/.husky/pre-commit +1 -0
- package/.prettierignore +15 -0
- package/.prettierrc +7 -3
- package/CONTRIBUTING.md +38 -0
- package/README.md +2 -148
- package/dist/index.js +10 -11
- package/dist/package.json +30 -2
- package/dist/src/agents/app.js +28 -0
- package/dist/src/agents/backend.js +25 -0
- package/dist/src/agents/devops.js +34 -0
- package/dist/src/agents/frontend.js +25 -0
- package/dist/src/agents/fullstack.js +25 -0
- package/dist/src/agents/index.js +61 -0
- package/dist/src/agents/quality.js +70 -0
- package/dist/src/agents/security.js +26 -0
- package/dist/src/agents/types.js +2 -0
- package/dist/src/client.js +97 -117
- package/dist/src/commands/api-keys.js +75 -90
- package/dist/src/commands/auth.js +7 -16
- package/dist/src/commands/autocomplete.js +1 -1
- package/dist/src/commands/billing.js +6 -17
- package/dist/src/commands/chat.js +68 -101
- package/dist/src/commands/clusters.js +9 -18
- package/dist/src/commands/code/__tests__/auth-sync.test.js +351 -0
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +13 -0
- package/dist/src/commands/code/__tests__/fake-auth-service.js +47 -0
- package/dist/src/commands/code/__tests__/fake-command-runner.js +21 -34
- package/dist/src/commands/code/__tests__/fake-file-store.js +20 -33
- package/dist/src/commands/code/__tests__/fake-prompter.js +83 -57
- package/dist/src/commands/code/__tests__/setup-flow.test.js +359 -92
- package/dist/src/commands/code/adapters/clack-prompter.js +15 -22
- package/dist/src/commands/code/adapters/fs-file-store.js +26 -40
- package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -37
- package/dist/src/commands/code/auth-sync.js +270 -0
- package/dist/src/commands/code/errors.js +12 -9
- package/dist/src/commands/code/ports/auth-services.js +2 -0
- package/dist/src/commands/code/setup.js +387 -281
- package/dist/src/commands/code.js +205 -332
- package/dist/src/commands/index.js +5 -5
- package/dist/src/commands/models.js +6 -17
- package/dist/src/commands/users.js +5 -16
- package/dist/src/constants/command-structure.js +104 -104
- package/dist/src/services/api-key-service.js +132 -157
- package/dist/src/services/auth-service.js +89 -342
- package/dist/src/services/browser-auth.js +268 -0
- package/dist/src/services/chat-service.js +371 -401
- package/dist/src/services/cluster-service.js +47 -62
- package/dist/src/services/collaborator-service.js +10 -25
- package/dist/src/services/flux-service.js +14 -29
- package/dist/src/services/helm-service.js +10 -25
- package/dist/src/services/kubectl-service.js +16 -33
- package/dist/src/utils/config-checker.js +3 -3
- package/dist/src/utils/config-loader.js +95 -95
- package/dist/src/utils/default-api-key.js +124 -134
- package/dist/src/utils/env-manager.js +55 -66
- package/dist/src/utils/error-handler.js +20 -21
- package/dist/src/utils/logger.js +72 -65
- package/dist/src/utils/markdown-renderer.js +27 -27
- package/dist/src/utils/opencode-validator.js +63 -68
- package/dist/src/utils/token-manager.js +74 -45
- package/dist/tests/commands/chat.test.js +16 -25
- package/dist/tests/commands/code.test.js +95 -104
- package/dist/tests/utils/config-loader.test.js +48 -48
- package/dist/tests/utils/env-manager.test.js +43 -52
- package/dist/tests/utils/opencode-validator.test.js +22 -21
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +67 -0
- package/index.ts +35 -42
- package/package.json +30 -2
- package/src/agents/app.ts +27 -0
- package/src/agents/backend.ts +24 -0
- package/src/agents/devops.ts +33 -0
- package/src/agents/frontend.ts +24 -0
- package/src/agents/fullstack.ts +24 -0
- package/src/agents/index.ts +73 -0
- package/src/agents/quality.ts +69 -0
- package/src/agents/security.ts +26 -0
- package/src/agents/types.ts +17 -0
- package/src/client.ts +118 -152
- package/src/commands/api-keys.ts +241 -333
- package/src/commands/auth.ts +22 -27
- package/src/commands/autocomplete.ts +9 -9
- package/src/commands/billing.ts +20 -24
- package/src/commands/chat.ts +248 -338
- package/src/commands/clusters.ts +27 -26
- package/src/commands/code/__tests__/auth-sync.test.ts +482 -0
- package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
- package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
- package/src/commands/code/__tests__/fake-command-runner.ts +45 -42
- package/src/commands/code/__tests__/fake-file-store.ts +32 -23
- package/src/commands/code/__tests__/fake-prompter.ts +116 -77
- package/src/commands/code/__tests__/setup-flow.test.ts +624 -268
- package/src/commands/code/adapters/clack-prompter.ts +53 -39
- package/src/commands/code/adapters/fs-file-store.ts +32 -27
- package/src/commands/code/adapters/spawn-command-runner.ts +38 -29
- package/src/commands/code/auth-sync.ts +329 -0
- package/src/commands/code/errors.ts +18 -18
- package/src/commands/code/ports/auth-services.ts +14 -0
- package/src/commands/code/ports/command-runner.ts +8 -4
- package/src/commands/code/ports/file-store.ts +5 -4
- package/src/commands/code/ports/prompter.ts +24 -18
- package/src/commands/code/setup.ts +570 -340
- package/src/commands/code.ts +338 -539
- package/src/commands/index.ts +20 -19
- package/src/commands/models.ts +28 -32
- package/src/commands/users.ts +15 -21
- package/src/constants/command-structure.ts +134 -157
- package/src/services/api-key-service.ts +105 -122
- package/src/services/auth-service.ts +99 -345
- package/src/services/browser-auth.ts +296 -0
- package/src/services/chat-service.ts +265 -299
- package/src/services/cluster-service.ts +42 -45
- package/src/services/collaborator-service.ts +14 -19
- package/src/services/flux-service.ts +23 -25
- package/src/services/helm-service.ts +19 -21
- package/src/services/kubectl-service.ts +17 -19
- package/src/types/api.d.ts +1905 -1907
- package/src/types/json.d.ts +2 -2
- package/src/utils/config-checker.ts +10 -10
- package/src/utils/config-loader.ts +162 -178
- package/src/utils/default-api-key.ts +114 -125
- package/src/utils/env-manager.ts +53 -57
- package/src/utils/error-handler.ts +61 -56
- package/src/utils/logger.ts +79 -73
- package/src/utils/markdown-renderer.ts +31 -31
- package/src/utils/opencode-validator.ts +85 -89
- package/src/utils/token-manager.ts +108 -87
- package/templates/agents/app.md +1 -0
- package/templates/agents/backend.md +1 -0
- package/templates/agents/devops.md +2 -0
- package/templates/agents/frontend.md +1 -0
- package/templates/agents/fullstack.md +1 -0
- package/templates/agents/quality.md +45 -40
- package/templates/agents/security.md +1 -0
- package/tests/commands/chat.test.ts +53 -62
- package/tests/commands/code.test.ts +265 -310
- package/tests/utils/config-loader.test.ts +189 -188
- package/tests/utils/env-manager.test.ts +110 -113
- package/tests/utils/opencode-validator.test.ts +52 -56
- package/tsconfig.json +4 -3
- package/vitest.config.ts +3 -3
- package/AGENTS.md +0 -374
- package/TODO.md +0 -19
package/src/commands/chat.ts
CHANGED
|
@@ -1,42 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import readline from 'readline'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from '../
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { handleError } from '../utils/error-handler'
|
|
13
|
-
import { DefaultApiKeyManager } from '../utils/default-api-key'
|
|
14
|
-
import { renderMarkdown, containsMarkdown } from '../utils/markdown-renderer'
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Helper function to get user confirmation
|
|
18
|
-
*/
|
|
19
|
-
async function confirm(question: string): Promise<boolean> {
|
|
20
|
-
const rl = readline.createInterface({
|
|
21
|
-
input: process.stdin,
|
|
22
|
-
output: process.stdout,
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
return new Promise<boolean>((resolve) => {
|
|
26
|
-
rl.question(question, (answer) => {
|
|
27
|
-
rl.close()
|
|
28
|
-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes')
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
}
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import readline from 'node:readline';
|
|
4
|
+
|
|
5
|
+
import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure';
|
|
6
|
+
import { ApiKeyService } from '../services/api-key-service';
|
|
7
|
+
import { AuthService } from '../services/auth-service';
|
|
8
|
+
import { ChatCompletionOptions, ChatMessage, ChatService } from '../services/chat-service';
|
|
9
|
+
import { DefaultApiKeyManager } from '../utils/default-api-key';
|
|
10
|
+
import { handleError } from '../utils/error-handler';
|
|
11
|
+
import { containsMarkdown, renderMarkdown } from '../utils/markdown-renderer';
|
|
32
12
|
|
|
33
13
|
/**
|
|
34
14
|
* Register chat commands
|
|
35
15
|
*/
|
|
36
16
|
export function registerChatCommands(program: Command): void {
|
|
37
|
-
const chat = program
|
|
38
|
-
.command(COMMAND_GROUPS.CHAT)
|
|
39
|
-
.description('Interact with AI chat models')
|
|
17
|
+
const chat = program.command(COMMAND_GROUPS.CHAT).description('Interact with AI chat models');
|
|
40
18
|
|
|
41
19
|
chat
|
|
42
20
|
.command(SUBCOMMANDS.CHAT.RUN)
|
|
@@ -44,115 +22,87 @@ export function registerChatCommands(program: Command): void {
|
|
|
44
22
|
.argument('[message]', 'Message to send directly (skips interactive mode)')
|
|
45
23
|
.option('-m, --model <model>', 'Model to use (default: glm-4.7)')
|
|
46
24
|
|
|
47
|
-
.option('-t, --temperature <temp>', 'Temperature (0-1)', parseFloat)
|
|
48
|
-
.option('--max-tokens <tokens>', 'Maximum tokens to generate', parseInt)
|
|
25
|
+
.option('-t, --temperature <temp>', 'Temperature (0-1)', Number.parseFloat)
|
|
26
|
+
.option('--max-tokens <tokens>', 'Maximum tokens to generate', Number.parseInt)
|
|
49
27
|
.option('-k, --api-key <key>', 'API key to use for this chat session')
|
|
50
|
-
.option(
|
|
51
|
-
|
|
52
|
-
'ID of the API key to use from your saved keys'
|
|
53
|
-
)
|
|
54
|
-
.option(
|
|
55
|
-
'--no-stream',
|
|
56
|
-
'Disable streaming (streaming is enabled by default)'
|
|
57
|
-
)
|
|
28
|
+
.option('--api-key-id <id>', 'ID of the API key to use from your saved keys')
|
|
29
|
+
.option('--no-stream', 'Disable streaming (streaming is enabled by default)')
|
|
58
30
|
.action(async (message, options) => {
|
|
59
31
|
try {
|
|
60
|
-
const chatService = ChatService.getInstance()
|
|
32
|
+
const chatService = ChatService.getInstance();
|
|
61
33
|
|
|
62
34
|
// Check if we have an API key or need to get one
|
|
63
|
-
let apiKey = options.apiKey
|
|
64
|
-
let apiKeyId = options.apiKeyId
|
|
35
|
+
let apiKey = options.apiKey;
|
|
36
|
+
let apiKeyId = options.apiKeyId;
|
|
65
37
|
|
|
66
38
|
// Check for environment variable first
|
|
67
|
-
const
|
|
68
|
-
if (
|
|
69
|
-
console.log(
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
apiKey = envApiKey
|
|
39
|
+
const environmentApiKey = process.env.BERGET_API_KEY;
|
|
40
|
+
if (environmentApiKey) {
|
|
41
|
+
console.log(chalk.dim(`Using API key from BERGET_API_KEY environment variable`));
|
|
42
|
+
apiKey = environmentApiKey;
|
|
73
43
|
|
|
74
44
|
// Debug the API key (first few characters only)
|
|
75
45
|
if (process.argv.includes('--debug')) {
|
|
76
46
|
console.log(
|
|
77
47
|
chalk.yellow(
|
|
78
|
-
`DEBUG: API key from env starts with: ${
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)}...`
|
|
82
|
-
)
|
|
83
|
-
)
|
|
48
|
+
`DEBUG: API key from env starts with: ${environmentApiKey.slice(0, 4)}...`,
|
|
49
|
+
),
|
|
50
|
+
);
|
|
84
51
|
}
|
|
85
52
|
}
|
|
86
53
|
// If API key is already provided via command line, use it
|
|
87
54
|
else if (options.apiKey) {
|
|
88
|
-
console.log(chalk.dim(`Using API key from command line argument`))
|
|
89
|
-
apiKey = options.apiKey
|
|
55
|
+
console.log(chalk.dim(`Using API key from command line argument`));
|
|
56
|
+
apiKey = options.apiKey;
|
|
90
57
|
}
|
|
91
58
|
// If no API key or API key ID provided and no env var, check for default API key
|
|
92
59
|
else if (!apiKey && !apiKeyId) {
|
|
93
60
|
try {
|
|
94
|
-
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
95
|
-
const defaultApiKeyData =
|
|
96
|
-
defaultApiKeyManager.getDefaultApiKeyData()
|
|
61
|
+
const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
|
|
62
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
|
|
97
63
|
|
|
98
64
|
if (defaultApiKeyData) {
|
|
99
|
-
apiKeyId = defaultApiKeyData.id
|
|
100
|
-
apiKey = defaultApiKeyData.key
|
|
65
|
+
apiKeyId = defaultApiKeyData.id;
|
|
66
|
+
apiKey = defaultApiKeyData.key;
|
|
101
67
|
|
|
102
68
|
if (apiKey) {
|
|
103
|
-
console.log(
|
|
104
|
-
chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)
|
|
105
|
-
)
|
|
69
|
+
console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`));
|
|
106
70
|
} else {
|
|
107
71
|
console.log(
|
|
108
72
|
chalk.yellow(
|
|
109
|
-
`Default API key "${defaultApiKeyData.name}" exists but the key value is missing
|
|
110
|
-
)
|
|
111
|
-
)
|
|
73
|
+
`Default API key "${defaultApiKeyData.name}" exists but the key value is missing.`,
|
|
74
|
+
),
|
|
75
|
+
);
|
|
112
76
|
console.log(
|
|
113
77
|
chalk.yellow(
|
|
114
|
-
`Try rotating the key with: berget api-keys rotate ${defaultApiKeyData.id}
|
|
115
|
-
)
|
|
116
|
-
)
|
|
78
|
+
`Try rotating the key with: berget api-keys rotate ${defaultApiKeyData.id}`,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
117
81
|
}
|
|
118
82
|
} else {
|
|
119
83
|
// No default API key, prompt the user to create one
|
|
120
|
-
console.log(chalk.yellow('No default API key set.'))
|
|
84
|
+
console.log(chalk.yellow('No default API key set.'));
|
|
121
85
|
|
|
122
86
|
// Try to prompt for a default API key
|
|
123
|
-
apiKey = await defaultApiKeyManager.promptForDefaultApiKey()
|
|
87
|
+
apiKey = await defaultApiKeyManager.promptForDefaultApiKey();
|
|
124
88
|
|
|
125
89
|
if (!apiKey) {
|
|
90
|
+
console.log(chalk.red('Error: An API key is required to use the chat command.'));
|
|
91
|
+
console.log(chalk.yellow('You can:'));
|
|
126
92
|
console.log(
|
|
127
|
-
chalk.
|
|
128
|
-
|
|
129
|
-
)
|
|
130
|
-
)
|
|
131
|
-
console.log(chalk.yellow('You can:'))
|
|
132
|
-
console.log(
|
|
133
|
-
chalk.yellow(
|
|
134
|
-
'1. Create an API key with: berget api-keys create --name "My Key"'
|
|
135
|
-
)
|
|
136
|
-
)
|
|
137
|
-
console.log(
|
|
138
|
-
chalk.yellow(
|
|
139
|
-
'2. Set a default API key with: berget api-keys set-default <id>'
|
|
140
|
-
)
|
|
141
|
-
)
|
|
93
|
+
chalk.yellow('1. Create an API key with: berget api-keys create --name "My Key"'),
|
|
94
|
+
);
|
|
142
95
|
console.log(
|
|
143
|
-
chalk.yellow(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return
|
|
96
|
+
chalk.yellow('2. Set a default API key with: berget api-keys set-default <id>'),
|
|
97
|
+
);
|
|
98
|
+
console.log(chalk.yellow('3. Provide an API key with the --api-key option'));
|
|
99
|
+
return;
|
|
148
100
|
}
|
|
149
101
|
}
|
|
150
102
|
} catch (error) {
|
|
151
103
|
if (process.argv.includes('--debug')) {
|
|
152
|
-
console.log(
|
|
153
|
-
|
|
154
|
-
)
|
|
155
|
-
console.log(chalk.yellow(String(error)))
|
|
104
|
+
console.log(chalk.yellow('DEBUG: Error checking default API key:'));
|
|
105
|
+
console.log(chalk.yellow(String(error)));
|
|
156
106
|
}
|
|
157
107
|
}
|
|
158
108
|
}
|
|
@@ -160,144 +110,128 @@ export function registerChatCommands(program: Command): void {
|
|
|
160
110
|
// If no direct API key, try to get one from API key ID
|
|
161
111
|
if (!apiKey && apiKeyId) {
|
|
162
112
|
try {
|
|
163
|
-
const apiKeyService = ApiKeyService.getInstance()
|
|
164
|
-
const keys = await apiKeyService.list()
|
|
165
|
-
const selectedKey = keys.find(
|
|
166
|
-
(key) => key.id.toString() === options.apiKeyId
|
|
167
|
-
)
|
|
113
|
+
const apiKeyService = ApiKeyService.getInstance();
|
|
114
|
+
const keys = await apiKeyService.list();
|
|
115
|
+
const selectedKey = keys.find((key) => key.id.toString() === options.apiKeyId);
|
|
168
116
|
|
|
169
|
-
if (
|
|
170
|
-
console.log(
|
|
171
|
-
chalk.yellow(
|
|
172
|
-
`API key with ID ${options.apiKeyId} not found. Using default authentication.`
|
|
173
|
-
)
|
|
174
|
-
)
|
|
175
|
-
} else {
|
|
176
|
-
console.log(chalk.dim(`Using API key: ${selectedKey.name}`))
|
|
117
|
+
if (selectedKey) {
|
|
118
|
+
console.log(chalk.dim(`Using API key: ${selectedKey.name}`));
|
|
177
119
|
|
|
178
120
|
// We need to rotate the key to get the actual key value
|
|
179
121
|
if (
|
|
180
122
|
await confirm(
|
|
181
123
|
chalk.yellow(
|
|
182
|
-
`To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue? (y/n)
|
|
183
|
-
)
|
|
124
|
+
`To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue? (y/n)`,
|
|
125
|
+
),
|
|
184
126
|
)
|
|
185
127
|
) {
|
|
186
|
-
const rotatedKey = await apiKeyService.rotate(options.apiKeyId)
|
|
187
|
-
apiKey = rotatedKey.key
|
|
188
|
-
console.log(
|
|
189
|
-
chalk.green(
|
|
190
|
-
`API key "${selectedKey.name}" rotated successfully.`
|
|
191
|
-
)
|
|
192
|
-
)
|
|
128
|
+
const rotatedKey = await apiKeyService.rotate(options.apiKeyId);
|
|
129
|
+
apiKey = rotatedKey.key;
|
|
130
|
+
console.log(chalk.green(`API key "${selectedKey.name}" rotated successfully.`));
|
|
193
131
|
} else {
|
|
194
|
-
console.log(
|
|
195
|
-
chalk.yellow('Using default authentication instead.')
|
|
196
|
-
)
|
|
132
|
+
console.log(chalk.yellow('Using default authentication instead.'));
|
|
197
133
|
}
|
|
134
|
+
} else {
|
|
135
|
+
console.log(
|
|
136
|
+
chalk.yellow(
|
|
137
|
+
`API key with ID ${options.apiKeyId} not found. Using default authentication.`,
|
|
138
|
+
),
|
|
139
|
+
);
|
|
198
140
|
}
|
|
199
141
|
} catch (error) {
|
|
200
142
|
// Check if this is an authentication error
|
|
201
|
-
const errorMessage =
|
|
202
|
-
error instanceof Error ? error.message : String(error)
|
|
143
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
203
144
|
const isAuthError =
|
|
204
145
|
errorMessage.includes('Unauthorized') ||
|
|
205
146
|
errorMessage.includes('Authentication failed') ||
|
|
206
|
-
errorMessage.includes('AUTH_FAILED')
|
|
147
|
+
errorMessage.includes('AUTH_FAILED');
|
|
207
148
|
|
|
208
149
|
if (isAuthError) {
|
|
209
150
|
console.log(
|
|
210
|
-
chalk.yellow(
|
|
211
|
-
|
|
212
|
-
)
|
|
213
|
-
)
|
|
151
|
+
chalk.yellow('Authentication required. Please run `berget auth login` first.'),
|
|
152
|
+
);
|
|
214
153
|
} else {
|
|
215
|
-
console.error(chalk.red('Error fetching API key:'))
|
|
216
|
-
console.error(error)
|
|
154
|
+
console.error(chalk.red('Error fetching API key:'));
|
|
155
|
+
console.error(error);
|
|
217
156
|
}
|
|
218
|
-
console.log(chalk.yellow('Using default authentication instead.'))
|
|
157
|
+
console.log(chalk.yellow('Using default authentication instead.'));
|
|
219
158
|
}
|
|
220
159
|
}
|
|
221
160
|
|
|
222
161
|
// Verify we have authentication before starting chat
|
|
223
162
|
if (!apiKey) {
|
|
224
163
|
try {
|
|
225
|
-
AuthService.getInstance()
|
|
226
|
-
} catch
|
|
227
|
-
console.log(chalk.red('Error: Authentication required for chat'))
|
|
228
|
-
console.log(chalk.yellow('Please either:'))
|
|
229
|
-
console.log(chalk.yellow('1. Log in with `berget auth login`'))
|
|
230
|
-
console.log(chalk.yellow('2. Provide an API key with `--api-key`'))
|
|
231
|
-
console.log(
|
|
232
|
-
chalk.yellow('3. Provide an API key ID with `--api-key-id`')
|
|
233
|
-
)
|
|
164
|
+
AuthService.getInstance();
|
|
165
|
+
} catch {
|
|
166
|
+
console.log(chalk.red('Error: Authentication required for chat'));
|
|
167
|
+
console.log(chalk.yellow('Please either:'));
|
|
168
|
+
console.log(chalk.yellow('1. Log in with `berget auth login`'));
|
|
169
|
+
console.log(chalk.yellow('2. Provide an API key with `--api-key`'));
|
|
170
|
+
console.log(chalk.yellow('3. Provide an API key ID with `--api-key-id`'));
|
|
234
171
|
console.log(
|
|
235
|
-
chalk.yellow(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
)
|
|
239
|
-
return
|
|
172
|
+
chalk.yellow('4. Set a default API key with `berget api-keys set-default <id>`'),
|
|
173
|
+
);
|
|
174
|
+
return;
|
|
240
175
|
}
|
|
241
176
|
}
|
|
242
177
|
|
|
243
178
|
// Prepare messages array
|
|
244
|
-
const messages: ChatMessage[] = []
|
|
179
|
+
const messages: ChatMessage[] = [];
|
|
245
180
|
|
|
246
181
|
// Add system message if provided
|
|
247
182
|
if (options.system) {
|
|
248
183
|
messages.push({
|
|
249
|
-
role: 'system',
|
|
250
184
|
content: options.system,
|
|
251
|
-
|
|
185
|
+
role: 'system',
|
|
186
|
+
});
|
|
252
187
|
}
|
|
253
188
|
|
|
254
189
|
// Check if input is being piped in
|
|
255
|
-
let inputMessage = message
|
|
256
|
-
let stdinContent = ''
|
|
190
|
+
let inputMessage = message;
|
|
191
|
+
let stdinContent = '';
|
|
257
192
|
|
|
258
193
|
if (!process.stdin.isTTY) {
|
|
259
194
|
// Read from stdin (piped input)
|
|
260
|
-
const chunks = []
|
|
195
|
+
const chunks = [];
|
|
261
196
|
for await (const chunk of process.stdin) {
|
|
262
|
-
chunks.push(chunk)
|
|
197
|
+
chunks.push(chunk);
|
|
263
198
|
}
|
|
264
|
-
stdinContent = Buffer.concat(chunks).toString('utf8').trim()
|
|
199
|
+
stdinContent = Buffer.concat(chunks).toString('utf8').trim();
|
|
265
200
|
}
|
|
266
201
|
|
|
267
202
|
// Combine stdin content with message if both exist
|
|
268
203
|
if (stdinContent && message) {
|
|
269
|
-
inputMessage = `${stdinContent}\n\n${message}
|
|
204
|
+
inputMessage = `${stdinContent}\n\n${message}`;
|
|
270
205
|
} else if (stdinContent && !message) {
|
|
271
|
-
inputMessage = stdinContent
|
|
206
|
+
inputMessage = stdinContent;
|
|
272
207
|
}
|
|
273
208
|
|
|
274
209
|
// If a message is provided (either as argument, from stdin, or both), send it directly and exit
|
|
275
210
|
if (inputMessage) {
|
|
276
211
|
// Add user message
|
|
277
212
|
messages.push({
|
|
278
|
-
role: 'user',
|
|
279
213
|
content: inputMessage,
|
|
280
|
-
|
|
214
|
+
role: 'user',
|
|
215
|
+
});
|
|
281
216
|
|
|
282
217
|
try {
|
|
283
218
|
// Call the API
|
|
284
219
|
const completionOptions: ChatCompletionOptions = {
|
|
285
|
-
model: options.model || 'openai/gpt-oss',
|
|
286
|
-
messages: messages,
|
|
287
|
-
temperature:
|
|
288
|
-
options.temperature !== undefined ? options.temperature : 0.7,
|
|
289
220
|
max_tokens: options.maxTokens || 4096,
|
|
221
|
+
messages: messages,
|
|
222
|
+
model: options.model || 'openai/gpt-oss',
|
|
290
223
|
stream: options.stream !== false,
|
|
291
|
-
|
|
224
|
+
temperature: options.temperature === undefined ? 0.7 : options.temperature,
|
|
225
|
+
};
|
|
292
226
|
|
|
293
227
|
// Only add apiKey if it actually exists
|
|
294
228
|
if (apiKey) {
|
|
295
|
-
completionOptions.apiKey = apiKey
|
|
229
|
+
completionOptions.apiKey = apiKey;
|
|
296
230
|
}
|
|
297
231
|
|
|
298
232
|
// Add streaming support (now default)
|
|
299
233
|
if (completionOptions.stream) {
|
|
300
|
-
let assistantResponse = ''
|
|
234
|
+
let assistantResponse = '';
|
|
301
235
|
|
|
302
236
|
// Stream the response in real-time
|
|
303
237
|
completionOptions.onChunk = (chunk: any) => {
|
|
@@ -307,36 +241,32 @@ export function registerChatCommands(program: Command): void {
|
|
|
307
241
|
chunk.choices[0].delta &&
|
|
308
242
|
chunk.choices[0].delta.content
|
|
309
243
|
) {
|
|
310
|
-
const content = chunk.choices[0].delta.content
|
|
244
|
+
const content = chunk.choices[0].delta.content;
|
|
311
245
|
try {
|
|
312
|
-
process.stdout.write(content)
|
|
246
|
+
process.stdout.write(content);
|
|
313
247
|
} catch (error: any) {
|
|
314
248
|
// Handle EPIPE errors gracefully (when pipe is closed)
|
|
315
249
|
if (error.code === 'EPIPE') {
|
|
316
250
|
// Stop streaming if the pipe is closed
|
|
317
|
-
return
|
|
251
|
+
return;
|
|
318
252
|
}
|
|
319
|
-
throw error
|
|
253
|
+
throw error;
|
|
320
254
|
}
|
|
321
|
-
assistantResponse += content
|
|
255
|
+
assistantResponse += content;
|
|
322
256
|
}
|
|
323
|
-
}
|
|
257
|
+
};
|
|
324
258
|
|
|
325
259
|
try {
|
|
326
|
-
await chatService.createCompletion(completionOptions)
|
|
260
|
+
await chatService.createCompletion(completionOptions);
|
|
327
261
|
} catch (streamError) {
|
|
328
|
-
console.error(chalk.red('\nStreaming error:'), streamError)
|
|
262
|
+
console.error(chalk.red('\nStreaming error:'), streamError);
|
|
329
263
|
|
|
330
264
|
// Fallback to non-streaming if streaming fails
|
|
331
|
-
console.log(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
completionOptions.stream = false
|
|
335
|
-
delete completionOptions.onChunk
|
|
265
|
+
console.log(chalk.yellow('Falling back to non-streaming mode...'));
|
|
266
|
+
completionOptions.stream = false;
|
|
267
|
+
delete completionOptions.onChunk;
|
|
336
268
|
|
|
337
|
-
const response = await chatService.createCompletion(
|
|
338
|
-
completionOptions
|
|
339
|
-
)
|
|
269
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
340
270
|
|
|
341
271
|
if (
|
|
342
272
|
response &&
|
|
@@ -344,17 +274,15 @@ export function registerChatCommands(program: Command): void {
|
|
|
344
274
|
response.choices[0] &&
|
|
345
275
|
response.choices[0].message
|
|
346
276
|
) {
|
|
347
|
-
assistantResponse = response.choices[0].message.content
|
|
348
|
-
console.log(assistantResponse)
|
|
277
|
+
assistantResponse = response.choices[0].message.content;
|
|
278
|
+
console.log(assistantResponse);
|
|
349
279
|
}
|
|
350
280
|
}
|
|
351
|
-
console.log() // Add newline at the end
|
|
352
|
-
return
|
|
281
|
+
console.log(); // Add newline at the end
|
|
282
|
+
return;
|
|
353
283
|
}
|
|
354
284
|
|
|
355
|
-
const response = await chatService.createCompletion(
|
|
356
|
-
completionOptions
|
|
357
|
-
)
|
|
285
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
358
286
|
|
|
359
287
|
// Check if response has the expected structure
|
|
360
288
|
if (
|
|
@@ -363,32 +291,28 @@ export function registerChatCommands(program: Command): void {
|
|
|
363
291
|
!response.choices[0] ||
|
|
364
292
|
!response.choices[0].message
|
|
365
293
|
) {
|
|
366
|
-
console.error(
|
|
367
|
-
|
|
368
|
-
)
|
|
369
|
-
console.error(
|
|
370
|
-
chalk.red('Response:', JSON.stringify(response, null, 2))
|
|
371
|
-
)
|
|
372
|
-
throw new Error('Unexpected response format from API')
|
|
294
|
+
console.error(chalk.red('Error: Unexpected response format from API'));
|
|
295
|
+
console.error(chalk.red('Response:', JSON.stringify(response, null, 2)));
|
|
296
|
+
throw new Error('Unexpected response format from API');
|
|
373
297
|
}
|
|
374
298
|
|
|
375
299
|
// Get assistant's response
|
|
376
|
-
const assistantMessage = response.choices[0].message.content
|
|
300
|
+
const assistantMessage = response.choices[0].message.content;
|
|
377
301
|
|
|
378
302
|
// Display the response
|
|
379
303
|
if (containsMarkdown(assistantMessage)) {
|
|
380
|
-
console.log(renderMarkdown(assistantMessage))
|
|
304
|
+
console.log(renderMarkdown(assistantMessage));
|
|
381
305
|
} else {
|
|
382
|
-
console.log(assistantMessage)
|
|
306
|
+
console.log(assistantMessage);
|
|
383
307
|
}
|
|
384
308
|
|
|
385
|
-
return
|
|
309
|
+
return;
|
|
386
310
|
} catch (error) {
|
|
387
|
-
console.error(chalk.red('Error: Failed to get response'))
|
|
311
|
+
console.error(chalk.red('Error: Failed to get response'));
|
|
388
312
|
if (error instanceof Error) {
|
|
389
|
-
console.error(chalk.red(error.message))
|
|
313
|
+
console.error(chalk.red(error.message));
|
|
390
314
|
}
|
|
391
|
-
process.exit(1)
|
|
315
|
+
process.exit(1);
|
|
392
316
|
}
|
|
393
317
|
}
|
|
394
318
|
|
|
@@ -396,47 +320,46 @@ export function registerChatCommands(program: Command): void {
|
|
|
396
320
|
const rl = readline.createInterface({
|
|
397
321
|
input: process.stdin,
|
|
398
322
|
output: process.stdout,
|
|
399
|
-
})
|
|
323
|
+
});
|
|
400
324
|
|
|
401
|
-
console.log(chalk.cyan('Chat with Berget AI (type "exit" to quit)'))
|
|
402
|
-
console.log(chalk.cyan('----------------------------------------'))
|
|
325
|
+
console.log(chalk.cyan('Chat with Berget AI (type "exit" to quit)'));
|
|
326
|
+
console.log(chalk.cyan('----------------------------------------'));
|
|
403
327
|
|
|
404
328
|
// Start the conversation loop
|
|
405
329
|
const askQuestion = () => {
|
|
406
330
|
rl.question(chalk.green('You: '), async (input) => {
|
|
407
331
|
// Check if user wants to exit
|
|
408
332
|
if (input.toLowerCase() === 'exit') {
|
|
409
|
-
console.log(chalk.cyan('Goodbye!'))
|
|
410
|
-
rl.close()
|
|
411
|
-
return
|
|
333
|
+
console.log(chalk.cyan('Goodbye!'));
|
|
334
|
+
rl.close();
|
|
335
|
+
return;
|
|
412
336
|
}
|
|
413
337
|
|
|
414
338
|
// Add user message
|
|
415
339
|
messages.push({
|
|
416
|
-
role: 'user',
|
|
417
340
|
content: input,
|
|
418
|
-
|
|
341
|
+
role: 'user',
|
|
342
|
+
});
|
|
419
343
|
|
|
420
344
|
try {
|
|
421
345
|
// Call the API
|
|
422
346
|
const completionOptions: ChatCompletionOptions = {
|
|
423
|
-
model: options.model || 'openai/gpt-oss',
|
|
424
|
-
messages: messages,
|
|
425
|
-
temperature:
|
|
426
|
-
options.temperature !== undefined ? options.temperature : 0.7,
|
|
427
347
|
max_tokens: options.maxTokens || 4096,
|
|
348
|
+
messages: messages,
|
|
349
|
+
model: options.model || 'openai/gpt-oss',
|
|
428
350
|
stream: options.stream !== false,
|
|
429
|
-
|
|
351
|
+
temperature: options.temperature === undefined ? 0.7 : options.temperature,
|
|
352
|
+
};
|
|
430
353
|
|
|
431
354
|
// Only add apiKey if it actually exists
|
|
432
355
|
if (apiKey) {
|
|
433
|
-
completionOptions.apiKey = apiKey
|
|
356
|
+
completionOptions.apiKey = apiKey;
|
|
434
357
|
}
|
|
435
358
|
|
|
436
359
|
// Add streaming support (now default)
|
|
437
360
|
if (completionOptions.stream) {
|
|
438
|
-
let assistantResponse = ''
|
|
439
|
-
console.log(chalk.blue('Assistant: '))
|
|
361
|
+
let assistantResponse = '';
|
|
362
|
+
console.log(chalk.blue('Assistant: '));
|
|
440
363
|
|
|
441
364
|
// Stream the response in real-time
|
|
442
365
|
completionOptions.onChunk = (chunk: any) => {
|
|
@@ -446,36 +369,32 @@ export function registerChatCommands(program: Command): void {
|
|
|
446
369
|
chunk.choices[0].delta &&
|
|
447
370
|
chunk.choices[0].delta.content
|
|
448
371
|
) {
|
|
449
|
-
const content = chunk.choices[0].delta.content
|
|
372
|
+
const content = chunk.choices[0].delta.content;
|
|
450
373
|
try {
|
|
451
|
-
process.stdout.write(content)
|
|
374
|
+
process.stdout.write(content);
|
|
452
375
|
} catch (error: any) {
|
|
453
376
|
// Handle EPIPE errors gracefully (when pipe is closed)
|
|
454
377
|
if (error.code === 'EPIPE') {
|
|
455
378
|
// Stop streaming if the pipe is closed
|
|
456
|
-
return
|
|
379
|
+
return;
|
|
457
380
|
}
|
|
458
|
-
throw error
|
|
381
|
+
throw error;
|
|
459
382
|
}
|
|
460
|
-
assistantResponse += content
|
|
383
|
+
assistantResponse += content;
|
|
461
384
|
}
|
|
462
|
-
}
|
|
385
|
+
};
|
|
463
386
|
|
|
464
387
|
try {
|
|
465
|
-
await chatService.createCompletion(completionOptions)
|
|
388
|
+
await chatService.createCompletion(completionOptions);
|
|
466
389
|
} catch (streamError) {
|
|
467
|
-
console.error(chalk.red('\nStreaming error:'), streamError)
|
|
390
|
+
console.error(chalk.red('\nStreaming error:'), streamError);
|
|
468
391
|
|
|
469
392
|
// Fallback to non-streaming if streaming fails
|
|
470
|
-
console.log(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
completionOptions.stream = false
|
|
474
|
-
delete completionOptions.onChunk
|
|
393
|
+
console.log(chalk.yellow('Falling back to non-streaming mode...'));
|
|
394
|
+
completionOptions.stream = false;
|
|
395
|
+
delete completionOptions.onChunk;
|
|
475
396
|
|
|
476
|
-
const response = await chatService.createCompletion(
|
|
477
|
-
completionOptions
|
|
478
|
-
)
|
|
397
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
479
398
|
|
|
480
399
|
if (
|
|
481
400
|
response &&
|
|
@@ -483,31 +402,29 @@ export function registerChatCommands(program: Command): void {
|
|
|
483
402
|
response.choices[0] &&
|
|
484
403
|
response.choices[0].message
|
|
485
404
|
) {
|
|
486
|
-
assistantResponse = response.choices[0].message.content
|
|
487
|
-
console.log(assistantResponse)
|
|
405
|
+
assistantResponse = response.choices[0].message.content;
|
|
406
|
+
console.log(assistantResponse);
|
|
488
407
|
}
|
|
489
408
|
}
|
|
490
|
-
console.log('\n')
|
|
409
|
+
console.log('\n');
|
|
491
410
|
|
|
492
411
|
// Add assistant response to messages
|
|
493
412
|
messages.push({
|
|
494
|
-
role: 'assistant',
|
|
495
413
|
content: assistantResponse,
|
|
496
|
-
|
|
414
|
+
role: 'assistant',
|
|
415
|
+
});
|
|
497
416
|
|
|
498
417
|
// Continue the conversation
|
|
499
|
-
askQuestion()
|
|
500
|
-
return
|
|
418
|
+
askQuestion();
|
|
419
|
+
return;
|
|
501
420
|
}
|
|
502
421
|
|
|
503
|
-
const response = await chatService.createCompletion(
|
|
504
|
-
completionOptions
|
|
505
|
-
)
|
|
422
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
506
423
|
|
|
507
424
|
// Debug output
|
|
508
425
|
if (program.opts().debug) {
|
|
509
|
-
console.log(chalk.yellow('DEBUG: Full response:'))
|
|
510
|
-
console.log(chalk.yellow(JSON.stringify(response, null, 2)))
|
|
426
|
+
console.log(chalk.yellow('DEBUG: Full response:'));
|
|
427
|
+
console.log(chalk.yellow(JSON.stringify(response, null, 2)));
|
|
511
428
|
}
|
|
512
429
|
|
|
513
430
|
// Check if response has the expected structure
|
|
@@ -517,165 +434,158 @@ export function registerChatCommands(program: Command): void {
|
|
|
517
434
|
!response.choices[0] ||
|
|
518
435
|
!response.choices[0].message
|
|
519
436
|
) {
|
|
520
|
-
console.error(
|
|
521
|
-
|
|
522
|
-
)
|
|
523
|
-
console.error(
|
|
524
|
-
chalk.red('Response:', JSON.stringify(response, null, 2))
|
|
525
|
-
)
|
|
526
|
-
throw new Error('Unexpected response format from API')
|
|
437
|
+
console.error(chalk.red('Error: Unexpected response format from API'));
|
|
438
|
+
console.error(chalk.red('Response:', JSON.stringify(response, null, 2)));
|
|
439
|
+
throw new Error('Unexpected response format from API');
|
|
527
440
|
}
|
|
528
441
|
|
|
529
442
|
// Get assistant's response
|
|
530
|
-
const assistantMessage = response.choices[0].message.content
|
|
443
|
+
const assistantMessage = response.choices[0].message.content;
|
|
531
444
|
|
|
532
445
|
// Add to messages array
|
|
533
446
|
messages.push({
|
|
534
|
-
role: 'assistant',
|
|
535
447
|
content: assistantMessage,
|
|
536
|
-
|
|
448
|
+
role: 'assistant',
|
|
449
|
+
});
|
|
537
450
|
|
|
538
451
|
// Display the response
|
|
539
|
-
console.log(chalk.blue('Assistant: '))
|
|
452
|
+
console.log(chalk.blue('Assistant: '));
|
|
540
453
|
|
|
541
454
|
// Check if the response contains markdown and render it if it does
|
|
542
455
|
if (containsMarkdown(assistantMessage)) {
|
|
543
|
-
console.log(renderMarkdown(assistantMessage))
|
|
456
|
+
console.log(renderMarkdown(assistantMessage));
|
|
544
457
|
} else {
|
|
545
|
-
console.log(assistantMessage)
|
|
458
|
+
console.log(assistantMessage);
|
|
546
459
|
}
|
|
547
460
|
|
|
548
|
-
console.log() // Empty line for better readability
|
|
461
|
+
console.log(); // Empty line for better readability
|
|
549
462
|
|
|
550
463
|
// Continue the conversation
|
|
551
|
-
askQuestion()
|
|
464
|
+
askQuestion();
|
|
552
465
|
} catch (error) {
|
|
553
|
-
console.error(chalk.red('Error: Failed to get response'))
|
|
466
|
+
console.error(chalk.red('Error: Failed to get response'));
|
|
554
467
|
if (error instanceof Error) {
|
|
555
|
-
console.error(chalk.red(error.message))
|
|
468
|
+
console.error(chalk.red(error.message));
|
|
556
469
|
}
|
|
557
470
|
// Continue despite error
|
|
558
|
-
askQuestion()
|
|
471
|
+
askQuestion();
|
|
559
472
|
}
|
|
560
|
-
})
|
|
561
|
-
}
|
|
473
|
+
});
|
|
474
|
+
};
|
|
562
475
|
|
|
563
476
|
// Start the conversation
|
|
564
|
-
askQuestion()
|
|
477
|
+
askQuestion();
|
|
565
478
|
} catch (error) {
|
|
566
|
-
handleError('Failed to create chat completion', error)
|
|
479
|
+
handleError('Failed to create chat completion', error);
|
|
567
480
|
}
|
|
568
|
-
})
|
|
481
|
+
});
|
|
569
482
|
|
|
570
483
|
chat
|
|
571
484
|
.command(SUBCOMMANDS.CHAT.LIST)
|
|
572
485
|
.description('List available chat models')
|
|
573
486
|
.option('-k, --api-key <key>', 'API key to use for this request')
|
|
574
|
-
.option(
|
|
575
|
-
'--api-key-id <id>',
|
|
576
|
-
'ID of the API key to use from your saved keys'
|
|
577
|
-
)
|
|
487
|
+
.option('--api-key-id <id>', 'ID of the API key to use from your saved keys')
|
|
578
488
|
.action(async (options) => {
|
|
579
489
|
try {
|
|
580
490
|
// If API key ID is provided, fetch the actual key
|
|
581
|
-
let apiKey = options.apiKey
|
|
582
|
-
let apiKeyId = options.apiKeyId
|
|
491
|
+
let apiKey = options.apiKey;
|
|
492
|
+
let apiKeyId = options.apiKeyId;
|
|
583
493
|
|
|
584
494
|
// If no API key or API key ID provided, check for default API key
|
|
585
495
|
if (!apiKey && !apiKeyId) {
|
|
586
|
-
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
587
|
-
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData()
|
|
496
|
+
const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
|
|
497
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
|
|
588
498
|
|
|
589
499
|
if (defaultApiKeyData) {
|
|
590
|
-
apiKeyId = defaultApiKeyData.id
|
|
591
|
-
console.log(
|
|
592
|
-
chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)
|
|
593
|
-
)
|
|
500
|
+
apiKeyId = defaultApiKeyData.id;
|
|
501
|
+
console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`));
|
|
594
502
|
}
|
|
595
503
|
}
|
|
596
504
|
|
|
597
505
|
if (apiKeyId && !apiKey) {
|
|
598
506
|
try {
|
|
599
|
-
const apiKeyService = ApiKeyService.getInstance()
|
|
600
|
-
const keys = await apiKeyService.list()
|
|
601
|
-
const selectedKey = keys.find(
|
|
602
|
-
(key) => key.id.toString() === options.apiKeyId
|
|
603
|
-
)
|
|
507
|
+
const apiKeyService = ApiKeyService.getInstance();
|
|
508
|
+
const keys = await apiKeyService.list();
|
|
509
|
+
const selectedKey = keys.find((key) => key.id.toString() === options.apiKeyId);
|
|
604
510
|
|
|
605
|
-
if (
|
|
606
|
-
console.log(
|
|
607
|
-
chalk.yellow(
|
|
608
|
-
`API key with ID ${options.apiKeyId} not found. Using default authentication.`
|
|
609
|
-
)
|
|
610
|
-
)
|
|
611
|
-
} else {
|
|
612
|
-
console.log(chalk.dim(`Using API key: ${selectedKey.name}`))
|
|
511
|
+
if (selectedKey) {
|
|
512
|
+
console.log(chalk.dim(`Using API key: ${selectedKey.name}`));
|
|
613
513
|
|
|
614
514
|
// We need to rotate the key to get the actual key value
|
|
615
515
|
if (
|
|
616
516
|
await confirm(
|
|
617
517
|
chalk.yellow(
|
|
618
|
-
`To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue? (y/n)
|
|
619
|
-
)
|
|
518
|
+
`To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue? (y/n)`,
|
|
519
|
+
),
|
|
620
520
|
)
|
|
621
521
|
) {
|
|
622
|
-
const rotatedKey = await apiKeyService.rotate(options.apiKeyId)
|
|
623
|
-
apiKey = rotatedKey.key
|
|
624
|
-
console.log(
|
|
625
|
-
chalk.green(
|
|
626
|
-
`API key "${selectedKey.name}" rotated successfully.`
|
|
627
|
-
)
|
|
628
|
-
)
|
|
522
|
+
const rotatedKey = await apiKeyService.rotate(options.apiKeyId);
|
|
523
|
+
apiKey = rotatedKey.key;
|
|
524
|
+
console.log(chalk.green(`API key "${selectedKey.name}" rotated successfully.`));
|
|
629
525
|
} else {
|
|
630
|
-
console.log(
|
|
631
|
-
chalk.yellow('Using default authentication instead.')
|
|
632
|
-
)
|
|
526
|
+
console.log(chalk.yellow('Using default authentication instead.'));
|
|
633
527
|
}
|
|
528
|
+
} else {
|
|
529
|
+
console.log(
|
|
530
|
+
chalk.yellow(
|
|
531
|
+
`API key with ID ${options.apiKeyId} not found. Using default authentication.`,
|
|
532
|
+
),
|
|
533
|
+
);
|
|
634
534
|
}
|
|
635
535
|
} catch (error) {
|
|
636
|
-
console.error(chalk.red('Error fetching API key:'))
|
|
637
|
-
console.error(error)
|
|
638
|
-
console.log(chalk.yellow('Using default authentication instead.'))
|
|
536
|
+
console.error(chalk.red('Error fetching API key:'));
|
|
537
|
+
console.error(error);
|
|
538
|
+
console.log(chalk.yellow('Using default authentication instead.'));
|
|
639
539
|
}
|
|
640
540
|
}
|
|
641
541
|
|
|
642
|
-
const chatService = ChatService.getInstance()
|
|
643
|
-
const models = await chatService.listModels(apiKey)
|
|
542
|
+
const chatService = ChatService.getInstance();
|
|
543
|
+
const models = await chatService.listModels(apiKey);
|
|
644
544
|
|
|
645
545
|
// Debug output
|
|
646
546
|
if (program.opts().debug) {
|
|
647
|
-
console.log(chalk.yellow('DEBUG: Models response:'))
|
|
648
|
-
console.log(chalk.yellow(JSON.stringify(models, null, 2)))
|
|
547
|
+
console.log(chalk.yellow('DEBUG: Models response:'));
|
|
548
|
+
console.log(chalk.yellow(JSON.stringify(models, null, 2)));
|
|
649
549
|
}
|
|
650
550
|
|
|
651
|
-
console.log(chalk.bold('Available Chat Models:'))
|
|
652
|
-
console.log(chalk.dim('─'.repeat(70)))
|
|
653
|
-
console.log(
|
|
654
|
-
|
|
655
|
-
)
|
|
656
|
-
console.log(chalk.dim('─'.repeat(70)))
|
|
551
|
+
console.log(chalk.bold('Available Chat Models:'));
|
|
552
|
+
console.log(chalk.dim('─'.repeat(70)));
|
|
553
|
+
console.log(chalk.dim('MODEL ID'.padEnd(40)) + chalk.dim('CAPABILITIES'));
|
|
554
|
+
console.log(chalk.dim('─'.repeat(70)));
|
|
657
555
|
|
|
658
556
|
// Filter to only show active models
|
|
659
|
-
const activeModels = models.data.filter(
|
|
660
|
-
(model: any) => model.active === true
|
|
661
|
-
)
|
|
557
|
+
const activeModels = models.data.filter((model: any) => model.active === true);
|
|
662
558
|
|
|
663
559
|
activeModels.forEach((model: any) => {
|
|
664
|
-
const capabilities = []
|
|
665
|
-
if (model.capabilities.vision) capabilities.push('vision')
|
|
666
|
-
if (model.capabilities.function_calling)
|
|
667
|
-
|
|
668
|
-
if (model.capabilities.json_mode) capabilities.push('json_mode')
|
|
560
|
+
const capabilities = [];
|
|
561
|
+
if (model.capabilities.vision) capabilities.push('vision');
|
|
562
|
+
if (model.capabilities.function_calling) capabilities.push('function_calling');
|
|
563
|
+
if (model.capabilities.json_mode) capabilities.push('json_mode');
|
|
669
564
|
|
|
670
565
|
// Format model ID in Huggingface compatible format (owner/model)
|
|
671
|
-
const modelId = `${model.owned_by.toLowerCase()}/${model.id}`.padEnd(
|
|
672
|
-
40
|
|
673
|
-
)
|
|
566
|
+
const modelId = `${model.owned_by.toLowerCase()}/${model.id}`.padEnd(40);
|
|
674
567
|
|
|
675
|
-
console.log(modelId + capabilities.join(', '))
|
|
676
|
-
})
|
|
568
|
+
console.log(modelId + capabilities.join(', '));
|
|
569
|
+
});
|
|
677
570
|
} catch (error) {
|
|
678
|
-
handleError('Failed to list chat models', error)
|
|
571
|
+
handleError('Failed to list chat models', error);
|
|
679
572
|
}
|
|
680
|
-
})
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Helper function to get user confirmation
|
|
578
|
+
*/
|
|
579
|
+
async function confirm(question: string): Promise<boolean> {
|
|
580
|
+
const rl = readline.createInterface({
|
|
581
|
+
input: process.stdin,
|
|
582
|
+
output: process.stdout,
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
return new Promise<boolean>((resolve) => {
|
|
586
|
+
rl.question(question, (answer) => {
|
|
587
|
+
rl.close();
|
|
588
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
589
|
+
});
|
|
590
|
+
});
|
|
681
591
|
}
|