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
|
@@ -22,26 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
35
|
-
var t = {};
|
|
36
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
37
|
-
t[p] = s[p];
|
|
38
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
39
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
40
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
41
|
-
t[p[i]] = s[p[i]];
|
|
42
|
-
}
|
|
43
|
-
return t;
|
|
44
|
-
};
|
|
45
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
26
|
exports.ChatService = void 0;
|
|
47
27
|
const client_1 = require("../client");
|
|
@@ -51,9 +31,16 @@ const logger_1 = require("../utils/logger");
|
|
|
51
31
|
* Command group: chat
|
|
52
32
|
*/
|
|
53
33
|
class ChatService {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
34
|
+
// Command group name for this service
|
|
35
|
+
static COMMAND_GROUP = 'chat';
|
|
36
|
+
// Subcommands for this service
|
|
37
|
+
static COMMANDS = {
|
|
38
|
+
LIST: 'list',
|
|
39
|
+
RUN: 'run',
|
|
40
|
+
};
|
|
41
|
+
static instance;
|
|
42
|
+
client = (0, client_1.createAuthenticatedClient)();
|
|
43
|
+
constructor() { }
|
|
57
44
|
static getInstance() {
|
|
58
45
|
if (!ChatService.instance) {
|
|
59
46
|
ChatService.instance = new ChatService();
|
|
@@ -64,133 +51,184 @@ class ChatService {
|
|
|
64
51
|
* Create a chat completion
|
|
65
52
|
* Command: berget chat completion
|
|
66
53
|
*/
|
|
67
|
-
createCompletion(options) {
|
|
68
|
-
|
|
54
|
+
async createCompletion(options) {
|
|
55
|
+
try {
|
|
56
|
+
logger_1.logger.debug('Starting createCompletion method');
|
|
57
|
+
// Initialize options if undefined
|
|
58
|
+
const optionsCopy = options ? { ...options } : { messages: [] };
|
|
59
|
+
// Check if messages are defined
|
|
60
|
+
if (!optionsCopy.messages || !Array.isArray(optionsCopy.messages)) {
|
|
61
|
+
logger_1.logger.error('messages is undefined or not an array');
|
|
62
|
+
optionsCopy.messages = [];
|
|
63
|
+
}
|
|
64
|
+
// Log the options object
|
|
65
|
+
logger_1.logger.debug('Starting createCompletion with options:');
|
|
69
66
|
try {
|
|
70
|
-
logger_1.logger.debug(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
logger_1.logger.
|
|
67
|
+
logger_1.logger.debug(JSON.stringify({
|
|
68
|
+
...optionsCopy,
|
|
69
|
+
apiKey: optionsCopy.apiKey ? '***' : undefined,
|
|
70
|
+
messages: optionsCopy.messages
|
|
71
|
+
? `${optionsCopy.messages.length} messages`
|
|
72
|
+
: '0 messages',
|
|
73
|
+
}, null, 2));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
logger_1.logger.error('Failed to stringify options:', error);
|
|
77
|
+
}
|
|
78
|
+
const headers = {};
|
|
79
|
+
// First try to use the authenticated client (with refresh token support)
|
|
80
|
+
// Only fall back to API key flow if explicitly requested or no auth tokens available
|
|
81
|
+
const { TokenManager } = await Promise.resolve().then(() => __importStar(require('../utils/token-manager')));
|
|
82
|
+
const tokenManagerInstance = TokenManager.getInstance();
|
|
83
|
+
const hasValidAuth = tokenManagerInstance.getAccessToken() && !tokenManagerInstance.isTokenExpired();
|
|
84
|
+
const environmentApiKeyForAuth = process.env.BERGET_API_KEY;
|
|
85
|
+
const hasExplicitApiKey = !!optionsCopy.apiKey || !!environmentApiKeyForAuth;
|
|
86
|
+
// If we have valid auth tokens and no explicit API key, use authenticated client
|
|
87
|
+
if (hasValidAuth && !hasExplicitApiKey) {
|
|
88
|
+
logger_1.logger.debug('Using authenticated client with refresh token support');
|
|
89
|
+
// Create a copy without apiKey to let the authenticated client handle auth automatically
|
|
90
|
+
const { apiKey: _, ...optionsWithoutKey } = optionsCopy;
|
|
91
|
+
return this.executeCompletion(optionsWithoutKey, {});
|
|
92
|
+
}
|
|
93
|
+
// Check for environment variables first - prioritize this over everything else
|
|
94
|
+
const environmentApiKey = process.env.BERGET_API_KEY;
|
|
95
|
+
if (environmentApiKey) {
|
|
96
|
+
logger_1.logger.debug('Using API key from BERGET_API_KEY environment variable');
|
|
97
|
+
optionsCopy.apiKey = environmentApiKey;
|
|
98
|
+
// Skip the default API key logic if we already have a key
|
|
99
|
+
return this.executeCompletion(optionsCopy, headers);
|
|
100
|
+
}
|
|
101
|
+
// If API key is already provided, use it directly
|
|
102
|
+
else if (optionsCopy.apiKey) {
|
|
103
|
+
logger_1.logger.debug('Using API key provided in options');
|
|
104
|
+
// Skip the default API key logic if we already have a key
|
|
105
|
+
return this.executeCompletion(optionsCopy, headers);
|
|
106
|
+
}
|
|
107
|
+
// Only try to get the default API key if no API key is provided and no env var is set
|
|
108
|
+
else {
|
|
109
|
+
logger_1.logger.debug('No API key provided, trying to get default');
|
|
80
110
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
111
|
+
// Import the DefaultApiKeyManager directly
|
|
112
|
+
logger_1.logger.debug('Importing DefaultApiKeyManager');
|
|
113
|
+
const { DefaultApiKeyManager } = await Promise.resolve().then(() => __importStar(require('../utils/default-api-key')));
|
|
114
|
+
const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
|
|
115
|
+
logger_1.logger.debug('Got DefaultApiKeyManager instance');
|
|
116
|
+
// Try to get the default API key
|
|
117
|
+
logger_1.logger.debug('Calling promptForDefaultApiKey');
|
|
118
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
|
|
119
|
+
const apiKey = defaultApiKeyData?.key || (await defaultApiKeyManager.promptForDefaultApiKey());
|
|
120
|
+
logger_1.logger.debug(`Default API key data exists: ${!!defaultApiKeyData}`);
|
|
121
|
+
logger_1.logger.debug(`promptForDefaultApiKey returned: ${apiKey ? 'a key' : 'null'}`);
|
|
122
|
+
if (apiKey) {
|
|
123
|
+
logger_1.logger.debug('Using API key from default API key manager');
|
|
124
|
+
optionsCopy.apiKey = apiKey;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
logger_1.logger.warn('No API key available. You need to either:');
|
|
128
|
+
logger_1.logger.warn('1. Create an API key with: berget api-keys create --name "My Key"');
|
|
129
|
+
logger_1.logger.warn('2. Set a default API key with: berget api-keys set-default <id>');
|
|
130
|
+
logger_1.logger.warn('3. Provide an API key with the --api-key option');
|
|
131
|
+
logger_1.logger.warn('4. Set the BERGET_API_KEY environment variable');
|
|
132
|
+
logger_1.logger.warn('\nExample:');
|
|
133
|
+
logger_1.logger.warn(' export BERGET_API_KEY=your_api_key_here');
|
|
134
|
+
logger_1.logger.warn(' # or for a single command:');
|
|
135
|
+
logger_1.logger.warn(' BERGET_API_KEY=your_api_key_here berget chat run google/gemma-3-27b-it');
|
|
136
|
+
throw new Error('No API key provided and no default API key set');
|
|
137
|
+
}
|
|
138
|
+
// Set the API key in the options
|
|
139
|
+
logger_1.logger.debug('Setting API key in options');
|
|
140
|
+
// Only set the API key if it's not null
|
|
141
|
+
if (apiKey) {
|
|
142
|
+
optionsCopy.apiKey = apiKey;
|
|
143
|
+
}
|
|
84
144
|
}
|
|
85
145
|
catch (error) {
|
|
86
|
-
logger_1.logger.error(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// First try to use the authenticated client (with refresh token support)
|
|
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("../utils/token-manager")));
|
|
92
|
-
const tokenManagerInstance = TokenManager.getInstance();
|
|
93
|
-
const hasValidAuth = tokenManagerInstance.getAccessToken() && !tokenManagerInstance.isTokenExpired();
|
|
94
|
-
const envApiKeyForAuth = process.env.BERGET_API_KEY;
|
|
95
|
-
const hasExplicitApiKey = !!optionsCopy.apiKey || !!envApiKeyForAuth;
|
|
96
|
-
// If we have valid auth tokens and no explicit API key, use authenticated client
|
|
97
|
-
if (hasValidAuth && !hasExplicitApiKey) {
|
|
98
|
-
logger_1.logger.debug("Using authenticated client with refresh token support");
|
|
99
|
-
// Create a copy without apiKey to let the authenticated client handle auth automatically
|
|
100
|
-
const { apiKey: _apiKey } = optionsCopy, optionsWithoutKey = __rest(optionsCopy, ["apiKey"]);
|
|
101
|
-
return this.executeCompletion(optionsWithoutKey, {});
|
|
102
|
-
}
|
|
103
|
-
// Check for environment variables first - prioritize this over everything else
|
|
104
|
-
const envApiKey = process.env.BERGET_API_KEY;
|
|
105
|
-
if (envApiKey) {
|
|
106
|
-
logger_1.logger.debug("Using API key from BERGET_API_KEY environment variable");
|
|
107
|
-
optionsCopy.apiKey = envApiKey;
|
|
108
|
-
// Skip the default API key logic if we already have a key
|
|
109
|
-
return this.executeCompletion(optionsCopy, headers);
|
|
110
|
-
}
|
|
111
|
-
// If API key is already provided, use it directly
|
|
112
|
-
else if (optionsCopy.apiKey) {
|
|
113
|
-
logger_1.logger.debug("Using API key provided in options");
|
|
114
|
-
// Skip the default API key logic if we already have a key
|
|
115
|
-
return this.executeCompletion(optionsCopy, headers);
|
|
116
|
-
}
|
|
117
|
-
// Only try to get the default API key if no API key is provided and no env var is set
|
|
118
|
-
else {
|
|
119
|
-
logger_1.logger.debug("No API key provided, trying to get default");
|
|
120
|
-
try {
|
|
121
|
-
// Import the DefaultApiKeyManager directly
|
|
122
|
-
logger_1.logger.debug("Importing DefaultApiKeyManager");
|
|
123
|
-
const DefaultApiKeyManager = (yield Promise.resolve().then(() => __importStar(require("../utils/default-api-key"))))
|
|
124
|
-
.DefaultApiKeyManager;
|
|
125
|
-
const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
|
|
126
|
-
logger_1.logger.debug("Got DefaultApiKeyManager instance");
|
|
127
|
-
// Try to get the default API key
|
|
128
|
-
logger_1.logger.debug("Calling promptForDefaultApiKey");
|
|
129
|
-
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
|
|
130
|
-
const apiKey = (defaultApiKeyData === null || defaultApiKeyData === void 0 ? void 0 : defaultApiKeyData.key) || (yield defaultApiKeyManager.promptForDefaultApiKey());
|
|
131
|
-
logger_1.logger.debug(`Default API key data exists: ${!!defaultApiKeyData}`);
|
|
132
|
-
logger_1.logger.debug(`promptForDefaultApiKey returned: ${apiKey ? "a key" : "null"}`);
|
|
133
|
-
if (apiKey) {
|
|
134
|
-
logger_1.logger.debug("Using API key from default API key manager");
|
|
135
|
-
optionsCopy.apiKey = apiKey;
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
logger_1.logger.warn("No API key available. You need to either:");
|
|
139
|
-
logger_1.logger.warn('1. Create an API key with: berget api-keys create --name "My Key"');
|
|
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
|
-
}
|
|
149
|
-
// Set the API key in the options
|
|
150
|
-
logger_1.logger.debug("Setting API key in options");
|
|
151
|
-
// Only set the API key if it's not null
|
|
152
|
-
if (apiKey) {
|
|
153
|
-
optionsCopy.apiKey = apiKey;
|
|
154
|
-
}
|
|
146
|
+
logger_1.logger.error('Error getting API key:');
|
|
147
|
+
if (error instanceof Error) {
|
|
148
|
+
logger_1.logger.error(error.message);
|
|
155
149
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
150
|
+
logger_1.logger.warn('Please create an API key with: berget api-keys create --name "My Key"');
|
|
151
|
+
throw new Error('Failed to get API key');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Set default model if not provided
|
|
155
|
+
if (!optionsCopy.model) {
|
|
156
|
+
logger_1.logger.debug('No model specified, using default: google/gemma-3-27b-it');
|
|
157
|
+
optionsCopy.model = 'google/gemma-3-27b-it';
|
|
158
|
+
}
|
|
159
|
+
logger_1.logger.debug('Chat completion options:');
|
|
160
|
+
logger_1.logger.debug(JSON.stringify({
|
|
161
|
+
...optionsCopy,
|
|
162
|
+
apiKey: optionsCopy.apiKey ? '***' : undefined, // Hide the actual API key in debug output
|
|
163
|
+
}, null, 2));
|
|
164
|
+
return this.executeCompletion(optionsCopy, headers);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
// Improved error handling
|
|
168
|
+
let errorMessage = 'Failed to create chat completion';
|
|
169
|
+
if (error instanceof Error) {
|
|
170
|
+
try {
|
|
171
|
+
// Try to parse the error message as JSON
|
|
172
|
+
const parsedError = JSON.parse(error.message);
|
|
173
|
+
if (parsedError.error && parsedError.error.message) {
|
|
174
|
+
errorMessage = `Chat error: ${parsedError.error.message}`;
|
|
163
175
|
}
|
|
164
176
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
optionsCopy.model = "google/gemma-3-27b-it";
|
|
177
|
+
catch {
|
|
178
|
+
// If parsing fails, use the original error message
|
|
179
|
+
errorMessage = `Chat error: ${error.message}`;
|
|
169
180
|
}
|
|
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
|
-
return this.executeCompletion(optionsCopy, headers);
|
|
173
181
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
logger_1.logger.error(errorMessage);
|
|
183
|
+
throw new Error(errorMessage);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* List available models
|
|
188
|
+
* Command: berget chat list
|
|
189
|
+
*/
|
|
190
|
+
async listModels(apiKey) {
|
|
191
|
+
try {
|
|
192
|
+
// Check for environment variable first, then fallback to provided API key
|
|
193
|
+
const environmentApiKey = process.env.BERGET_API_KEY;
|
|
194
|
+
const effectiveApiKey = environmentApiKey || apiKey;
|
|
195
|
+
if (effectiveApiKey) {
|
|
196
|
+
const headers = {
|
|
197
|
+
Authorization: effectiveApiKey,
|
|
198
|
+
};
|
|
199
|
+
const { data, error } = await this.client.GET('/v1/models', { headers });
|
|
200
|
+
if (error)
|
|
201
|
+
throw new Error(JSON.stringify(error));
|
|
202
|
+
return data;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
const { data, error } = await this.client.GET('/v1/models');
|
|
206
|
+
if (error)
|
|
207
|
+
throw new Error(JSON.stringify(error));
|
|
208
|
+
return data;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
// Improved error handling
|
|
213
|
+
let errorMessage = 'Failed to list models';
|
|
214
|
+
if (error instanceof Error) {
|
|
215
|
+
try {
|
|
216
|
+
// Try to parse the error message as JSON
|
|
217
|
+
const parsedError = JSON.parse(error.message);
|
|
218
|
+
if (parsedError.error) {
|
|
219
|
+
errorMessage = `Models error: ${typeof parsedError.error === 'string'
|
|
220
|
+
? parsedError.error
|
|
221
|
+
: parsedError.error.message || JSON.stringify(parsedError.error)}`;
|
|
188
222
|
}
|
|
189
223
|
}
|
|
190
|
-
|
|
191
|
-
|
|
224
|
+
catch {
|
|
225
|
+
// If parsing fails, use the original error message
|
|
226
|
+
errorMessage = `Models error: ${error.message}`;
|
|
227
|
+
}
|
|
192
228
|
}
|
|
193
|
-
|
|
229
|
+
logger_1.logger.error(errorMessage);
|
|
230
|
+
throw new Error(errorMessage);
|
|
231
|
+
}
|
|
194
232
|
}
|
|
195
233
|
/**
|
|
196
234
|
* Execute the completion request with the provided options
|
|
@@ -198,51 +236,55 @@ class ChatService {
|
|
|
198
236
|
* @param headers Additional headers to include
|
|
199
237
|
* @returns The completion response
|
|
200
238
|
*/
|
|
201
|
-
executeCompletion(options, headers = {}) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
// Ensure model is always defined for the API call
|
|
221
|
-
const requestBody = Object.assign(Object.assign({}, requestOptions), { model: requestOptions.model || "google/gemma-3-27b-it" });
|
|
222
|
-
// Debug the headers being sent
|
|
223
|
-
logger_1.logger.debug("Headers being sent:");
|
|
224
|
-
logger_1.logger.debug(JSON.stringify(headers, null, 2));
|
|
225
|
-
const response = yield this.client.POST("/v1/chat/completions", {
|
|
226
|
-
body: requestBody,
|
|
227
|
-
headers,
|
|
228
|
-
});
|
|
229
|
-
// Check if response has an error property
|
|
230
|
-
const responseAny = response;
|
|
231
|
-
if (responseAny && responseAny.error)
|
|
232
|
-
throw new Error(JSON.stringify(responseAny.error));
|
|
233
|
-
logger_1.logger.debug("API response:");
|
|
234
|
-
logger_1.logger.debug(JSON.stringify(response, null, 2));
|
|
235
|
-
// Output the complete response data for debugging
|
|
236
|
-
logger_1.logger.debug("Complete response data:");
|
|
237
|
-
logger_1.logger.debug(JSON.stringify(response.data, null, 2));
|
|
238
|
-
return response.data;
|
|
239
|
-
}
|
|
239
|
+
async executeCompletion(options, headers = {}) {
|
|
240
|
+
try {
|
|
241
|
+
// If an API key is provided, use it for this request
|
|
242
|
+
if (options.apiKey) {
|
|
243
|
+
// API keys should be sent directly, not with Bearer prefix
|
|
244
|
+
headers['Authorization'] = options.apiKey;
|
|
245
|
+
}
|
|
246
|
+
// Remove apiKey and onChunk from options before sending to API
|
|
247
|
+
const { apiKey: _, onChunk, ...requestOptions } = options;
|
|
248
|
+
logger_1.logger.debug('Request options:');
|
|
249
|
+
logger_1.logger.debug(JSON.stringify({
|
|
250
|
+
...requestOptions,
|
|
251
|
+
messages: requestOptions.messages
|
|
252
|
+
? `${requestOptions.messages.length} messages`
|
|
253
|
+
: '0 messages',
|
|
254
|
+
}, null, 2));
|
|
255
|
+
// Handle streaming responses differently
|
|
256
|
+
if (requestOptions.stream && onChunk) {
|
|
257
|
+
return await this.handleStreamingResponse({ ...requestOptions, onChunk }, headers);
|
|
240
258
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
259
|
+
else {
|
|
260
|
+
// Ensure model is always defined for the API call
|
|
261
|
+
const requestBody = {
|
|
262
|
+
...requestOptions,
|
|
263
|
+
model: requestOptions.model || 'google/gemma-3-27b-it',
|
|
264
|
+
};
|
|
265
|
+
// Debug the headers being sent
|
|
266
|
+
logger_1.logger.debug('Headers being sent:');
|
|
267
|
+
logger_1.logger.debug(JSON.stringify(headers, null, 2));
|
|
268
|
+
const response = await this.client.POST('/v1/chat/completions', {
|
|
269
|
+
body: requestBody,
|
|
270
|
+
headers,
|
|
271
|
+
});
|
|
272
|
+
// Check if response has an error property
|
|
273
|
+
const responseAny = response;
|
|
274
|
+
if (responseAny && responseAny.error)
|
|
275
|
+
throw new Error(JSON.stringify(responseAny.error));
|
|
276
|
+
logger_1.logger.debug('API response:');
|
|
277
|
+
logger_1.logger.debug(JSON.stringify(response, null, 2));
|
|
278
|
+
// Output the complete response data for debugging
|
|
279
|
+
logger_1.logger.debug('Complete response data:');
|
|
280
|
+
logger_1.logger.debug(JSON.stringify(response.data, null, 2));
|
|
281
|
+
return response.data;
|
|
244
282
|
}
|
|
245
|
-
}
|
|
283
|
+
}
|
|
284
|
+
catch (requestError) {
|
|
285
|
+
logger_1.logger.debug(`Request error: ${requestError instanceof Error ? requestError.message : String(requestError)}`);
|
|
286
|
+
throw requestError;
|
|
287
|
+
}
|
|
246
288
|
}
|
|
247
289
|
/**
|
|
248
290
|
|
|
@@ -253,226 +295,167 @@ class ChatService {
|
|
|
253
295
|
* @param headers Request headers
|
|
254
296
|
* @returns A promise that resolves when the stream is complete
|
|
255
297
|
*/
|
|
256
|
-
handleStreamingResponse(options, headers) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
298
|
+
async handleStreamingResponse(options, headers) {
|
|
299
|
+
// Use the same base URL as the client
|
|
300
|
+
const baseUrl = process.env.API_BASE_URL || 'https://api.berget.ai';
|
|
301
|
+
const url = new URL(`${baseUrl}/v1/chat/completions`);
|
|
302
|
+
try {
|
|
303
|
+
logger_1.logger.debug(`Making streaming request to: ${url.toString()}`);
|
|
304
|
+
logger_1.logger.debug(`Headers:`, JSON.stringify(headers, null, 2));
|
|
305
|
+
logger_1.logger.debug(`Body:`, JSON.stringify(options, null, 2));
|
|
306
|
+
// Make fetch request directly to handle streaming
|
|
307
|
+
const response = await fetch(url.toString(), {
|
|
308
|
+
body: JSON.stringify(options),
|
|
309
|
+
headers: {
|
|
310
|
+
Accept: 'text/event-stream',
|
|
311
|
+
'Content-Type': 'application/json',
|
|
312
|
+
...headers,
|
|
313
|
+
},
|
|
314
|
+
method: 'POST',
|
|
315
|
+
});
|
|
316
|
+
logger_1.logger.debug(`Response status: ${response.status}`);
|
|
317
|
+
logger_1.logger.debug(`Response headers:`, JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2));
|
|
318
|
+
if (!response.ok) {
|
|
319
|
+
const errorText = await response.text();
|
|
320
|
+
logger_1.logger.error(`Stream request failed: ${response.status} ${response.statusText}`);
|
|
321
|
+
logger_1.logger.error(`Error response: ${errorText}`);
|
|
322
|
+
throw new Error(`Stream request failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
323
|
+
}
|
|
324
|
+
if (!response.body) {
|
|
325
|
+
throw new Error('No response body received');
|
|
326
|
+
}
|
|
327
|
+
// Process the stream
|
|
328
|
+
const reader = response.body.getReader();
|
|
329
|
+
const decoder = new TextDecoder();
|
|
330
|
+
let fullContent = '';
|
|
331
|
+
let fullResponse = null;
|
|
332
|
+
let buffer = ''; // Buffer to accumulate partial JSON data
|
|
333
|
+
while (true) {
|
|
334
|
+
const { done, value } = await reader.read();
|
|
335
|
+
if (done)
|
|
336
|
+
break;
|
|
337
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
338
|
+
logger_1.logger.debug(`Received chunk: ${chunk.length} bytes`);
|
|
339
|
+
// Add chunk to buffer
|
|
340
|
+
buffer += chunk;
|
|
341
|
+
logger_1.logger.debug(`Added chunk to buffer. Buffer length: ${buffer.length}`);
|
|
342
|
+
// Process the buffer - it may contain multiple SSE events
|
|
343
|
+
const lines = buffer.split('\n');
|
|
344
|
+
logger_1.logger.debug(`Processing ${lines.length} lines from buffer`);
|
|
345
|
+
// Keep track of processed lines to update buffer
|
|
346
|
+
let processedLines = 0;
|
|
347
|
+
for (const [index, line] of lines.entries()) {
|
|
348
|
+
logger_1.logger.debug(`Line ${index}: "${line}"`);
|
|
349
|
+
if (line.startsWith('data:')) {
|
|
350
|
+
const jsonData = line.slice(5).trim();
|
|
351
|
+
logger_1.logger.debug(`Extracted JSON data: "${jsonData}"`);
|
|
352
|
+
// Skip empty data or [DONE] marker
|
|
353
|
+
if (jsonData === '' || jsonData === '[DONE]') {
|
|
354
|
+
logger_1.logger.debug(`Skipping empty data or [DONE] marker`);
|
|
355
|
+
processedLines = index + 1;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
// Check if JSON looks complete (basic validation)
|
|
359
|
+
if (!jsonData.startsWith('{')) {
|
|
360
|
+
logger_1.logger.warn(`JSON data doesn't start with '{', might be partial: "${jsonData.slice(0, 50)}..."`);
|
|
361
|
+
// Don't process this line yet, keep it in buffer
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
// Count braces to check if JSON is complete
|
|
365
|
+
let braceCount = 0;
|
|
366
|
+
let inString = false;
|
|
367
|
+
let escaped = false;
|
|
368
|
+
for (const char of jsonData) {
|
|
369
|
+
if (escaped) {
|
|
370
|
+
escaped = false;
|
|
313
371
|
continue;
|
|
314
372
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// Don't process this line yet, keep it in buffer
|
|
319
|
-
break;
|
|
373
|
+
if (char === '\\') {
|
|
374
|
+
escaped = true;
|
|
375
|
+
continue;
|
|
320
376
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
377
|
+
if (char === '"') {
|
|
378
|
+
inString = !inString;
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (!inString && char === '{') {
|
|
382
|
+
braceCount++;
|
|
383
|
+
}
|
|
384
|
+
else if (!inString && char === '}') {
|
|
385
|
+
braceCount--;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (braceCount !== 0) {
|
|
389
|
+
logger_1.logger.warn(`JSON braces don't balance (${braceCount}), treating as partial: "${jsonData.slice(0, 50)}..."`);
|
|
390
|
+
// Don't process this line yet, keep it in buffer
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
try {
|
|
394
|
+
logger_1.logger.debug(`Attempting to parse JSON of length: ${jsonData.length}`);
|
|
395
|
+
const parsedData = JSON.parse(jsonData);
|
|
396
|
+
logger_1.logger.debug(`Successfully parsed JSON: ${JSON.stringify(parsedData, null, 2)}`);
|
|
397
|
+
processedLines = index + 1; // Mark this line as processed
|
|
398
|
+
// Call the onChunk callback with the parsed data
|
|
399
|
+
if (options.onChunk) {
|
|
400
|
+
options.onChunk(parsedData);
|
|
345
401
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
break;
|
|
402
|
+
// Keep track of the full response
|
|
403
|
+
if (!fullResponse) {
|
|
404
|
+
fullResponse = parsedData;
|
|
350
405
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
// Call the onChunk callback with the parsed data
|
|
357
|
-
if (options.onChunk) {
|
|
358
|
-
options.onChunk(parsedData);
|
|
359
|
-
}
|
|
360
|
-
// Keep track of the full response
|
|
361
|
-
if (!fullResponse) {
|
|
362
|
-
fullResponse = parsedData;
|
|
363
|
-
}
|
|
364
|
-
else if (parsedData.choices &&
|
|
365
|
-
parsedData.choices[0] &&
|
|
366
|
-
parsedData.choices[0].delta) {
|
|
367
|
-
// Accumulate content for the full response
|
|
368
|
-
if (parsedData.choices[0].delta.content) {
|
|
369
|
-
fullContent += parsedData.choices[0].delta.content;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
406
|
+
else if (parsedData.choices &&
|
|
407
|
+
parsedData.choices[0] &&
|
|
408
|
+
parsedData.choices[0].delta && // Accumulate content for the full response
|
|
409
|
+
parsedData.choices[0].delta.content) {
|
|
410
|
+
fullContent += parsedData.choices[0].delta.content;
|
|
372
411
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
logger_1.logger.error(`Error parsing chunk: ${error}`);
|
|
415
|
+
logger_1.logger.error(`JSON parse error at position ${error.message?.match(/position (\d+)/)?.[1] || 'unknown'}`);
|
|
416
|
+
logger_1.logger.error(`Problematic chunk length: ${jsonData.length}`);
|
|
417
|
+
logger_1.logger.error(`Problematic chunk content: "${jsonData}"`);
|
|
418
|
+
logger_1.logger.error(`Chunk starts with: "${jsonData.slice(0, 50)}..."`);
|
|
419
|
+
logger_1.logger.error(`Chunk ends with: "...${jsonData.slice(Math.max(0, jsonData.length - 50))}"`);
|
|
420
|
+
// Show character codes around the error position
|
|
421
|
+
const errorPos = Number.parseInt(error.message?.match(/position (\d+)/)?.[1] || '0');
|
|
422
|
+
if (errorPos > 0) {
|
|
423
|
+
const start = Math.max(0, errorPos - 20);
|
|
424
|
+
const end = Math.min(jsonData.length, errorPos + 20);
|
|
425
|
+
logger_1.logger.error(`Context around error position ${errorPos}:`);
|
|
426
|
+
logger_1.logger.error(`"${jsonData.substring(start, end)}"`);
|
|
427
|
+
logger_1.logger.error(`Character codes: ${[...jsonData.substring(start, end)]
|
|
428
|
+
.map((c) => c.charCodeAt(0))
|
|
429
|
+
.join(' ')}`);
|
|
391
430
|
}
|
|
392
431
|
}
|
|
393
432
|
}
|
|
394
|
-
// Update buffer to only contain unprocessed lines
|
|
395
|
-
if (processedLines > 0) {
|
|
396
|
-
const remainingLines = lines.slice(processedLines);
|
|
397
|
-
buffer = remainingLines.join("\n");
|
|
398
|
-
logger_1.logger.debug(`Updated buffer. Remaining lines: ${remainingLines.length}, Buffer length: ${buffer.length}`);
|
|
399
|
-
}
|
|
400
433
|
}
|
|
401
|
-
//
|
|
402
|
-
if (
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
content: fullContent,
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
return fullResponse;
|
|
434
|
+
// Update buffer to only contain unprocessed lines
|
|
435
|
+
if (processedLines > 0) {
|
|
436
|
+
const remainingLines = lines.slice(processedLines);
|
|
437
|
+
buffer = remainingLines.join('\n');
|
|
438
|
+
logger_1.logger.debug(`Updated buffer. Remaining lines: ${remainingLines.length}, Buffer length: ${buffer.length}`);
|
|
410
439
|
}
|
|
411
|
-
return {
|
|
412
|
-
choices: [{ message: { role: "assistant", content: fullContent } }],
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
catch (error) {
|
|
416
|
-
logger_1.logger.error(`Streaming error: ${error instanceof Error ? error.message : String(error)}`);
|
|
417
|
-
throw error;
|
|
418
440
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
listModels(apiKey) {
|
|
426
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
427
|
-
try {
|
|
428
|
-
// Check for environment variable first, then fallback to provided API key
|
|
429
|
-
const envApiKey = process.env.BERGET_API_KEY;
|
|
430
|
-
const effectiveApiKey = envApiKey || apiKey;
|
|
431
|
-
if (effectiveApiKey) {
|
|
432
|
-
const headers = {
|
|
433
|
-
Authorization: effectiveApiKey,
|
|
441
|
+
// Construct the final response object similar to non-streaming response
|
|
442
|
+
if (fullResponse) {
|
|
443
|
+
if (fullContent) {
|
|
444
|
+
fullResponse.choices[0].message = {
|
|
445
|
+
content: fullContent,
|
|
446
|
+
role: 'assistant',
|
|
434
447
|
};
|
|
435
|
-
const { data, error } = yield this.client.GET("/v1/models", { headers });
|
|
436
|
-
if (error)
|
|
437
|
-
throw new Error(JSON.stringify(error));
|
|
438
|
-
return data;
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
const { data, error } = yield this.client.GET("/v1/models");
|
|
442
|
-
if (error)
|
|
443
|
-
throw new Error(JSON.stringify(error));
|
|
444
|
-
return data;
|
|
445
448
|
}
|
|
449
|
+
return fullResponse;
|
|
446
450
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
errorMessage = `Models error: ${typeof parsedError.error === "string"
|
|
456
|
-
? parsedError.error
|
|
457
|
-
: parsedError.error.message || JSON.stringify(parsedError.error)}`;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
catch (_a) {
|
|
461
|
-
// If parsing fails, use the original error message
|
|
462
|
-
errorMessage = `Models error: ${error.message}`;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
logger_1.logger.error(errorMessage);
|
|
466
|
-
throw new Error(errorMessage);
|
|
467
|
-
}
|
|
468
|
-
});
|
|
451
|
+
return {
|
|
452
|
+
choices: [{ message: { content: fullContent, role: 'assistant' } }],
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
logger_1.logger.error(`Streaming error: ${error instanceof Error ? error.message : String(error)}`);
|
|
457
|
+
throw error;
|
|
458
|
+
}
|
|
469
459
|
}
|
|
470
460
|
}
|
|
471
461
|
exports.ChatService = ChatService;
|
|
472
|
-
// Command group name for this service
|
|
473
|
-
ChatService.COMMAND_GROUP = "chat";
|
|
474
|
-
// Subcommands for this service
|
|
475
|
-
ChatService.COMMANDS = {
|
|
476
|
-
RUN: "run",
|
|
477
|
-
LIST: "list",
|
|
478
|
-
};
|