berget 2.2.6 → 2.2.7
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 +11 -5
- package/.husky/pre-commit +1 -0
- package/.prettierignore +15 -0
- package/.prettierrc +5 -3
- package/CONTRIBUTING.md +38 -0
- package/README.md +2 -148
- package/dist/index.js +21 -21
- package/dist/package.json +28 -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 +54 -62
- package/dist/src/commands/api-keys.js +132 -140
- package/dist/src/commands/auth.js +9 -9
- package/dist/src/commands/autocomplete.js +9 -9
- package/dist/src/commands/billing.js +7 -9
- package/dist/src/commands/chat.js +90 -92
- package/dist/src/commands/clusters.js +12 -12
- package/dist/src/commands/code/__tests__/auth-sync.test.js +348 -0
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +23 -0
- package/dist/src/commands/code/__tests__/fake-auth-service.js +55 -0
- package/dist/src/commands/code/__tests__/fake-command-runner.js +5 -7
- package/dist/src/commands/code/__tests__/fake-file-store.js +9 -0
- package/dist/src/commands/code/__tests__/fake-prompter.js +60 -18
- package/dist/src/commands/code/__tests__/setup-flow.test.js +374 -107
- package/dist/src/commands/code/adapters/clack-prompter.js +10 -0
- package/dist/src/commands/code/adapters/fs-file-store.js +8 -3
- package/dist/src/commands/code/adapters/spawn-command-runner.js +15 -11
- package/dist/src/commands/code/auth-sync.js +283 -0
- package/dist/src/commands/code/errors.js +4 -4
- package/dist/src/commands/code/ports/auth-services.js +2 -0
- package/dist/src/commands/code/setup.js +234 -93
- package/dist/src/commands/code.js +139 -251
- package/dist/src/commands/models.js +13 -15
- package/dist/src/commands/users.js +6 -8
- package/dist/src/constants/command-structure.js +116 -116
- package/dist/src/services/api-key-service.js +43 -48
- package/dist/src/services/auth-service.js +60 -299
- package/dist/src/services/browser-auth.js +278 -0
- package/dist/src/services/chat-service.js +78 -91
- package/dist/src/services/cluster-service.js +6 -6
- package/dist/src/services/collaborator-service.js +5 -8
- package/dist/src/services/flux-service.js +5 -8
- package/dist/src/services/helm-service.js +5 -8
- package/dist/src/services/kubectl-service.js +7 -10
- package/dist/src/utils/config-checker.js +5 -5
- package/dist/src/utils/config-loader.js +25 -25
- package/dist/src/utils/default-api-key.js +23 -23
- package/dist/src/utils/env-manager.js +7 -7
- package/dist/src/utils/error-handler.js +60 -61
- package/dist/src/utils/logger.js +7 -7
- package/dist/src/utils/markdown-renderer.js +2 -2
- package/dist/src/utils/opencode-validator.js +17 -20
- package/dist/src/utils/token-manager.js +38 -11
- package/dist/tests/commands/chat.test.js +24 -24
- package/dist/tests/commands/code.test.js +147 -147
- package/dist/tests/utils/config-loader.test.js +114 -114
- package/dist/tests/utils/env-manager.test.js +57 -57
- package/dist/tests/utils/opencode-validator.test.js +33 -33
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +47 -0
- package/index.ts +42 -48
- package/package.json +28 -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 +71 -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 +125 -167
- package/src/commands/api-keys.ts +261 -358
- package/src/commands/auth.ts +24 -30
- package/src/commands/autocomplete.ts +12 -12
- package/src/commands/billing.ts +22 -27
- package/src/commands/chat.ts +230 -323
- package/src/commands/clusters.ts +33 -33
- package/src/commands/code/__tests__/auth-sync.test.ts +481 -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 +39 -42
- package/src/commands/code/__tests__/fake-file-store.ts +32 -23
- package/src/commands/code/__tests__/fake-prompter.ts +107 -69
- package/src/commands/code/__tests__/setup-flow.test.ts +624 -270
- package/src/commands/code/adapters/clack-prompter.ts +50 -38
- package/src/commands/code/adapters/fs-file-store.ts +31 -27
- package/src/commands/code/adapters/spawn-command-runner.ts +33 -29
- package/src/commands/code/auth-sync.ts +329 -0
- package/src/commands/code/errors.ts +15 -15
- 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 +545 -317
- package/src/commands/code.ts +271 -473
- package/src/commands/index.ts +19 -19
- package/src/commands/models.ts +32 -37
- package/src/commands/users.ts +15 -22
- package/src/constants/command-structure.ts +119 -142
- package/src/services/api-key-service.ts +96 -113
- package/src/services/auth-service.ts +92 -339
- package/src/services/browser-auth.ts +296 -0
- package/src/services/chat-service.ts +246 -279
- package/src/services/cluster-service.ts +29 -32
- package/src/services/collaborator-service.ts +13 -18
- package/src/services/flux-service.ts +16 -18
- package/src/services/helm-service.ts +16 -18
- package/src/services/kubectl-service.ts +12 -14
- package/src/types/api.d.ts +924 -926
- package/src/types/json.d.ts +3 -3
- package/src/utils/config-checker.ts +10 -10
- package/src/utils/config-loader.ts +110 -127
- package/src/utils/default-api-key.ts +81 -93
- package/src/utils/env-manager.ts +36 -40
- package/src/utils/error-handler.ts +83 -78
- package/src/utils/logger.ts +41 -41
- package/src/utils/markdown-renderer.ts +11 -11
- package/src/utils/opencode-validator.ts +51 -56
- package/src/utils/token-manager.ts +84 -64
- 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 +60 -70
- package/tests/commands/code.test.ts +330 -376
- package/tests/utils/config-loader.test.ts +260 -260
- package/tests/utils/env-manager.test.ts +127 -134
- package/tests/utils/opencode-validator.test.ts +58 -63
- package/tsconfig.json +2 -2
- package/vitest.config.ts +3 -3
- package/AGENTS.md +0 -374
- package/TODO.md +0 -19
|
@@ -67,113 +67,113 @@ class ChatService {
|
|
|
67
67
|
createCompletion(options) {
|
|
68
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
69
69
|
try {
|
|
70
|
-
logger_1.logger.debug(
|
|
70
|
+
logger_1.logger.debug("Starting createCompletion method");
|
|
71
71
|
// Initialize options if undefined
|
|
72
72
|
const optionsCopy = options ? Object.assign({}, options) : { messages: [] };
|
|
73
73
|
// Check if messages are defined
|
|
74
74
|
if (!optionsCopy.messages || !Array.isArray(optionsCopy.messages)) {
|
|
75
|
-
logger_1.logger.error(
|
|
75
|
+
logger_1.logger.error("messages is undefined or not an array");
|
|
76
76
|
optionsCopy.messages = [];
|
|
77
77
|
}
|
|
78
78
|
// Log the options object
|
|
79
|
-
logger_1.logger.debug(
|
|
79
|
+
logger_1.logger.debug("Starting createCompletion with options:");
|
|
80
80
|
try {
|
|
81
|
-
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, optionsCopy), { apiKey: optionsCopy.apiKey ?
|
|
81
|
+
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, optionsCopy), { apiKey: optionsCopy.apiKey ? "***" : undefined, messages: optionsCopy.messages
|
|
82
82
|
? `${optionsCopy.messages.length} messages`
|
|
83
|
-
:
|
|
83
|
+
: "0 messages" }), null, 2));
|
|
84
84
|
}
|
|
85
85
|
catch (error) {
|
|
86
|
-
logger_1.logger.error(
|
|
86
|
+
logger_1.logger.error("Failed to stringify options:", error);
|
|
87
87
|
}
|
|
88
88
|
const headers = {};
|
|
89
89
|
// First try to use the authenticated client (with refresh token support)
|
|
90
90
|
// Only fall back to API key flow if explicitly requested or no auth tokens available
|
|
91
|
-
const { TokenManager } = yield Promise.resolve().then(() => __importStar(require(
|
|
91
|
+
const { TokenManager } = yield Promise.resolve().then(() => __importStar(require("../utils/token-manager")));
|
|
92
92
|
const tokenManagerInstance = TokenManager.getInstance();
|
|
93
93
|
const hasValidAuth = tokenManagerInstance.getAccessToken() && !tokenManagerInstance.isTokenExpired();
|
|
94
94
|
const envApiKeyForAuth = process.env.BERGET_API_KEY;
|
|
95
95
|
const hasExplicitApiKey = !!optionsCopy.apiKey || !!envApiKeyForAuth;
|
|
96
96
|
// If we have valid auth tokens and no explicit API key, use authenticated client
|
|
97
97
|
if (hasValidAuth && !hasExplicitApiKey) {
|
|
98
|
-
logger_1.logger.debug(
|
|
98
|
+
logger_1.logger.debug("Using authenticated client with refresh token support");
|
|
99
99
|
// Create a copy without apiKey to let the authenticated client handle auth automatically
|
|
100
|
-
const { apiKey } = optionsCopy, optionsWithoutKey = __rest(optionsCopy, ["apiKey"]);
|
|
100
|
+
const { apiKey: _apiKey } = optionsCopy, optionsWithoutKey = __rest(optionsCopy, ["apiKey"]);
|
|
101
101
|
return this.executeCompletion(optionsWithoutKey, {});
|
|
102
102
|
}
|
|
103
103
|
// Check for environment variables first - prioritize this over everything else
|
|
104
104
|
const envApiKey = process.env.BERGET_API_KEY;
|
|
105
105
|
if (envApiKey) {
|
|
106
|
-
logger_1.logger.debug(
|
|
106
|
+
logger_1.logger.debug("Using API key from BERGET_API_KEY environment variable");
|
|
107
107
|
optionsCopy.apiKey = envApiKey;
|
|
108
108
|
// Skip the default API key logic if we already have a key
|
|
109
109
|
return this.executeCompletion(optionsCopy, headers);
|
|
110
110
|
}
|
|
111
111
|
// If API key is already provided, use it directly
|
|
112
112
|
else if (optionsCopy.apiKey) {
|
|
113
|
-
logger_1.logger.debug(
|
|
113
|
+
logger_1.logger.debug("Using API key provided in options");
|
|
114
114
|
// Skip the default API key logic if we already have a key
|
|
115
115
|
return this.executeCompletion(optionsCopy, headers);
|
|
116
116
|
}
|
|
117
117
|
// Only try to get the default API key if no API key is provided and no env var is set
|
|
118
118
|
else {
|
|
119
|
-
logger_1.logger.debug(
|
|
119
|
+
logger_1.logger.debug("No API key provided, trying to get default");
|
|
120
120
|
try {
|
|
121
121
|
// Import the DefaultApiKeyManager directly
|
|
122
|
-
logger_1.logger.debug(
|
|
123
|
-
const DefaultApiKeyManager = (yield Promise.resolve().then(() => __importStar(require(
|
|
122
|
+
logger_1.logger.debug("Importing DefaultApiKeyManager");
|
|
123
|
+
const DefaultApiKeyManager = (yield Promise.resolve().then(() => __importStar(require("../utils/default-api-key"))))
|
|
124
|
+
.DefaultApiKeyManager;
|
|
124
125
|
const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
|
|
125
|
-
logger_1.logger.debug(
|
|
126
|
+
logger_1.logger.debug("Got DefaultApiKeyManager instance");
|
|
126
127
|
// Try to get the default API key
|
|
127
|
-
logger_1.logger.debug(
|
|
128
|
+
logger_1.logger.debug("Calling promptForDefaultApiKey");
|
|
128
129
|
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
|
|
129
|
-
const apiKey = (defaultApiKeyData === null || defaultApiKeyData === void 0 ? void 0 : defaultApiKeyData.key) ||
|
|
130
|
-
(yield defaultApiKeyManager.promptForDefaultApiKey());
|
|
130
|
+
const apiKey = (defaultApiKeyData === null || defaultApiKeyData === void 0 ? void 0 : defaultApiKeyData.key) || (yield defaultApiKeyManager.promptForDefaultApiKey());
|
|
131
131
|
logger_1.logger.debug(`Default API key data exists: ${!!defaultApiKeyData}`);
|
|
132
|
-
logger_1.logger.debug(`promptForDefaultApiKey returned: ${apiKey ?
|
|
132
|
+
logger_1.logger.debug(`promptForDefaultApiKey returned: ${apiKey ? "a key" : "null"}`);
|
|
133
133
|
if (apiKey) {
|
|
134
|
-
logger_1.logger.debug(
|
|
134
|
+
logger_1.logger.debug("Using API key from default API key manager");
|
|
135
135
|
optionsCopy.apiKey = apiKey;
|
|
136
136
|
}
|
|
137
137
|
else {
|
|
138
|
-
logger_1.logger.warn(
|
|
138
|
+
logger_1.logger.warn("No API key available. You need to either:");
|
|
139
139
|
logger_1.logger.warn('1. Create an API key with: berget api-keys create --name "My Key"');
|
|
140
|
-
logger_1.logger.warn(
|
|
141
|
-
logger_1.logger.warn(
|
|
142
|
-
logger_1.logger.warn(
|
|
143
|
-
logger_1.logger.warn(
|
|
144
|
-
logger_1.logger.warn(
|
|
145
|
-
logger_1.logger.warn(
|
|
146
|
-
logger_1.logger.warn(
|
|
147
|
-
throw new Error(
|
|
140
|
+
logger_1.logger.warn("2. Set a default API key with: berget api-keys set-default <id>");
|
|
141
|
+
logger_1.logger.warn("3. Provide an API key with the --api-key option");
|
|
142
|
+
logger_1.logger.warn("4. Set the BERGET_API_KEY environment variable");
|
|
143
|
+
logger_1.logger.warn("\nExample:");
|
|
144
|
+
logger_1.logger.warn(" export BERGET_API_KEY=your_api_key_here");
|
|
145
|
+
logger_1.logger.warn(" # or for a single command:");
|
|
146
|
+
logger_1.logger.warn(" BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it");
|
|
147
|
+
throw new Error("No API key provided and no default API key set");
|
|
148
148
|
}
|
|
149
149
|
// Set the API key in the options
|
|
150
|
-
logger_1.logger.debug(
|
|
150
|
+
logger_1.logger.debug("Setting API key in options");
|
|
151
151
|
// Only set the API key if it's not null
|
|
152
152
|
if (apiKey) {
|
|
153
153
|
optionsCopy.apiKey = apiKey;
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
catch (error) {
|
|
157
|
-
logger_1.logger.error(
|
|
157
|
+
logger_1.logger.error("Error getting API key:");
|
|
158
158
|
if (error instanceof Error) {
|
|
159
159
|
logger_1.logger.error(error.message);
|
|
160
160
|
}
|
|
161
161
|
logger_1.logger.warn('Please create an API key with: berget api-keys create --name "My Key"');
|
|
162
|
-
throw new Error(
|
|
162
|
+
throw new Error("Failed to get API key");
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
// Set default model if not provided
|
|
166
166
|
if (!optionsCopy.model) {
|
|
167
|
-
logger_1.logger.debug(
|
|
168
|
-
optionsCopy.model =
|
|
167
|
+
logger_1.logger.debug("No model specified, using default: google/gemma-3-27b-it");
|
|
168
|
+
optionsCopy.model = "google/gemma-3-27b-it";
|
|
169
169
|
}
|
|
170
|
-
logger_1.logger.debug(
|
|
171
|
-
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, optionsCopy), { apiKey: optionsCopy.apiKey ?
|
|
170
|
+
logger_1.logger.debug("Chat completion options:");
|
|
171
|
+
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, optionsCopy), { apiKey: optionsCopy.apiKey ? "***" : undefined }), null, 2));
|
|
172
172
|
return this.executeCompletion(optionsCopy, headers);
|
|
173
173
|
}
|
|
174
174
|
catch (error) {
|
|
175
175
|
// Improved error handling
|
|
176
|
-
let errorMessage =
|
|
176
|
+
let errorMessage = "Failed to create chat completion";
|
|
177
177
|
if (error instanceof Error) {
|
|
178
178
|
try {
|
|
179
179
|
// Try to parse the error message as JSON
|
|
@@ -182,7 +182,7 @@ class ChatService {
|
|
|
182
182
|
errorMessage = `Chat error: ${parsedError.error.message}`;
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
catch (
|
|
185
|
+
catch (_a) {
|
|
186
186
|
// If parsing fails, use the original error message
|
|
187
187
|
errorMessage = `Chat error: ${error.message}`;
|
|
188
188
|
}
|
|
@@ -204,25 +204,25 @@ class ChatService {
|
|
|
204
204
|
// If an API key is provided, use it for this request
|
|
205
205
|
if (options.apiKey) {
|
|
206
206
|
// API keys should be sent directly, not with Bearer prefix
|
|
207
|
-
headers[
|
|
207
|
+
headers["Authorization"] = options.apiKey;
|
|
208
208
|
}
|
|
209
209
|
// Remove apiKey and onChunk from options before sending to API
|
|
210
210
|
const { apiKey, onChunk } = options, requestOptions = __rest(options, ["apiKey", "onChunk"]);
|
|
211
|
-
logger_1.logger.debug(
|
|
211
|
+
logger_1.logger.debug("Request options:");
|
|
212
212
|
logger_1.logger.debug(JSON.stringify(Object.assign(Object.assign({}, requestOptions), { messages: requestOptions.messages
|
|
213
213
|
? `${requestOptions.messages.length} messages`
|
|
214
|
-
:
|
|
214
|
+
: "0 messages" }), null, 2));
|
|
215
215
|
// Handle streaming responses differently
|
|
216
216
|
if (requestOptions.stream && onChunk) {
|
|
217
217
|
return yield this.handleStreamingResponse(Object.assign(Object.assign({}, requestOptions), { onChunk }), headers);
|
|
218
218
|
}
|
|
219
219
|
else {
|
|
220
220
|
// Ensure model is always defined for the API call
|
|
221
|
-
const requestBody = Object.assign(Object.assign({}, requestOptions), { model: requestOptions.model ||
|
|
221
|
+
const requestBody = Object.assign(Object.assign({}, requestOptions), { model: requestOptions.model || "google/gemma-3-27b-it" });
|
|
222
222
|
// Debug the headers being sent
|
|
223
|
-
logger_1.logger.debug(
|
|
223
|
+
logger_1.logger.debug("Headers being sent:");
|
|
224
224
|
logger_1.logger.debug(JSON.stringify(headers, null, 2));
|
|
225
|
-
const response = yield this.client.POST(
|
|
225
|
+
const response = yield this.client.POST("/v1/chat/completions", {
|
|
226
226
|
body: requestBody,
|
|
227
227
|
headers,
|
|
228
228
|
});
|
|
@@ -230,38 +230,23 @@ class ChatService {
|
|
|
230
230
|
const responseAny = response;
|
|
231
231
|
if (responseAny && responseAny.error)
|
|
232
232
|
throw new Error(JSON.stringify(responseAny.error));
|
|
233
|
-
logger_1.logger.debug(
|
|
233
|
+
logger_1.logger.debug("API response:");
|
|
234
234
|
logger_1.logger.debug(JSON.stringify(response, null, 2));
|
|
235
235
|
// Output the complete response data for debugging
|
|
236
|
-
logger_1.logger.debug(
|
|
236
|
+
logger_1.logger.debug("Complete response data:");
|
|
237
237
|
logger_1.logger.debug(JSON.stringify(response.data, null, 2));
|
|
238
238
|
return response.data;
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
catch (requestError) {
|
|
242
|
-
logger_1.logger.debug(`Request error: ${requestError instanceof Error
|
|
243
|
-
? requestError.message
|
|
244
|
-
: String(requestError)}`);
|
|
242
|
+
logger_1.logger.debug(`Request error: ${requestError instanceof Error ? requestError.message : String(requestError)}`);
|
|
245
243
|
throw requestError;
|
|
246
244
|
}
|
|
247
245
|
});
|
|
248
246
|
}
|
|
249
247
|
/**
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
handleNoApiKey() {
|
|
253
|
-
// We've exhausted all options for getting an API key
|
|
254
|
-
logger_1.logger.warn('No API key available. You need to either:');
|
|
255
|
-
logger_1.logger.warn('1. Create an API key with: berget api-keys create --name "My Key"');
|
|
256
|
-
logger_1.logger.warn('2. Set a default API key with: berget api-keys set-default <id>');
|
|
257
|
-
logger_1.logger.warn('3. Provide an API key with the --api-key option');
|
|
258
|
-
logger_1.logger.warn('4. Set the BERGET_API_KEY environment variable');
|
|
259
|
-
logger_1.logger.warn('\nExample:');
|
|
260
|
-
logger_1.logger.warn(' export BERGET_API_KEY=your_api_key_here');
|
|
261
|
-
logger_1.logger.warn(' # or for a single command:');
|
|
262
|
-
logger_1.logger.warn(' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it');
|
|
263
|
-
throw new Error('No API key available. Please provide an API key or set a default API key.');
|
|
264
|
-
}
|
|
248
|
+
|
|
249
|
+
|
|
265
250
|
/**
|
|
266
251
|
* Handle streaming response from the API
|
|
267
252
|
* @param options Request options
|
|
@@ -272,7 +257,7 @@ class ChatService {
|
|
|
272
257
|
var _a, _b, _c, _d;
|
|
273
258
|
return __awaiter(this, void 0, void 0, function* () {
|
|
274
259
|
// Use the same base URL as the client
|
|
275
|
-
const baseUrl = process.env.API_BASE_URL ||
|
|
260
|
+
const baseUrl = process.env.API_BASE_URL || "https://api.berget.ai";
|
|
276
261
|
const url = new URL(`${baseUrl}/v1/chat/completions`);
|
|
277
262
|
try {
|
|
278
263
|
logger_1.logger.debug(`Making streaming request to: ${url.toString()}`);
|
|
@@ -280,8 +265,8 @@ class ChatService {
|
|
|
280
265
|
logger_1.logger.debug(`Body:`, JSON.stringify(options, null, 2));
|
|
281
266
|
// Make fetch request directly to handle streaming
|
|
282
267
|
const response = yield fetch(url.toString(), {
|
|
283
|
-
method:
|
|
284
|
-
headers: Object.assign({
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: Object.assign({ "Content-Type": "application/json", Accept: "text/event-stream" }, headers),
|
|
285
270
|
body: JSON.stringify(options),
|
|
286
271
|
});
|
|
287
272
|
logger_1.logger.debug(`Response status: ${response.status}`);
|
|
@@ -293,14 +278,14 @@ class ChatService {
|
|
|
293
278
|
throw new Error(`Stream request failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
294
279
|
}
|
|
295
280
|
if (!response.body) {
|
|
296
|
-
throw new Error(
|
|
281
|
+
throw new Error("No response body received");
|
|
297
282
|
}
|
|
298
283
|
// Process the stream
|
|
299
284
|
const reader = response.body.getReader();
|
|
300
285
|
const decoder = new TextDecoder();
|
|
301
|
-
let fullContent =
|
|
286
|
+
let fullContent = "";
|
|
302
287
|
let fullResponse = null;
|
|
303
|
-
let buffer =
|
|
288
|
+
let buffer = ""; // Buffer to accumulate partial JSON data
|
|
304
289
|
while (true) {
|
|
305
290
|
const { done, value } = yield reader.read();
|
|
306
291
|
if (done)
|
|
@@ -311,24 +296,24 @@ class ChatService {
|
|
|
311
296
|
buffer += chunk;
|
|
312
297
|
logger_1.logger.debug(`Added chunk to buffer. Buffer length: ${buffer.length}`);
|
|
313
298
|
// Process the buffer - it may contain multiple SSE events
|
|
314
|
-
const lines = buffer.split(
|
|
299
|
+
const lines = buffer.split("\n");
|
|
315
300
|
logger_1.logger.debug(`Processing ${lines.length} lines from buffer`);
|
|
316
301
|
// Keep track of processed lines to update buffer
|
|
317
302
|
let processedLines = 0;
|
|
318
303
|
for (let i = 0; i < lines.length; i++) {
|
|
319
304
|
const line = lines[i];
|
|
320
305
|
logger_1.logger.debug(`Line ${i}: "${line}"`);
|
|
321
|
-
if (line.startsWith(
|
|
306
|
+
if (line.startsWith("data:")) {
|
|
322
307
|
const jsonData = line.slice(5).trim();
|
|
323
308
|
logger_1.logger.debug(`Extracted JSON data: "${jsonData}"`);
|
|
324
309
|
// Skip empty data or [DONE] marker
|
|
325
|
-
if (jsonData ===
|
|
310
|
+
if (jsonData === "" || jsonData === "[DONE]") {
|
|
326
311
|
logger_1.logger.debug(`Skipping empty data or [DONE] marker`);
|
|
327
312
|
processedLines = i + 1;
|
|
328
313
|
continue;
|
|
329
314
|
}
|
|
330
315
|
// Check if JSON looks complete (basic validation)
|
|
331
|
-
if (!jsonData.startsWith(
|
|
316
|
+
if (!jsonData.startsWith("{")) {
|
|
332
317
|
logger_1.logger.warn(`JSON data doesn't start with '{', might be partial: "${jsonData.substring(0, 50)}..."`);
|
|
333
318
|
// Don't process this line yet, keep it in buffer
|
|
334
319
|
break;
|
|
@@ -343,7 +328,7 @@ class ChatService {
|
|
|
343
328
|
escaped = false;
|
|
344
329
|
continue;
|
|
345
330
|
}
|
|
346
|
-
if (char ===
|
|
331
|
+
if (char === "\\") {
|
|
347
332
|
escaped = true;
|
|
348
333
|
continue;
|
|
349
334
|
}
|
|
@@ -351,10 +336,10 @@ class ChatService {
|
|
|
351
336
|
inString = !inString;
|
|
352
337
|
continue;
|
|
353
338
|
}
|
|
354
|
-
if (!inString && char ===
|
|
339
|
+
if (!inString && char === "{") {
|
|
355
340
|
braceCount++;
|
|
356
341
|
}
|
|
357
|
-
else if (!inString && char ===
|
|
342
|
+
else if (!inString && char === "}") {
|
|
358
343
|
braceCount--;
|
|
359
344
|
}
|
|
360
345
|
}
|
|
@@ -387,19 +372,21 @@ class ChatService {
|
|
|
387
372
|
}
|
|
388
373
|
catch (e) {
|
|
389
374
|
logger_1.logger.error(`Error parsing chunk: ${e}`);
|
|
390
|
-
logger_1.logger.error(`JSON parse error at position ${((_b = (_a = e.message) === null || _a === void 0 ? void 0 : _a.match(/position (\d+)/)) === null || _b === void 0 ? void 0 : _b[1]) ||
|
|
375
|
+
logger_1.logger.error(`JSON parse error at position ${((_b = (_a = e.message) === null || _a === void 0 ? void 0 : _a.match(/position (\d+)/)) === null || _b === void 0 ? void 0 : _b[1]) || "unknown"}`);
|
|
391
376
|
logger_1.logger.error(`Problematic chunk length: ${jsonData.length}`);
|
|
392
377
|
logger_1.logger.error(`Problematic chunk content: "${jsonData}"`);
|
|
393
378
|
logger_1.logger.error(`Chunk starts with: "${jsonData.substring(0, 50)}..."`);
|
|
394
379
|
logger_1.logger.error(`Chunk ends with: "...${jsonData.substring(jsonData.length - 50)}"`);
|
|
395
380
|
// Show character codes around the error position
|
|
396
|
-
const errorPos = parseInt(((_d = (_c = e.message) === null || _c === void 0 ? void 0 : _c.match(/position (\d+)/)) === null || _d === void 0 ? void 0 : _d[1]) ||
|
|
381
|
+
const errorPos = parseInt(((_d = (_c = e.message) === null || _c === void 0 ? void 0 : _c.match(/position (\d+)/)) === null || _d === void 0 ? void 0 : _d[1]) || "0");
|
|
397
382
|
if (errorPos > 0) {
|
|
398
383
|
const start = Math.max(0, errorPos - 20);
|
|
399
384
|
const end = Math.min(jsonData.length, errorPos + 20);
|
|
400
385
|
logger_1.logger.error(`Context around error position ${errorPos}:`);
|
|
401
386
|
logger_1.logger.error(`"${jsonData.substring(start, end)}"`);
|
|
402
|
-
logger_1.logger.error(`Character codes: ${Array.from(jsonData.substring(start, end))
|
|
387
|
+
logger_1.logger.error(`Character codes: ${Array.from(jsonData.substring(start, end))
|
|
388
|
+
.map(c => c.charCodeAt(0))
|
|
389
|
+
.join(" ")}`);
|
|
403
390
|
}
|
|
404
391
|
}
|
|
405
392
|
}
|
|
@@ -407,7 +394,7 @@ class ChatService {
|
|
|
407
394
|
// Update buffer to only contain unprocessed lines
|
|
408
395
|
if (processedLines > 0) {
|
|
409
396
|
const remainingLines = lines.slice(processedLines);
|
|
410
|
-
buffer = remainingLines.join(
|
|
397
|
+
buffer = remainingLines.join("\n");
|
|
411
398
|
logger_1.logger.debug(`Updated buffer. Remaining lines: ${remainingLines.length}, Buffer length: ${buffer.length}`);
|
|
412
399
|
}
|
|
413
400
|
}
|
|
@@ -415,14 +402,14 @@ class ChatService {
|
|
|
415
402
|
if (fullResponse) {
|
|
416
403
|
if (fullContent) {
|
|
417
404
|
fullResponse.choices[0].message = {
|
|
418
|
-
role:
|
|
405
|
+
role: "assistant",
|
|
419
406
|
content: fullContent,
|
|
420
407
|
};
|
|
421
408
|
}
|
|
422
409
|
return fullResponse;
|
|
423
410
|
}
|
|
424
411
|
return {
|
|
425
|
-
choices: [{ message: { role:
|
|
412
|
+
choices: [{ message: { role: "assistant", content: fullContent } }],
|
|
426
413
|
};
|
|
427
414
|
}
|
|
428
415
|
catch (error) {
|
|
@@ -445,13 +432,13 @@ class ChatService {
|
|
|
445
432
|
const headers = {
|
|
446
433
|
Authorization: effectiveApiKey,
|
|
447
434
|
};
|
|
448
|
-
const { data, error } = yield this.client.GET(
|
|
435
|
+
const { data, error } = yield this.client.GET("/v1/models", { headers });
|
|
449
436
|
if (error)
|
|
450
437
|
throw new Error(JSON.stringify(error));
|
|
451
438
|
return data;
|
|
452
439
|
}
|
|
453
440
|
else {
|
|
454
|
-
const { data, error } = yield this.client.GET(
|
|
441
|
+
const { data, error } = yield this.client.GET("/v1/models");
|
|
455
442
|
if (error)
|
|
456
443
|
throw new Error(JSON.stringify(error));
|
|
457
444
|
return data;
|
|
@@ -459,18 +446,18 @@ class ChatService {
|
|
|
459
446
|
}
|
|
460
447
|
catch (error) {
|
|
461
448
|
// Improved error handling
|
|
462
|
-
let errorMessage =
|
|
449
|
+
let errorMessage = "Failed to list models";
|
|
463
450
|
if (error instanceof Error) {
|
|
464
451
|
try {
|
|
465
452
|
// Try to parse the error message as JSON
|
|
466
453
|
const parsedError = JSON.parse(error.message);
|
|
467
454
|
if (parsedError.error) {
|
|
468
|
-
errorMessage = `Models error: ${typeof parsedError.error ===
|
|
455
|
+
errorMessage = `Models error: ${typeof parsedError.error === "string"
|
|
469
456
|
? parsedError.error
|
|
470
457
|
: parsedError.error.message || JSON.stringify(parsedError.error)}`;
|
|
471
458
|
}
|
|
472
459
|
}
|
|
473
|
-
catch (
|
|
460
|
+
catch (_a) {
|
|
474
461
|
// If parsing fails, use the original error message
|
|
475
462
|
errorMessage = `Models error: ${error.message}`;
|
|
476
463
|
}
|
|
@@ -483,9 +470,9 @@ class ChatService {
|
|
|
483
470
|
}
|
|
484
471
|
exports.ChatService = ChatService;
|
|
485
472
|
// Command group name for this service
|
|
486
|
-
ChatService.COMMAND_GROUP =
|
|
473
|
+
ChatService.COMMAND_GROUP = "chat";
|
|
487
474
|
// Subcommands for this service
|
|
488
475
|
ChatService.COMMANDS = {
|
|
489
|
-
RUN:
|
|
490
|
-
LIST:
|
|
476
|
+
RUN: "run",
|
|
477
|
+
LIST: "list",
|
|
491
478
|
};
|
|
@@ -33,7 +33,7 @@ class ClusterService {
|
|
|
33
33
|
getUsage(clusterId) {
|
|
34
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
35
35
|
try {
|
|
36
|
-
const { data, error } = yield this.client.GET(
|
|
36
|
+
const { data, error } = yield this.client.GET("/v1/clusters/{clusterId}/usage", {
|
|
37
37
|
params: { path: { clusterId } },
|
|
38
38
|
});
|
|
39
39
|
if (error)
|
|
@@ -41,7 +41,7 @@ class ClusterService {
|
|
|
41
41
|
return data;
|
|
42
42
|
}
|
|
43
43
|
catch (error) {
|
|
44
|
-
console.error(
|
|
44
|
+
console.error("Failed to get cluster usage:", error);
|
|
45
45
|
throw error;
|
|
46
46
|
}
|
|
47
47
|
});
|
|
@@ -53,13 +53,13 @@ class ClusterService {
|
|
|
53
53
|
list() {
|
|
54
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
55
55
|
try {
|
|
56
|
-
const { data, error } = yield this.client.GET(
|
|
56
|
+
const { data, error } = yield this.client.GET("/v1/clusters");
|
|
57
57
|
if (error)
|
|
58
58
|
throw new Error(JSON.stringify(error));
|
|
59
59
|
return (data === null || data === void 0 ? void 0 : data.data) || [];
|
|
60
60
|
}
|
|
61
61
|
catch (error) {
|
|
62
|
-
console.error(
|
|
62
|
+
console.error("Failed to list clusters:", error);
|
|
63
63
|
throw error;
|
|
64
64
|
}
|
|
65
65
|
});
|
|
@@ -74,10 +74,10 @@ class ClusterService {
|
|
|
74
74
|
// This is a placeholder since the API doesn't have a specific endpoint
|
|
75
75
|
// In a real implementation, this would call a specific endpoint
|
|
76
76
|
const clusters = yield this.list();
|
|
77
|
-
return clusters.find(
|
|
77
|
+
return clusters.find(cluster => cluster.id === clusterId) || null;
|
|
78
78
|
}
|
|
79
79
|
catch (error) {
|
|
80
|
-
console.error(
|
|
80
|
+
console.error("Failed to describe cluster:", error);
|
|
81
81
|
throw error;
|
|
82
82
|
}
|
|
83
83
|
});
|
|
@@ -10,16 +10,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.CollaboratorService = void 0;
|
|
13
|
-
const client_1 = require("../client");
|
|
14
13
|
const command_structure_1 = require("../constants/command-structure");
|
|
15
14
|
/**
|
|
16
15
|
* Service for managing collaborators
|
|
17
16
|
* Command group: users
|
|
18
17
|
*/
|
|
19
18
|
class CollaboratorService {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.client = (0, client_1.createAuthenticatedClient)();
|
|
22
|
-
}
|
|
19
|
+
constructor() { }
|
|
23
20
|
static getInstance() {
|
|
24
21
|
if (!CollaboratorService.instance) {
|
|
25
22
|
CollaboratorService.instance = new CollaboratorService();
|
|
@@ -31,9 +28,9 @@ class CollaboratorService {
|
|
|
31
28
|
* Command: berget users invite
|
|
32
29
|
* This endpoint is not available in the API
|
|
33
30
|
*/
|
|
34
|
-
invite(
|
|
31
|
+
invite(_clusterId, _githubUsername) {
|
|
35
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
-
throw new Error(
|
|
33
|
+
throw new Error("This functionality is not available in the API");
|
|
37
34
|
});
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
@@ -41,9 +38,9 @@ class CollaboratorService {
|
|
|
41
38
|
* Command: berget users list
|
|
42
39
|
* This endpoint is not available in the API
|
|
43
40
|
*/
|
|
44
|
-
list(
|
|
41
|
+
list(_clusterId) {
|
|
45
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
throw new Error(
|
|
43
|
+
throw new Error("This functionality is not available in the API");
|
|
47
44
|
});
|
|
48
45
|
}
|
|
49
46
|
}
|
|
@@ -10,16 +10,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.FluxService = void 0;
|
|
13
|
-
const client_1 = require("../client");
|
|
14
13
|
const command_structure_1 = require("../constants/command-structure");
|
|
15
14
|
/**
|
|
16
15
|
* Service for managing Flux CD
|
|
17
16
|
* Command group: flux
|
|
18
17
|
*/
|
|
19
18
|
class FluxService {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.client = (0, client_1.createAuthenticatedClient)();
|
|
22
|
-
}
|
|
19
|
+
constructor() { }
|
|
23
20
|
static getInstance() {
|
|
24
21
|
if (!FluxService.instance) {
|
|
25
22
|
FluxService.instance = new FluxService();
|
|
@@ -31,9 +28,9 @@ class FluxService {
|
|
|
31
28
|
* Command: berget flux install
|
|
32
29
|
* This endpoint is not available in the API
|
|
33
30
|
*/
|
|
34
|
-
install(
|
|
31
|
+
install(_options) {
|
|
35
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
-
throw new Error(
|
|
33
|
+
throw new Error("This functionality is not available in the API");
|
|
37
34
|
});
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
@@ -41,9 +38,9 @@ class FluxService {
|
|
|
41
38
|
* Command: berget flux bootstrap
|
|
42
39
|
* This endpoint is not available in the API
|
|
43
40
|
*/
|
|
44
|
-
bootstrap(
|
|
41
|
+
bootstrap(_options) {
|
|
45
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
throw new Error(
|
|
43
|
+
throw new Error("This functionality is not available in the API");
|
|
47
44
|
});
|
|
48
45
|
}
|
|
49
46
|
}
|
|
@@ -10,16 +10,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.HelmService = void 0;
|
|
13
|
-
const client_1 = require("../client");
|
|
14
13
|
const command_structure_1 = require("../constants/command-structure");
|
|
15
14
|
/**
|
|
16
15
|
* Service for managing Helm charts
|
|
17
16
|
* Command group: helm
|
|
18
17
|
*/
|
|
19
18
|
class HelmService {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.client = (0, client_1.createAuthenticatedClient)();
|
|
22
|
-
}
|
|
19
|
+
constructor() { }
|
|
23
20
|
static getInstance() {
|
|
24
21
|
if (!HelmService.instance) {
|
|
25
22
|
HelmService.instance = new HelmService();
|
|
@@ -31,9 +28,9 @@ class HelmService {
|
|
|
31
28
|
* Command: berget helm add-repo
|
|
32
29
|
* This endpoint is not available in the API
|
|
33
30
|
*/
|
|
34
|
-
addRepo(
|
|
31
|
+
addRepo(_options) {
|
|
35
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
-
throw new Error(
|
|
33
|
+
throw new Error("This functionality is not available in the API");
|
|
37
34
|
});
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
@@ -41,9 +38,9 @@ class HelmService {
|
|
|
41
38
|
* Command: berget helm install
|
|
42
39
|
* This endpoint is not available in the API
|
|
43
40
|
*/
|
|
44
|
-
install(
|
|
41
|
+
install(_options) {
|
|
45
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
throw new Error(
|
|
43
|
+
throw new Error("This functionality is not available in the API");
|
|
47
44
|
});
|
|
48
45
|
}
|
|
49
46
|
}
|