berget 2.2.7 → 2.2.9
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 +6 -6
- package/.github/workflows/test.yml +1 -1
- package/.prettierrc +5 -3
- package/dist/index.js +24 -25
- package/dist/package.json +7 -3
- package/dist/src/agents/app.js +8 -8
- package/dist/src/agents/backend.js +3 -3
- package/dist/src/agents/devops.js +8 -8
- package/dist/src/agents/frontend.js +3 -3
- package/dist/src/agents/fullstack.js +3 -3
- package/dist/src/agents/index.js +18 -18
- package/dist/src/agents/quality.js +8 -8
- package/dist/src/agents/security.js +8 -8
- package/dist/src/client.js +115 -127
- package/dist/src/commands/api-keys.js +181 -202
- package/dist/src/commands/auth.js +16 -25
- package/dist/src/commands/autocomplete.js +8 -8
- package/dist/src/commands/billing.js +10 -19
- package/dist/src/commands/chat.js +139 -170
- package/dist/src/commands/clusters.js +21 -30
- package/dist/src/commands/code/__tests__/auth-sync.test.js +189 -186
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +3 -13
- package/dist/src/commands/code/__tests__/fake-auth-service.js +21 -29
- package/dist/src/commands/code/__tests__/fake-command-runner.js +22 -33
- package/dist/src/commands/code/__tests__/fake-file-store.js +19 -41
- package/dist/src/commands/code/__tests__/fake-prompter.js +81 -97
- package/dist/src/commands/code/__tests__/setup-flow.test.js +295 -295
- package/dist/src/commands/code/adapters/clack-prompter.js +15 -32
- package/dist/src/commands/code/adapters/fs-file-store.js +25 -44
- package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -41
- package/dist/src/commands/code/auth-sync.js +215 -228
- package/dist/src/commands/code/errors.js +15 -12
- package/dist/src/commands/code/setup.js +390 -425
- package/dist/src/commands/code.js +279 -294
- package/dist/src/commands/index.js +5 -5
- package/dist/src/commands/models.js +16 -25
- package/dist/src/commands/users.js +9 -18
- package/dist/src/constants/command-structure.js +138 -138
- package/dist/src/services/api-key-service.js +132 -152
- package/dist/src/services/auth-service.js +81 -95
- package/dist/src/services/browser-auth.js +121 -131
- package/dist/src/services/chat-service.js +369 -386
- package/dist/src/services/cluster-service.js +47 -62
- package/dist/src/services/collaborator-service.js +9 -21
- package/dist/src/services/flux-service.js +13 -25
- package/dist/src/services/helm-service.js +9 -21
- package/dist/src/services/kubectl-service.js +15 -29
- package/dist/src/utils/config-checker.js +8 -8
- package/dist/src/utils/config-loader.js +109 -109
- package/dist/src/utils/default-api-key.js +129 -139
- package/dist/src/utils/env-manager.js +55 -66
- package/dist/src/utils/error-handler.js +62 -62
- package/dist/src/utils/logger.js +74 -67
- package/dist/src/utils/markdown-renderer.js +28 -28
- package/dist/src/utils/opencode-validator.js +67 -69
- package/dist/src/utils/token-manager.js +67 -65
- package/dist/tests/commands/chat.test.js +30 -39
- package/dist/tests/commands/code.test.js +186 -195
- package/dist/tests/utils/config-loader.test.js +107 -107
- package/dist/tests/utils/env-manager.test.js +81 -90
- package/dist/tests/utils/opencode-validator.test.js +42 -41
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +65 -30
- package/index.ts +30 -31
- package/package.json +7 -3
- package/src/agents/app.ts +9 -9
- package/src/agents/backend.ts +4 -4
- package/src/agents/devops.ts +9 -9
- package/src/agents/frontend.ts +4 -4
- package/src/agents/fullstack.ts +4 -4
- package/src/agents/index.ts +27 -25
- package/src/agents/quality.ts +9 -9
- package/src/agents/security.ts +9 -9
- package/src/agents/types.ts +10 -10
- package/src/client.ts +85 -77
- package/src/commands/api-keys.ts +180 -185
- package/src/commands/auth.ts +15 -14
- package/src/commands/autocomplete.ts +10 -10
- package/src/commands/billing.ts +13 -12
- package/src/commands/chat.ts +145 -142
- package/src/commands/clusters.ts +20 -19
- package/src/commands/code/__tests__/auth-sync.test.ts +176 -175
- package/src/commands/code/__tests__/fake-api-key-service.ts +2 -2
- package/src/commands/code/__tests__/fake-auth-service.ts +18 -18
- package/src/commands/code/__tests__/fake-command-runner.ts +28 -22
- package/src/commands/code/__tests__/fake-file-store.ts +15 -15
- package/src/commands/code/__tests__/fake-prompter.ts +86 -85
- package/src/commands/code/__tests__/setup-flow.test.ts +253 -251
- package/src/commands/code/adapters/clack-prompter.ts +32 -30
- package/src/commands/code/adapters/fs-file-store.ts +18 -17
- package/src/commands/code/adapters/spawn-command-runner.ts +20 -15
- package/src/commands/code/auth-sync.ts +210 -210
- package/src/commands/code/errors.ts +11 -11
- package/src/commands/code/ports/auth-services.ts +7 -7
- package/src/commands/code/ports/command-runner.ts +2 -2
- package/src/commands/code/ports/file-store.ts +3 -3
- package/src/commands/code/ports/prompter.ts +13 -13
- package/src/commands/code/setup.ts +408 -406
- package/src/commands/code.ts +288 -287
- package/src/commands/index.ts +11 -10
- package/src/commands/models.ts +19 -18
- package/src/commands/users.ts +11 -10
- package/src/constants/command-structure.ts +159 -159
- package/src/services/api-key-service.ts +85 -85
- package/src/services/auth-service.ts +55 -54
- package/src/services/browser-auth.ts +62 -62
- package/src/services/chat-service.ts +170 -171
- package/src/services/cluster-service.ts +28 -28
- package/src/services/collaborator-service.ts +6 -6
- package/src/services/flux-service.ts +17 -17
- package/src/services/helm-service.ts +11 -11
- package/src/services/kubectl-service.ts +12 -12
- package/src/types/api.d.ts +1933 -1933
- package/src/types/json.d.ts +1 -1
- package/src/utils/config-checker.ts +7 -7
- package/src/utils/config-loader.ts +130 -129
- package/src/utils/default-api-key.ts +81 -80
- package/src/utils/env-manager.ts +37 -37
- package/src/utils/error-handler.ts +64 -64
- package/src/utils/logger.ts +72 -66
- package/src/utils/markdown-renderer.ts +28 -28
- package/src/utils/opencode-validator.ts +72 -71
- package/src/utils/token-manager.ts +69 -68
- package/tests/commands/chat.test.ts +32 -31
- package/tests/commands/code.test.ts +182 -181
- package/tests/utils/config-loader.test.ts +111 -110
- package/tests/utils/env-manager.test.ts +83 -79
- package/tests/utils/opencode-validator.test.ts +43 -42
- package/tsconfig.json +2 -1
- package/vitest.config.ts +2 -2
|
@@ -1,81 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
12
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
-
var m = o[Symbol.asyncIterator], i;
|
|
14
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
15
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
16
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
17
|
-
};
|
|
18
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
19
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
20
4
|
};
|
|
21
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
6
|
exports.registerChatCommands = void 0;
|
|
23
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
24
|
-
const
|
|
8
|
+
const node_readline_1 = __importDefault(require("node:readline"));
|
|
25
9
|
const command_structure_1 = require("../constants/command-structure");
|
|
26
|
-
const chat_service_1 = require("../services/chat-service");
|
|
27
10
|
const api_key_service_1 = require("../services/api-key-service");
|
|
28
11
|
const auth_service_1 = require("../services/auth-service");
|
|
29
|
-
const
|
|
12
|
+
const chat_service_1 = require("../services/chat-service");
|
|
30
13
|
const default_api_key_1 = require("../utils/default-api-key");
|
|
14
|
+
const error_handler_1 = require("../utils/error-handler");
|
|
31
15
|
const markdown_renderer_1 = require("../utils/markdown-renderer");
|
|
32
|
-
/**
|
|
33
|
-
* Helper function to get user confirmation
|
|
34
|
-
*/
|
|
35
|
-
function confirm(question) {
|
|
36
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
const rl = readline_1.default.createInterface({
|
|
38
|
-
input: process.stdin,
|
|
39
|
-
output: process.stdout,
|
|
40
|
-
});
|
|
41
|
-
return new Promise(resolve => {
|
|
42
|
-
rl.question(question, answer => {
|
|
43
|
-
rl.close();
|
|
44
|
-
resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
16
|
/**
|
|
50
17
|
* Register chat commands
|
|
51
18
|
*/
|
|
52
19
|
function registerChatCommands(program) {
|
|
53
|
-
const chat = program.command(command_structure_1.COMMAND_GROUPS.CHAT).description(
|
|
20
|
+
const chat = program.command(command_structure_1.COMMAND_GROUPS.CHAT).description('Interact with AI chat models');
|
|
54
21
|
chat
|
|
55
22
|
.command(command_structure_1.SUBCOMMANDS.CHAT.RUN)
|
|
56
|
-
.description(
|
|
57
|
-
.argument(
|
|
58
|
-
.option(
|
|
59
|
-
.option(
|
|
60
|
-
.option(
|
|
61
|
-
.option(
|
|
62
|
-
.option(
|
|
63
|
-
.option(
|
|
64
|
-
.action((message, options) =>
|
|
65
|
-
var _a, e_1, _b, _c;
|
|
23
|
+
.description('Run a chat session with a specified model')
|
|
24
|
+
.argument('[message]', 'Message to send directly (skips interactive mode)')
|
|
25
|
+
.option('-m, --model <model>', 'Model to use (default: glm-4.7)')
|
|
26
|
+
.option('-t, --temperature <temp>', 'Temperature (0-1)', Number.parseFloat)
|
|
27
|
+
.option('--max-tokens <tokens>', 'Maximum tokens to generate', Number.parseInt)
|
|
28
|
+
.option('-k, --api-key <key>', 'API key to use for this chat session')
|
|
29
|
+
.option('--api-key-id <id>', 'ID of the API key to use from your saved keys')
|
|
30
|
+
.option('--no-stream', 'Disable streaming (streaming is enabled by default)')
|
|
31
|
+
.action(async (message, options) => {
|
|
66
32
|
try {
|
|
67
33
|
const chatService = chat_service_1.ChatService.getInstance();
|
|
68
34
|
// Check if we have an API key or need to get one
|
|
69
35
|
let apiKey = options.apiKey;
|
|
70
36
|
let apiKeyId = options.apiKeyId;
|
|
71
37
|
// Check for environment variable first
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
38
|
+
const environmentApiKey = process.env.BERGET_API_KEY;
|
|
39
|
+
if (environmentApiKey) {
|
|
74
40
|
console.log(chalk_1.default.dim(`Using API key from BERGET_API_KEY environment variable`));
|
|
75
|
-
apiKey =
|
|
41
|
+
apiKey = environmentApiKey;
|
|
76
42
|
// Debug the API key (first few characters only)
|
|
77
|
-
if (process.argv.includes(
|
|
78
|
-
console.log(chalk_1.default.yellow(`DEBUG: API key from env starts with: ${
|
|
43
|
+
if (process.argv.includes('--debug')) {
|
|
44
|
+
console.log(chalk_1.default.yellow(`DEBUG: API key from env starts with: ${environmentApiKey.slice(0, 4)}...`));
|
|
79
45
|
}
|
|
80
46
|
}
|
|
81
47
|
// If API key is already provided via command line, use it
|
|
@@ -101,22 +67,22 @@ function registerChatCommands(program) {
|
|
|
101
67
|
}
|
|
102
68
|
else {
|
|
103
69
|
// No default API key, prompt the user to create one
|
|
104
|
-
console.log(chalk_1.default.yellow(
|
|
70
|
+
console.log(chalk_1.default.yellow('No default API key set.'));
|
|
105
71
|
// Try to prompt for a default API key
|
|
106
|
-
apiKey =
|
|
72
|
+
apiKey = await defaultApiKeyManager.promptForDefaultApiKey();
|
|
107
73
|
if (!apiKey) {
|
|
108
|
-
console.log(chalk_1.default.red(
|
|
109
|
-
console.log(chalk_1.default.yellow(
|
|
74
|
+
console.log(chalk_1.default.red('Error: An API key is required to use the chat command.'));
|
|
75
|
+
console.log(chalk_1.default.yellow('You can:'));
|
|
110
76
|
console.log(chalk_1.default.yellow('1. Create an API key with: berget api-keys create --name "My Key"'));
|
|
111
|
-
console.log(chalk_1.default.yellow(
|
|
112
|
-
console.log(chalk_1.default.yellow(
|
|
77
|
+
console.log(chalk_1.default.yellow('2. Set a default API key with: berget api-keys set-default <id>'));
|
|
78
|
+
console.log(chalk_1.default.yellow('3. Provide an API key with the --api-key option'));
|
|
113
79
|
return;
|
|
114
80
|
}
|
|
115
81
|
}
|
|
116
82
|
}
|
|
117
83
|
catch (error) {
|
|
118
|
-
if (process.argv.includes(
|
|
119
|
-
console.log(chalk_1.default.yellow(
|
|
84
|
+
if (process.argv.includes('--debug')) {
|
|
85
|
+
console.log(chalk_1.default.yellow('DEBUG: Error checking default API key:'));
|
|
120
86
|
console.log(chalk_1.default.yellow(String(error)));
|
|
121
87
|
}
|
|
122
88
|
}
|
|
@@ -125,38 +91,38 @@ function registerChatCommands(program) {
|
|
|
125
91
|
if (!apiKey && apiKeyId) {
|
|
126
92
|
try {
|
|
127
93
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
128
|
-
const keys =
|
|
129
|
-
const selectedKey = keys.find(key => key.id.toString() === options.apiKeyId);
|
|
130
|
-
if (
|
|
131
|
-
console.log(chalk_1.default.yellow(`API key with ID ${options.apiKeyId} not found. Using default authentication.`));
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
94
|
+
const keys = await apiKeyService.list();
|
|
95
|
+
const selectedKey = keys.find((key) => key.id.toString() === options.apiKeyId);
|
|
96
|
+
if (selectedKey) {
|
|
134
97
|
console.log(chalk_1.default.dim(`Using API key: ${selectedKey.name}`));
|
|
135
98
|
// We need to rotate the key to get the actual key value
|
|
136
|
-
if (
|
|
137
|
-
const rotatedKey =
|
|
99
|
+
if (await confirm(chalk_1.default.yellow(`To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue? (y/n)`))) {
|
|
100
|
+
const rotatedKey = await apiKeyService.rotate(options.apiKeyId);
|
|
138
101
|
apiKey = rotatedKey.key;
|
|
139
102
|
console.log(chalk_1.default.green(`API key "${selectedKey.name}" rotated successfully.`));
|
|
140
103
|
}
|
|
141
104
|
else {
|
|
142
|
-
console.log(chalk_1.default.yellow(
|
|
105
|
+
console.log(chalk_1.default.yellow('Using default authentication instead.'));
|
|
143
106
|
}
|
|
144
107
|
}
|
|
108
|
+
else {
|
|
109
|
+
console.log(chalk_1.default.yellow(`API key with ID ${options.apiKeyId} not found. Using default authentication.`));
|
|
110
|
+
}
|
|
145
111
|
}
|
|
146
112
|
catch (error) {
|
|
147
113
|
// Check if this is an authentication error
|
|
148
114
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
149
|
-
const isAuthError = errorMessage.includes(
|
|
150
|
-
errorMessage.includes(
|
|
151
|
-
errorMessage.includes(
|
|
115
|
+
const isAuthError = errorMessage.includes('Unauthorized') ||
|
|
116
|
+
errorMessage.includes('Authentication failed') ||
|
|
117
|
+
errorMessage.includes('AUTH_FAILED');
|
|
152
118
|
if (isAuthError) {
|
|
153
|
-
console.log(chalk_1.default.yellow(
|
|
119
|
+
console.log(chalk_1.default.yellow('Authentication required. Please run `berget auth login` first.'));
|
|
154
120
|
}
|
|
155
121
|
else {
|
|
156
|
-
console.error(chalk_1.default.red(
|
|
122
|
+
console.error(chalk_1.default.red('Error fetching API key:'));
|
|
157
123
|
console.error(error);
|
|
158
124
|
}
|
|
159
|
-
console.log(chalk_1.default.yellow(
|
|
125
|
+
console.log(chalk_1.default.yellow('Using default authentication instead.'));
|
|
160
126
|
}
|
|
161
127
|
}
|
|
162
128
|
// Verify we have authentication before starting chat
|
|
@@ -164,13 +130,13 @@ function registerChatCommands(program) {
|
|
|
164
130
|
try {
|
|
165
131
|
auth_service_1.AuthService.getInstance();
|
|
166
132
|
}
|
|
167
|
-
catch
|
|
168
|
-
console.log(chalk_1.default.red(
|
|
169
|
-
console.log(chalk_1.default.yellow(
|
|
170
|
-
console.log(chalk_1.default.yellow(
|
|
171
|
-
console.log(chalk_1.default.yellow(
|
|
172
|
-
console.log(chalk_1.default.yellow(
|
|
173
|
-
console.log(chalk_1.default.yellow(
|
|
133
|
+
catch {
|
|
134
|
+
console.log(chalk_1.default.red('Error: Authentication required for chat'));
|
|
135
|
+
console.log(chalk_1.default.yellow('Please either:'));
|
|
136
|
+
console.log(chalk_1.default.yellow('1. Log in with `berget auth login`'));
|
|
137
|
+
console.log(chalk_1.default.yellow('2. Provide an API key with `--api-key`'));
|
|
138
|
+
console.log(chalk_1.default.yellow('3. Provide an API key ID with `--api-key-id`'));
|
|
139
|
+
console.log(chalk_1.default.yellow('4. Set a default API key with `berget api-keys set-default <id>`'));
|
|
174
140
|
return;
|
|
175
141
|
}
|
|
176
142
|
}
|
|
@@ -179,32 +145,20 @@ function registerChatCommands(program) {
|
|
|
179
145
|
// Add system message if provided
|
|
180
146
|
if (options.system) {
|
|
181
147
|
messages.push({
|
|
182
|
-
role: "system",
|
|
183
148
|
content: options.system,
|
|
149
|
+
role: 'system',
|
|
184
150
|
});
|
|
185
151
|
}
|
|
186
152
|
// Check if input is being piped in
|
|
187
153
|
let inputMessage = message;
|
|
188
|
-
let stdinContent =
|
|
154
|
+
let stdinContent = '';
|
|
189
155
|
if (!process.stdin.isTTY) {
|
|
190
156
|
// Read from stdin (piped input)
|
|
191
157
|
const chunks = [];
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
_c = _g.value;
|
|
195
|
-
_e = false;
|
|
196
|
-
const chunk = _c;
|
|
197
|
-
chunks.push(chunk);
|
|
198
|
-
}
|
|
158
|
+
for await (const chunk of process.stdin) {
|
|
159
|
+
chunks.push(chunk);
|
|
199
160
|
}
|
|
200
|
-
|
|
201
|
-
finally {
|
|
202
|
-
try {
|
|
203
|
-
if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
|
|
204
|
-
}
|
|
205
|
-
finally { if (e_1) throw e_1.error; }
|
|
206
|
-
}
|
|
207
|
-
stdinContent = Buffer.concat(chunks).toString("utf8").trim();
|
|
161
|
+
stdinContent = Buffer.concat(chunks).toString('utf8').trim();
|
|
208
162
|
}
|
|
209
163
|
// Combine stdin content with message if both exist
|
|
210
164
|
if (stdinContent && message) {
|
|
@@ -217,17 +171,17 @@ function registerChatCommands(program) {
|
|
|
217
171
|
if (inputMessage) {
|
|
218
172
|
// Add user message
|
|
219
173
|
messages.push({
|
|
220
|
-
role: "user",
|
|
221
174
|
content: inputMessage,
|
|
175
|
+
role: 'user',
|
|
222
176
|
});
|
|
223
177
|
try {
|
|
224
178
|
// Call the API
|
|
225
179
|
const completionOptions = {
|
|
226
|
-
model: options.model || "openai/gpt-oss",
|
|
227
|
-
messages: messages,
|
|
228
|
-
temperature: options.temperature !== undefined ? options.temperature : 0.7,
|
|
229
180
|
max_tokens: options.maxTokens || 4096,
|
|
181
|
+
messages: messages,
|
|
182
|
+
model: options.model || 'openai/gpt-oss',
|
|
230
183
|
stream: options.stream !== false,
|
|
184
|
+
temperature: options.temperature === undefined ? 0.7 : options.temperature,
|
|
231
185
|
};
|
|
232
186
|
// Only add apiKey if it actually exists
|
|
233
187
|
if (apiKey) {
|
|
@@ -235,7 +189,7 @@ function registerChatCommands(program) {
|
|
|
235
189
|
}
|
|
236
190
|
// Add streaming support (now default)
|
|
237
191
|
if (completionOptions.stream) {
|
|
238
|
-
let assistantResponse =
|
|
192
|
+
let assistantResponse = '';
|
|
239
193
|
// Stream the response in real-time
|
|
240
194
|
completionOptions.onChunk = (chunk) => {
|
|
241
195
|
if (chunk.choices &&
|
|
@@ -248,7 +202,7 @@ function registerChatCommands(program) {
|
|
|
248
202
|
}
|
|
249
203
|
catch (error) {
|
|
250
204
|
// Handle EPIPE errors gracefully (when pipe is closed)
|
|
251
|
-
if (error.code ===
|
|
205
|
+
if (error.code === 'EPIPE') {
|
|
252
206
|
// Stop streaming if the pipe is closed
|
|
253
207
|
return;
|
|
254
208
|
}
|
|
@@ -258,15 +212,15 @@ function registerChatCommands(program) {
|
|
|
258
212
|
}
|
|
259
213
|
};
|
|
260
214
|
try {
|
|
261
|
-
|
|
215
|
+
await chatService.createCompletion(completionOptions);
|
|
262
216
|
}
|
|
263
217
|
catch (streamError) {
|
|
264
|
-
console.error(chalk_1.default.red(
|
|
218
|
+
console.error(chalk_1.default.red('\nStreaming error:'), streamError);
|
|
265
219
|
// Fallback to non-streaming if streaming fails
|
|
266
|
-
console.log(chalk_1.default.yellow(
|
|
220
|
+
console.log(chalk_1.default.yellow('Falling back to non-streaming mode...'));
|
|
267
221
|
completionOptions.stream = false;
|
|
268
222
|
delete completionOptions.onChunk;
|
|
269
|
-
const response =
|
|
223
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
270
224
|
if (response &&
|
|
271
225
|
response.choices &&
|
|
272
226
|
response.choices[0] &&
|
|
@@ -278,15 +232,15 @@ function registerChatCommands(program) {
|
|
|
278
232
|
console.log(); // Add newline at the end
|
|
279
233
|
return;
|
|
280
234
|
}
|
|
281
|
-
const response =
|
|
235
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
282
236
|
// Check if response has the expected structure
|
|
283
237
|
if (!response ||
|
|
284
238
|
!response.choices ||
|
|
285
239
|
!response.choices[0] ||
|
|
286
240
|
!response.choices[0].message) {
|
|
287
|
-
console.error(chalk_1.default.red(
|
|
288
|
-
console.error(chalk_1.default.red(
|
|
289
|
-
throw new Error(
|
|
241
|
+
console.error(chalk_1.default.red('Error: Unexpected response format from API'));
|
|
242
|
+
console.error(chalk_1.default.red('Response:', JSON.stringify(response, null, 2)));
|
|
243
|
+
throw new Error('Unexpected response format from API');
|
|
290
244
|
}
|
|
291
245
|
// Get assistant's response
|
|
292
246
|
const assistantMessage = response.choices[0].message.content;
|
|
@@ -300,7 +254,7 @@ function registerChatCommands(program) {
|
|
|
300
254
|
return;
|
|
301
255
|
}
|
|
302
256
|
catch (error) {
|
|
303
|
-
console.error(chalk_1.default.red(
|
|
257
|
+
console.error(chalk_1.default.red('Error: Failed to get response'));
|
|
304
258
|
if (error instanceof Error) {
|
|
305
259
|
console.error(chalk_1.default.red(error.message));
|
|
306
260
|
}
|
|
@@ -308,34 +262,34 @@ function registerChatCommands(program) {
|
|
|
308
262
|
}
|
|
309
263
|
}
|
|
310
264
|
// Set up readline interface for user input (only for interactive mode)
|
|
311
|
-
const rl =
|
|
265
|
+
const rl = node_readline_1.default.createInterface({
|
|
312
266
|
input: process.stdin,
|
|
313
267
|
output: process.stdout,
|
|
314
268
|
});
|
|
315
269
|
console.log(chalk_1.default.cyan('Chat with Berget AI (type "exit" to quit)'));
|
|
316
|
-
console.log(chalk_1.default.cyan(
|
|
270
|
+
console.log(chalk_1.default.cyan('----------------------------------------'));
|
|
317
271
|
// Start the conversation loop
|
|
318
272
|
const askQuestion = () => {
|
|
319
|
-
rl.question(chalk_1.default.green(
|
|
273
|
+
rl.question(chalk_1.default.green('You: '), async (input) => {
|
|
320
274
|
// Check if user wants to exit
|
|
321
|
-
if (input.toLowerCase() ===
|
|
322
|
-
console.log(chalk_1.default.cyan(
|
|
275
|
+
if (input.toLowerCase() === 'exit') {
|
|
276
|
+
console.log(chalk_1.default.cyan('Goodbye!'));
|
|
323
277
|
rl.close();
|
|
324
278
|
return;
|
|
325
279
|
}
|
|
326
280
|
// Add user message
|
|
327
281
|
messages.push({
|
|
328
|
-
role: "user",
|
|
329
282
|
content: input,
|
|
283
|
+
role: 'user',
|
|
330
284
|
});
|
|
331
285
|
try {
|
|
332
286
|
// Call the API
|
|
333
287
|
const completionOptions = {
|
|
334
|
-
model: options.model || "openai/gpt-oss",
|
|
335
|
-
messages: messages,
|
|
336
|
-
temperature: options.temperature !== undefined ? options.temperature : 0.7,
|
|
337
288
|
max_tokens: options.maxTokens || 4096,
|
|
289
|
+
messages: messages,
|
|
290
|
+
model: options.model || 'openai/gpt-oss',
|
|
338
291
|
stream: options.stream !== false,
|
|
292
|
+
temperature: options.temperature === undefined ? 0.7 : options.temperature,
|
|
339
293
|
};
|
|
340
294
|
// Only add apiKey if it actually exists
|
|
341
295
|
if (apiKey) {
|
|
@@ -343,8 +297,8 @@ function registerChatCommands(program) {
|
|
|
343
297
|
}
|
|
344
298
|
// Add streaming support (now default)
|
|
345
299
|
if (completionOptions.stream) {
|
|
346
|
-
let assistantResponse =
|
|
347
|
-
console.log(chalk_1.default.blue(
|
|
300
|
+
let assistantResponse = '';
|
|
301
|
+
console.log(chalk_1.default.blue('Assistant: '));
|
|
348
302
|
// Stream the response in real-time
|
|
349
303
|
completionOptions.onChunk = (chunk) => {
|
|
350
304
|
if (chunk.choices &&
|
|
@@ -357,7 +311,7 @@ function registerChatCommands(program) {
|
|
|
357
311
|
}
|
|
358
312
|
catch (error) {
|
|
359
313
|
// Handle EPIPE errors gracefully (when pipe is closed)
|
|
360
|
-
if (error.code ===
|
|
314
|
+
if (error.code === 'EPIPE') {
|
|
361
315
|
// Stop streaming if the pipe is closed
|
|
362
316
|
return;
|
|
363
317
|
}
|
|
@@ -367,15 +321,15 @@ function registerChatCommands(program) {
|
|
|
367
321
|
}
|
|
368
322
|
};
|
|
369
323
|
try {
|
|
370
|
-
|
|
324
|
+
await chatService.createCompletion(completionOptions);
|
|
371
325
|
}
|
|
372
326
|
catch (streamError) {
|
|
373
|
-
console.error(chalk_1.default.red(
|
|
327
|
+
console.error(chalk_1.default.red('\nStreaming error:'), streamError);
|
|
374
328
|
// Fallback to non-streaming if streaming fails
|
|
375
|
-
console.log(chalk_1.default.yellow(
|
|
329
|
+
console.log(chalk_1.default.yellow('Falling back to non-streaming mode...'));
|
|
376
330
|
completionOptions.stream = false;
|
|
377
331
|
delete completionOptions.onChunk;
|
|
378
|
-
const response =
|
|
332
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
379
333
|
if (response &&
|
|
380
334
|
response.choices &&
|
|
381
335
|
response.choices[0] &&
|
|
@@ -384,20 +338,20 @@ function registerChatCommands(program) {
|
|
|
384
338
|
console.log(assistantResponse);
|
|
385
339
|
}
|
|
386
340
|
}
|
|
387
|
-
console.log(
|
|
341
|
+
console.log('\n');
|
|
388
342
|
// Add assistant response to messages
|
|
389
343
|
messages.push({
|
|
390
|
-
role: "assistant",
|
|
391
344
|
content: assistantResponse,
|
|
345
|
+
role: 'assistant',
|
|
392
346
|
});
|
|
393
347
|
// Continue the conversation
|
|
394
348
|
askQuestion();
|
|
395
349
|
return;
|
|
396
350
|
}
|
|
397
|
-
const response =
|
|
351
|
+
const response = await chatService.createCompletion(completionOptions);
|
|
398
352
|
// Debug output
|
|
399
353
|
if (program.opts().debug) {
|
|
400
|
-
console.log(chalk_1.default.yellow(
|
|
354
|
+
console.log(chalk_1.default.yellow('DEBUG: Full response:'));
|
|
401
355
|
console.log(chalk_1.default.yellow(JSON.stringify(response, null, 2)));
|
|
402
356
|
}
|
|
403
357
|
// Check if response has the expected structure
|
|
@@ -405,19 +359,19 @@ function registerChatCommands(program) {
|
|
|
405
359
|
!response.choices ||
|
|
406
360
|
!response.choices[0] ||
|
|
407
361
|
!response.choices[0].message) {
|
|
408
|
-
console.error(chalk_1.default.red(
|
|
409
|
-
console.error(chalk_1.default.red(
|
|
410
|
-
throw new Error(
|
|
362
|
+
console.error(chalk_1.default.red('Error: Unexpected response format from API'));
|
|
363
|
+
console.error(chalk_1.default.red('Response:', JSON.stringify(response, null, 2)));
|
|
364
|
+
throw new Error('Unexpected response format from API');
|
|
411
365
|
}
|
|
412
366
|
// Get assistant's response
|
|
413
367
|
const assistantMessage = response.choices[0].message.content;
|
|
414
368
|
// Add to messages array
|
|
415
369
|
messages.push({
|
|
416
|
-
role: "assistant",
|
|
417
370
|
content: assistantMessage,
|
|
371
|
+
role: 'assistant',
|
|
418
372
|
});
|
|
419
373
|
// Display the response
|
|
420
|
-
console.log(chalk_1.default.blue(
|
|
374
|
+
console.log(chalk_1.default.blue('Assistant: '));
|
|
421
375
|
// Check if the response contains markdown and render it if it does
|
|
422
376
|
if ((0, markdown_renderer_1.containsMarkdown)(assistantMessage)) {
|
|
423
377
|
console.log((0, markdown_renderer_1.renderMarkdown)(assistantMessage));
|
|
@@ -430,28 +384,28 @@ function registerChatCommands(program) {
|
|
|
430
384
|
askQuestion();
|
|
431
385
|
}
|
|
432
386
|
catch (error) {
|
|
433
|
-
console.error(chalk_1.default.red(
|
|
387
|
+
console.error(chalk_1.default.red('Error: Failed to get response'));
|
|
434
388
|
if (error instanceof Error) {
|
|
435
389
|
console.error(chalk_1.default.red(error.message));
|
|
436
390
|
}
|
|
437
391
|
// Continue despite error
|
|
438
392
|
askQuestion();
|
|
439
393
|
}
|
|
440
|
-
})
|
|
394
|
+
});
|
|
441
395
|
};
|
|
442
396
|
// Start the conversation
|
|
443
397
|
askQuestion();
|
|
444
398
|
}
|
|
445
399
|
catch (error) {
|
|
446
|
-
(0, error_handler_1.handleError)(
|
|
400
|
+
(0, error_handler_1.handleError)('Failed to create chat completion', error);
|
|
447
401
|
}
|
|
448
|
-
})
|
|
402
|
+
});
|
|
449
403
|
chat
|
|
450
404
|
.command(command_structure_1.SUBCOMMANDS.CHAT.LIST)
|
|
451
|
-
.description(
|
|
452
|
-
.option(
|
|
453
|
-
.option(
|
|
454
|
-
.action((options) =>
|
|
405
|
+
.description('List available chat models')
|
|
406
|
+
.option('-k, --api-key <key>', 'API key to use for this request')
|
|
407
|
+
.option('--api-key-id <id>', 'ID of the API key to use from your saved keys')
|
|
408
|
+
.action(async (options) => {
|
|
455
409
|
try {
|
|
456
410
|
// If API key ID is provided, fetch the actual key
|
|
457
411
|
let apiKey = options.apiKey;
|
|
@@ -468,59 +422,74 @@ function registerChatCommands(program) {
|
|
|
468
422
|
if (apiKeyId && !apiKey) {
|
|
469
423
|
try {
|
|
470
424
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
471
|
-
const keys =
|
|
472
|
-
const selectedKey = keys.find(key => key.id.toString() === options.apiKeyId);
|
|
473
|
-
if (
|
|
474
|
-
console.log(chalk_1.default.yellow(`API key with ID ${options.apiKeyId} not found. Using default authentication.`));
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
425
|
+
const keys = await apiKeyService.list();
|
|
426
|
+
const selectedKey = keys.find((key) => key.id.toString() === options.apiKeyId);
|
|
427
|
+
if (selectedKey) {
|
|
477
428
|
console.log(chalk_1.default.dim(`Using API key: ${selectedKey.name}`));
|
|
478
429
|
// We need to rotate the key to get the actual key value
|
|
479
|
-
if (
|
|
480
|
-
const rotatedKey =
|
|
430
|
+
if (await confirm(chalk_1.default.yellow(`To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue? (y/n)`))) {
|
|
431
|
+
const rotatedKey = await apiKeyService.rotate(options.apiKeyId);
|
|
481
432
|
apiKey = rotatedKey.key;
|
|
482
433
|
console.log(chalk_1.default.green(`API key "${selectedKey.name}" rotated successfully.`));
|
|
483
434
|
}
|
|
484
435
|
else {
|
|
485
|
-
console.log(chalk_1.default.yellow(
|
|
436
|
+
console.log(chalk_1.default.yellow('Using default authentication instead.'));
|
|
486
437
|
}
|
|
487
438
|
}
|
|
439
|
+
else {
|
|
440
|
+
console.log(chalk_1.default.yellow(`API key with ID ${options.apiKeyId} not found. Using default authentication.`));
|
|
441
|
+
}
|
|
488
442
|
}
|
|
489
443
|
catch (error) {
|
|
490
|
-
console.error(chalk_1.default.red(
|
|
444
|
+
console.error(chalk_1.default.red('Error fetching API key:'));
|
|
491
445
|
console.error(error);
|
|
492
|
-
console.log(chalk_1.default.yellow(
|
|
446
|
+
console.log(chalk_1.default.yellow('Using default authentication instead.'));
|
|
493
447
|
}
|
|
494
448
|
}
|
|
495
449
|
const chatService = chat_service_1.ChatService.getInstance();
|
|
496
|
-
const models =
|
|
450
|
+
const models = await chatService.listModels(apiKey);
|
|
497
451
|
// Debug output
|
|
498
452
|
if (program.opts().debug) {
|
|
499
|
-
console.log(chalk_1.default.yellow(
|
|
453
|
+
console.log(chalk_1.default.yellow('DEBUG: Models response:'));
|
|
500
454
|
console.log(chalk_1.default.yellow(JSON.stringify(models, null, 2)));
|
|
501
455
|
}
|
|
502
|
-
console.log(chalk_1.default.bold(
|
|
503
|
-
console.log(chalk_1.default.dim(
|
|
504
|
-
console.log(chalk_1.default.dim(
|
|
505
|
-
console.log(chalk_1.default.dim(
|
|
456
|
+
console.log(chalk_1.default.bold('Available Chat Models:'));
|
|
457
|
+
console.log(chalk_1.default.dim('─'.repeat(70)));
|
|
458
|
+
console.log(chalk_1.default.dim('MODEL ID'.padEnd(40)) + chalk_1.default.dim('CAPABILITIES'));
|
|
459
|
+
console.log(chalk_1.default.dim('─'.repeat(70)));
|
|
506
460
|
// Filter to only show active models
|
|
507
461
|
const activeModels = models.data.filter((model) => model.active === true);
|
|
508
462
|
activeModels.forEach((model) => {
|
|
509
463
|
const capabilities = [];
|
|
510
464
|
if (model.capabilities.vision)
|
|
511
|
-
capabilities.push(
|
|
465
|
+
capabilities.push('vision');
|
|
512
466
|
if (model.capabilities.function_calling)
|
|
513
|
-
capabilities.push(
|
|
467
|
+
capabilities.push('function_calling');
|
|
514
468
|
if (model.capabilities.json_mode)
|
|
515
|
-
capabilities.push(
|
|
469
|
+
capabilities.push('json_mode');
|
|
516
470
|
// Format model ID in Huggingface compatible format (owner/model)
|
|
517
471
|
const modelId = `${model.owned_by.toLowerCase()}/${model.id}`.padEnd(40);
|
|
518
|
-
console.log(modelId + capabilities.join(
|
|
472
|
+
console.log(modelId + capabilities.join(', '));
|
|
519
473
|
});
|
|
520
474
|
}
|
|
521
475
|
catch (error) {
|
|
522
|
-
(0, error_handler_1.handleError)(
|
|
476
|
+
(0, error_handler_1.handleError)('Failed to list chat models', error);
|
|
523
477
|
}
|
|
524
|
-
})
|
|
478
|
+
});
|
|
525
479
|
}
|
|
526
480
|
exports.registerChatCommands = registerChatCommands;
|
|
481
|
+
/**
|
|
482
|
+
* Helper function to get user confirmation
|
|
483
|
+
*/
|
|
484
|
+
async function confirm(question) {
|
|
485
|
+
const rl = node_readline_1.default.createInterface({
|
|
486
|
+
input: process.stdin,
|
|
487
|
+
output: process.stdout,
|
|
488
|
+
});
|
|
489
|
+
return new Promise((resolve) => {
|
|
490
|
+
rl.question(question, (answer) => {
|
|
491
|
+
rl.close();
|
|
492
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
}
|