@astermind/cybernetic-chatbot-client 2.2.44 → 2.2.55

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.
@@ -5,13 +5,14 @@ import 'path';
5
5
  // src/ApiClient.ts
6
6
  // HTTP client for AsterMind backend API
7
7
  /**
8
- * Map backend source format to client Source interface
8
+ * Map backend source format to client Source interface.
9
+ * Handles both canonical (title/score) and legacy (heading/no-score) field names.
9
10
  */
10
11
  function mapSource(raw) {
11
12
  return {
12
- title: raw.title,
13
- snippet: raw.content,
14
- relevance: raw.score,
13
+ title: raw.title || raw.heading || 'Document',
14
+ snippet: raw.content || '',
15
+ relevance: raw.score ?? 0,
15
16
  documentId: raw.documentId,
16
17
  fullContent: raw.fullContent,
17
18
  downloadUrl: raw.downloadUrl,
@@ -49,9 +50,10 @@ class ApiClient {
49
50
  throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`);
50
51
  }
51
52
  const data = await response.json();
52
- // Map backend source format to client Source interface
53
+ // Normalize response: accept both 'reply' (canonical) and 'answer' (legacy)
53
54
  return {
54
55
  ...data,
56
+ reply: data.reply || data.answer || '',
55
57
  sources: (data.sources || []).map(mapSource)
56
58
  };
57
59
  }
@@ -127,7 +129,8 @@ class ApiClient {
127
129
  }
128
130
  }
129
131
  /**
130
- * Get general documents for caching
132
+ * Get general documents for caching.
133
+ * Normalizes field names from both canonical (title) and legacy (name) formats.
131
134
  */
132
135
  async getGeneralDocs(since) {
133
136
  const params = new URLSearchParams();
@@ -144,10 +147,16 @@ class ApiClient {
144
147
  throw new Error(`HTTP ${response.status}`);
145
148
  }
146
149
  const data = await response.json();
147
- return data.documents;
150
+ // Normalize: accept both 'title' (canonical) and 'name' (legacy on-prem)
151
+ return (data.documents || []).map((doc) => ({
152
+ id: doc.id,
153
+ title: doc.title || doc.name || 'Untitled',
154
+ updatedAt: doc.updatedAt || doc.updated_at || new Date().toISOString(),
155
+ }));
148
156
  }
149
157
  /**
150
- * Get API status, quota, and system settings
158
+ * Get API status, quota, and system settings.
159
+ * Normalizes response from both canonical and legacy backend formats.
151
160
  */
152
161
  async getStatus() {
153
162
  const response = await fetch(`${this.baseUrl}/api/external/status`, {
@@ -158,7 +167,38 @@ class ApiClient {
158
167
  if (!response.ok) {
159
168
  throw new Error(`HTTP ${response.status}`);
160
169
  }
161
- return response.json();
170
+ const data = await response.json();
171
+ // Normalize: accept both canonical (apiKey) and legacy (key) structures
172
+ const apiKeyData = data.apiKey || data.key || {};
173
+ const scopes = apiKeyData.scopes || apiKeyData.permissions || ['chat'];
174
+ // Normalize quota: accept both canonical (perMinute/perDay) and legacy structures
175
+ const quota = data.quota || {};
176
+ const perMinute = quota.perMinute || {
177
+ limit: apiKeyData.rateLimit?.limit || quota.rateLimitPerMinute || 30,
178
+ remaining: apiKeyData.rateLimit?.remaining ?? quota.rateLimitPerMinute ?? 30,
179
+ };
180
+ const perDay = quota.perDay || {
181
+ limit: quota.rateLimitPerDay || perMinute.limit * 60 * 24,
182
+ remaining: quota.rateLimitPerDay || perMinute.limit * 60 * 24,
183
+ };
184
+ // Normalize systemSettings: accept both canonical and legacy (system) structures
185
+ const settings = data.systemSettings || data.system || {};
186
+ const cacheRetentionHours = settings.cacheRetentionHours ??
187
+ (settings.cacheRetentionDays ? settings.cacheRetentionDays * 24 : undefined);
188
+ return {
189
+ status: data.status || 'active',
190
+ apiKey: {
191
+ id: apiKeyData.id || '',
192
+ scopes,
193
+ },
194
+ quota: { perMinute, perDay },
195
+ systemSettings: {
196
+ cacheRetentionHours: cacheRetentionHours ?? 720,
197
+ maintenanceMode: settings.maintenanceMode ?? false,
198
+ maintenanceMessage: settings.maintenanceMessage,
199
+ forceOfflineClients: settings.forceOfflineClients ?? false,
200
+ },
201
+ };
162
202
  }
163
203
  /**
164
204
  * Health check (no auth required)
@@ -1296,12 +1336,14 @@ class WebSocketTransport {
1296
1336
  if (!Array.isArray(wsSources))
1297
1337
  return [];
1298
1338
  return wsSources.map((s) => ({
1299
- title: s.heading || s.documentName || 'Document',
1339
+ title: s.title || s.heading || s.documentName || 'Document',
1300
1340
  snippet: s.content || '',
1301
1341
  relevance: s.score ?? 0,
1302
1342
  documentId: s.documentId,
1303
1343
  documentName: s.documentName,
1304
- sourceType: 'document',
1344
+ sourceType: s.sourceType || 'document',
1345
+ chunkId: s.chunkId,
1346
+ downloadUrl: s.downloadUrl,
1305
1347
  }));
1306
1348
  }
1307
1349
  /**
@@ -2303,7 +2345,8 @@ class CyberneticClient {
2303
2345
  this.localRAG = new CyberneticLocalRAG();
2304
2346
  // Initialize license manager
2305
2347
  this.licenseManager = new LicenseManager({
2306
- licenseKey: config.licenseKey
2348
+ licenseKey: config.licenseKey,
2349
+ environment: config.environment,
2307
2350
  });
2308
2351
  // Verify license asynchronously (non-blocking)
2309
2352
  this.licenseManager.verify().then(() => {