lumnisai 0.1.0
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/LICENSE.md +21 -0
- package/README.md +479 -0
- package/dist/index.cjs +1110 -0
- package/dist/index.d.cts +1065 -0
- package/dist/index.d.mts +1064 -0
- package/dist/index.d.ts +1065 -0
- package/dist/index.mjs +1098 -0
- package/package.json +67 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1110 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
const DEFAULT_BASE_URL = "https://api.lumnis.ai";
|
|
6
|
+
const DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
7
|
+
const LONG_POLL_TIMEOUT_S = 10;
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
9
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
10
|
+
const DEFAULT_BACKOFF_FACTOR = 0.5;
|
|
11
|
+
|
|
12
|
+
class ExternalAPIKeysResource {
|
|
13
|
+
constructor(http) {
|
|
14
|
+
this.http = http;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Store a new external API key (encrypted)
|
|
18
|
+
*/
|
|
19
|
+
async store(data) {
|
|
20
|
+
return this.http.post("/external-api-keys", data);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a new external API key (alias for store)
|
|
24
|
+
*/
|
|
25
|
+
async create(data) {
|
|
26
|
+
return this.store(data);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* List all configured external API keys (metadata only, no key values)
|
|
30
|
+
*/
|
|
31
|
+
async list() {
|
|
32
|
+
return this.http.get("/external-api-keys");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get details for a specific external API key (no key value)
|
|
36
|
+
*/
|
|
37
|
+
async get(keyId) {
|
|
38
|
+
return this.http.get(`/external-api-keys/${keyId}`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Delete an external API key for a specific provider
|
|
42
|
+
*/
|
|
43
|
+
async delete(provider) {
|
|
44
|
+
return this.http.delete(`/external-api-keys/${provider}`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the current API key mode
|
|
48
|
+
*/
|
|
49
|
+
async getMode() {
|
|
50
|
+
return this.http.get("/external-api-keys/mode");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Update the API key mode
|
|
54
|
+
*/
|
|
55
|
+
async updateMode(data) {
|
|
56
|
+
return this.http.patch("/external-api-keys/mode", data);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Set the API key mode (alias for updateMode)
|
|
60
|
+
*/
|
|
61
|
+
async setMode(data) {
|
|
62
|
+
return this.updateMode(data);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class FilesResource {
|
|
67
|
+
constructor(http) {
|
|
68
|
+
this.http = http;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Upload a new file for processing
|
|
72
|
+
* @param file - The file to upload (File or Blob)
|
|
73
|
+
* @param options - Upload options
|
|
74
|
+
* @param options.scope - File access scope (user or tenant)
|
|
75
|
+
* @param options.userId - User ID or email (required for user-scoped files)
|
|
76
|
+
* @param options.tags - Comma-separated tags for categorization
|
|
77
|
+
* @param options.duplicateHandling - How to handle duplicate filenames
|
|
78
|
+
*/
|
|
79
|
+
async upload(file, options) {
|
|
80
|
+
const formData = new FormData();
|
|
81
|
+
formData.append("file", file);
|
|
82
|
+
formData.append("scope", options.scope);
|
|
83
|
+
if (options.userId)
|
|
84
|
+
formData.append("user_id", options.userId);
|
|
85
|
+
if (options.tags)
|
|
86
|
+
formData.append("tags", options.tags);
|
|
87
|
+
if (options.duplicateHandling)
|
|
88
|
+
formData.append("duplicate_handling", options.duplicateHandling);
|
|
89
|
+
return this.http.post("/files/upload", formData);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Upload multiple files at once
|
|
93
|
+
*/
|
|
94
|
+
async bulkUpload(files, options) {
|
|
95
|
+
const formData = new FormData();
|
|
96
|
+
for (const file of files)
|
|
97
|
+
formData.append("files", file);
|
|
98
|
+
formData.append("scope", options.scope);
|
|
99
|
+
if (options.userId)
|
|
100
|
+
formData.append("user_id", options.userId);
|
|
101
|
+
if (options.tags)
|
|
102
|
+
formData.append("tags", options.tags);
|
|
103
|
+
return this.http.post("/files/bulk-upload", formData);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get file metadata by ID
|
|
107
|
+
*/
|
|
108
|
+
async get(fileId, userId) {
|
|
109
|
+
const params = userId ? { user_id: userId } : void 0;
|
|
110
|
+
return this.http.get(`/files/${fileId}`, { params });
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* List files with optional filters
|
|
114
|
+
*/
|
|
115
|
+
async list(params) {
|
|
116
|
+
return this.http.get("/files", { params });
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get file content
|
|
120
|
+
*/
|
|
121
|
+
async getContent(fileId, options) {
|
|
122
|
+
const params = {
|
|
123
|
+
content_type: options?.contentType,
|
|
124
|
+
start_line: options?.startLine,
|
|
125
|
+
end_line: options?.endLine,
|
|
126
|
+
user_id: options?.userId
|
|
127
|
+
};
|
|
128
|
+
return this.http.get(`/files/${fileId}/content`, { params });
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Download original file
|
|
132
|
+
* Returns a redirect URL for blob storage or file content directly
|
|
133
|
+
*/
|
|
134
|
+
async download(fileId, userId) {
|
|
135
|
+
const params = userId ? { user_id: userId } : void 0;
|
|
136
|
+
return this.http.request(`/files/${fileId}/download`, {
|
|
137
|
+
method: "GET",
|
|
138
|
+
params
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Update file access scope
|
|
143
|
+
*/
|
|
144
|
+
async updateScope(fileId, data) {
|
|
145
|
+
return this.http.patch(`/files/${fileId}/scope`, data);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Delete a file
|
|
149
|
+
*/
|
|
150
|
+
async delete(fileId, options) {
|
|
151
|
+
const params = {
|
|
152
|
+
hard_delete: options?.hardDelete ?? true,
|
|
153
|
+
user_id: options?.userId
|
|
154
|
+
};
|
|
155
|
+
return this.http.delete(`/files/${fileId}`, { params });
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Delete multiple files at once
|
|
159
|
+
*/
|
|
160
|
+
async bulkDelete(data, options) {
|
|
161
|
+
const params = {
|
|
162
|
+
hard_delete: options?.hardDelete ?? true,
|
|
163
|
+
user_id: options?.userId
|
|
164
|
+
};
|
|
165
|
+
return this.http.request("/files/bulk", {
|
|
166
|
+
method: "DELETE",
|
|
167
|
+
body: data,
|
|
168
|
+
params
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get file processing status
|
|
173
|
+
*/
|
|
174
|
+
async getStatus(fileId, userId) {
|
|
175
|
+
const params = userId ? { user_id: userId } : void 0;
|
|
176
|
+
return this.http.get(`/files/${fileId}/status`, { params });
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Semantic search across files
|
|
180
|
+
*/
|
|
181
|
+
async search(request) {
|
|
182
|
+
return this.http.post("/files/search", request);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get file statistics for the tenant
|
|
186
|
+
*/
|
|
187
|
+
async getStatistics() {
|
|
188
|
+
return this.http.get("/files/statistics");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
class IntegrationsResource {
|
|
193
|
+
constructor(http) {
|
|
194
|
+
this.http = http;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Start an OAuth connection flow for a user
|
|
198
|
+
*/
|
|
199
|
+
async initiateConnection(data) {
|
|
200
|
+
const requestData = {
|
|
201
|
+
...data,
|
|
202
|
+
appName: data.appName.toUpperCase()
|
|
203
|
+
};
|
|
204
|
+
return this.http.post("/integrations/connections/initiate", requestData);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Check the status of a specific connection
|
|
208
|
+
*/
|
|
209
|
+
async getConnectionStatus(userId, appName) {
|
|
210
|
+
return this.http.get(
|
|
211
|
+
`/integrations/connections/${encodeURIComponent(userId)}/${appName.toUpperCase()}`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get all connections for a user
|
|
216
|
+
*/
|
|
217
|
+
async getUserConnections(userId, appFilter) {
|
|
218
|
+
const params = new URLSearchParams();
|
|
219
|
+
if (appFilter)
|
|
220
|
+
params.append("app_filter", appFilter);
|
|
221
|
+
const query = params.toString() ? `?${params.toString()}` : "";
|
|
222
|
+
return this.http.get(
|
|
223
|
+
`/integrations/connections/${encodeURIComponent(userId)}${query}`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get available tools for a user based on connections
|
|
228
|
+
*/
|
|
229
|
+
async getTools(data) {
|
|
230
|
+
const requestData = {
|
|
231
|
+
...data,
|
|
232
|
+
appFilter: data.appFilter?.map((app) => app.toUpperCase())
|
|
233
|
+
};
|
|
234
|
+
return this.http.post("/integrations/tools", requestData);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Disconnect a user from an external app
|
|
238
|
+
*/
|
|
239
|
+
async disconnect(data) {
|
|
240
|
+
const requestData = {
|
|
241
|
+
...data,
|
|
242
|
+
appName: data.appName.toUpperCase()
|
|
243
|
+
};
|
|
244
|
+
return this.http.post("/integrations/connections/disconnect", requestData);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Handle OAuth callback (for custom implementations)
|
|
248
|
+
*/
|
|
249
|
+
async handleCallback(data) {
|
|
250
|
+
return this.http.post("/integrations/connections/callback", data);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* List apps enabled for the tenant
|
|
254
|
+
*/
|
|
255
|
+
async listApps(params) {
|
|
256
|
+
const urlParams = new URLSearchParams();
|
|
257
|
+
if (params?.includeAvailable)
|
|
258
|
+
urlParams.append("include_available", "true");
|
|
259
|
+
const query = urlParams.toString() ? `?${urlParams.toString()}` : "";
|
|
260
|
+
return this.http.get(`/integrations/apps${query}`);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Check if a specific app is enabled
|
|
264
|
+
*/
|
|
265
|
+
async checkAppEnabled(appName) {
|
|
266
|
+
return this.http.get(
|
|
267
|
+
`/integrations/apps/${appName.toUpperCase()}/enabled`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Enable or disable an app for the tenant
|
|
272
|
+
*/
|
|
273
|
+
async updateAppStatus(appName, enabled) {
|
|
274
|
+
return this.http.put(
|
|
275
|
+
`/integrations/apps/${appName.toUpperCase()}?enabled=${enabled}`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get required fields for non-OAuth authentication (future)
|
|
280
|
+
*/
|
|
281
|
+
async getNonOAuthRequiredFields(appName, authScheme) {
|
|
282
|
+
const params = new URLSearchParams({ auth_scheme: authScheme });
|
|
283
|
+
return this.http.get(
|
|
284
|
+
`/integrations/non-oauth/required-fields/${appName.toUpperCase()}?${params.toString()}`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
// Aliases for backward compatibility with client methods
|
|
288
|
+
async isAppEnabled(appName) {
|
|
289
|
+
return this.checkAppEnabled(appName);
|
|
290
|
+
}
|
|
291
|
+
async setAppEnabled(appName, data) {
|
|
292
|
+
return this.updateAppStatus(appName, data.enabled);
|
|
293
|
+
}
|
|
294
|
+
async listConnections(userId, params) {
|
|
295
|
+
return this.getUserConnections(userId, params?.appFilter);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
class MCPServersResource {
|
|
300
|
+
constructor(http) {
|
|
301
|
+
this.http = http;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Create a new MCP server configuration
|
|
305
|
+
*/
|
|
306
|
+
async create(data) {
|
|
307
|
+
return this.http.post("/mcp-servers", data);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* List MCP server configurations
|
|
311
|
+
*/
|
|
312
|
+
async list(params) {
|
|
313
|
+
const queryParams = new URLSearchParams();
|
|
314
|
+
if (params?.scope)
|
|
315
|
+
queryParams.append("scope", params.scope);
|
|
316
|
+
if (params?.userIdentifier)
|
|
317
|
+
queryParams.append("user_identifier", params.userIdentifier);
|
|
318
|
+
if (params?.isActive !== void 0)
|
|
319
|
+
queryParams.append("is_active", params.isActive.toString());
|
|
320
|
+
if (params?.skip)
|
|
321
|
+
queryParams.append("skip", params.skip.toString());
|
|
322
|
+
if (params?.limit)
|
|
323
|
+
queryParams.append("limit", params.limit.toString());
|
|
324
|
+
const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
|
|
325
|
+
return this.http.get(`/mcp-servers${query}`);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Get a specific MCP server configuration
|
|
329
|
+
*/
|
|
330
|
+
async get(serverId) {
|
|
331
|
+
return this.http.get(`/mcp-servers/${serverId}`);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Update an MCP server configuration
|
|
335
|
+
*/
|
|
336
|
+
async update(serverId, data) {
|
|
337
|
+
return this.http.patch(`/mcp-servers/${serverId}`, data);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Delete an MCP server configuration
|
|
341
|
+
*/
|
|
342
|
+
async delete(serverId) {
|
|
343
|
+
await this.http.delete(`/mcp-servers/${serverId}`);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* List tools provided by an MCP server
|
|
347
|
+
* Note: Currently returns empty list, tool indexing coming in Phase 1
|
|
348
|
+
*/
|
|
349
|
+
async listTools(serverId) {
|
|
350
|
+
return this.http.get(`/mcp-servers/${serverId}/tools`);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Test connection to an MCP server
|
|
354
|
+
* Note: Currently returns placeholder, testing coming in Phase 1
|
|
355
|
+
*/
|
|
356
|
+
async testConnection(serverId) {
|
|
357
|
+
return this.http.post(`/mcp-servers/${serverId}/test`);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Test an MCP server configuration before saving
|
|
361
|
+
* Validates that the server can be connected to without creating a permanent configuration
|
|
362
|
+
*/
|
|
363
|
+
async testConfig(config) {
|
|
364
|
+
return this.http.post("/mcp-servers/test", config);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
class ModelPreferencesResource {
|
|
369
|
+
constructor(http) {
|
|
370
|
+
this.http = http;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Get all model preferences for the tenant
|
|
374
|
+
*/
|
|
375
|
+
async get(includeDefaults = true) {
|
|
376
|
+
const params = new URLSearchParams();
|
|
377
|
+
params.append("include_defaults", includeDefaults.toString());
|
|
378
|
+
return this.http.get(`/model-preferences?${params.toString()}`);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Update multiple model preferences in a single request
|
|
382
|
+
*/
|
|
383
|
+
async updateBulk(data) {
|
|
384
|
+
return this.http.put("/model-preferences", data);
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Update a specific model type preference
|
|
388
|
+
*/
|
|
389
|
+
async update(modelType, data) {
|
|
390
|
+
return this.http.patch(`/model-preferences/${modelType}`, data);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Delete a model preference to revert to system default
|
|
394
|
+
*/
|
|
395
|
+
async delete(modelType) {
|
|
396
|
+
await this.http.delete(`/model-preferences/${modelType}`);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Check which models are available based on API key configuration
|
|
400
|
+
*/
|
|
401
|
+
async checkAvailability(models) {
|
|
402
|
+
return this.http.post("/model-preferences/check-availability", models);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* List all model preferences (alias for get)
|
|
406
|
+
*/
|
|
407
|
+
async list(params) {
|
|
408
|
+
return this.get(params?.includeDefaults);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
class LumnisError extends Error {
|
|
413
|
+
code;
|
|
414
|
+
statusCode;
|
|
415
|
+
details;
|
|
416
|
+
requestId;
|
|
417
|
+
constructor(message, options = {}) {
|
|
418
|
+
super(message);
|
|
419
|
+
this.name = "LumnisError";
|
|
420
|
+
this.code = options.code || "UNKNOWN_ERROR";
|
|
421
|
+
this.statusCode = options.statusCode;
|
|
422
|
+
this.details = options.details;
|
|
423
|
+
this.requestId = options.requestId;
|
|
424
|
+
Error.captureStackTrace(this, this.constructor);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
class AuthenticationError extends LumnisError {
|
|
428
|
+
constructor(message, options = {}) {
|
|
429
|
+
super(message, { ...options, statusCode: options.statusCode || 401 });
|
|
430
|
+
this.name = "AuthenticationError";
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
class ValidationError extends LumnisError {
|
|
434
|
+
constructor(message, options = {}) {
|
|
435
|
+
super(message, { ...options, statusCode: options.statusCode || 400 });
|
|
436
|
+
this.name = "ValidationError";
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
class NotFoundError extends LumnisError {
|
|
440
|
+
constructor(message, options = {}) {
|
|
441
|
+
super(message, { ...options, statusCode: 404 });
|
|
442
|
+
this.name = "NotFoundError";
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
class RateLimitError extends LumnisError {
|
|
446
|
+
retryAfter;
|
|
447
|
+
constructor(options = {}) {
|
|
448
|
+
super("Rate limit exceeded", { ...options, statusCode: 429 });
|
|
449
|
+
this.name = "RateLimitError";
|
|
450
|
+
this.retryAfter = options.retryAfter;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
class InternalServerError extends LumnisError {
|
|
454
|
+
constructor(message, options = {}) {
|
|
455
|
+
super(message, { ...options, statusCode: 500 });
|
|
456
|
+
this.name = "InternalServerError";
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
class LocalFileNotSupportedError extends ValidationError {
|
|
460
|
+
constructor(filePath) {
|
|
461
|
+
super(
|
|
462
|
+
`Local file paths are not supported yet: ${filePath}. Please wait for the artifact upload API or use artifact IDs.`,
|
|
463
|
+
{ code: "LOCAL_FILE_NOT_SUPPORTED" }
|
|
464
|
+
);
|
|
465
|
+
this.name = "LocalFileNotSupportedError";
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
class ResponsesResource {
|
|
470
|
+
constructor(http) {
|
|
471
|
+
this.http = http;
|
|
472
|
+
}
|
|
473
|
+
_validateFileReference(uri) {
|
|
474
|
+
if (uri.startsWith("artifact_"))
|
|
475
|
+
return;
|
|
476
|
+
try {
|
|
477
|
+
const parsed = new URL(uri);
|
|
478
|
+
const allowedSchemes = [
|
|
479
|
+
"http",
|
|
480
|
+
"https",
|
|
481
|
+
"s3",
|
|
482
|
+
"gs",
|
|
483
|
+
"gcs",
|
|
484
|
+
"file",
|
|
485
|
+
"ftp",
|
|
486
|
+
"ftps",
|
|
487
|
+
"blob",
|
|
488
|
+
"data"
|
|
489
|
+
];
|
|
490
|
+
if (allowedSchemes.includes(parsed.protocol.replace(":", ""))) {
|
|
491
|
+
if ((parsed.protocol === "http:" || parsed.protocol === "https \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B:") && !parsed.hostname)
|
|
492
|
+
throw new LocalFileNotSupportedError(uri);
|
|
493
|
+
return;
|
|
494
|
+
} else {
|
|
495
|
+
throw new LocalFileNotSupportedError(uri);
|
|
496
|
+
}
|
|
497
|
+
} catch (error) {
|
|
498
|
+
if (error instanceof LocalFileNotSupportedError)
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
const isLocalPath = uri.startsWith("/") || uri.startsWith("./") || uri.startsWith("../") || /^[a-z]:/i.test(uri) || uri.startsWith("\\\\") || uri.split("/").length === 1 && uri.includes(".") && !uri.startsWith("artifact_");
|
|
502
|
+
if (isLocalPath)
|
|
503
|
+
throw new LocalFileNotSupportedError(uri);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Create a new response request for asynchronous processing
|
|
507
|
+
*/
|
|
508
|
+
async create(request) {
|
|
509
|
+
if (request.files) {
|
|
510
|
+
for (const file of request.files)
|
|
511
|
+
this._validateFileReference(file.uri);
|
|
512
|
+
}
|
|
513
|
+
return this.http.post("/responses", request);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Get response status and content
|
|
517
|
+
* @param responseId - The response ID
|
|
518
|
+
* @param options - Optional parameters
|
|
519
|
+
* @param options.wait - Wait time in seconds for long-polling
|
|
520
|
+
*/
|
|
521
|
+
async get(responseId, options) {
|
|
522
|
+
return this.http.get(`/responses/${responseId}`, { params: options });
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* List responses with optional filtering
|
|
526
|
+
* @param params - Optional filter parameters
|
|
527
|
+
* @param params.userId - Filter by user ID
|
|
528
|
+
* @param params.status - Filter by response status
|
|
529
|
+
* @param params.startDate - Filter responses created after this date
|
|
530
|
+
* @param params.endDate - Filter responses created before this date
|
|
531
|
+
* @param params.limit - Maximum number of responses to return
|
|
532
|
+
* @param params.offset - Number of responses to skip for pagination
|
|
533
|
+
*/
|
|
534
|
+
async list(params) {
|
|
535
|
+
const queryParams = {};
|
|
536
|
+
if (params?.userId)
|
|
537
|
+
queryParams.user_id = params.userId;
|
|
538
|
+
if (params?.status)
|
|
539
|
+
queryParams.status = params.status;
|
|
540
|
+
if (params?.startDate)
|
|
541
|
+
queryParams.start_date = params.startDate;
|
|
542
|
+
if (params?.endDate)
|
|
543
|
+
queryParams.end_date = params.endDate;
|
|
544
|
+
if (params?.limit)
|
|
545
|
+
queryParams.limit = params.limit;
|
|
546
|
+
if (params?.offset)
|
|
547
|
+
queryParams.offset = params.offset;
|
|
548
|
+
return this.http.get("/responses", { params: queryParams });
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Cancel a queued or in-progress response
|
|
552
|
+
*/
|
|
553
|
+
async cancel(responseId) {
|
|
554
|
+
return this.http.post(`/responses/${responseId}/cancel`);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* List artifacts generated by a response
|
|
558
|
+
*/
|
|
559
|
+
async listArtifacts(responseId, params) {
|
|
560
|
+
return this.http.get(`/responses/${responseId}/artifacts`, { params });
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
class TenantInfoResource {
|
|
565
|
+
constructor(http) {
|
|
566
|
+
this.http = http;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Get detailed information about a tenant
|
|
570
|
+
* Users can only access information about their own tenant
|
|
571
|
+
*/
|
|
572
|
+
async get(tenantId) {
|
|
573
|
+
return this.http.get(`/tenants/${tenantId}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
class ThreadsResource {
|
|
578
|
+
constructor(http) {
|
|
579
|
+
this.http = http;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Create a new thread
|
|
583
|
+
*/
|
|
584
|
+
async create(params) {
|
|
585
|
+
return this.http.post("/threads", params);
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* List threads for the authenticated tenant
|
|
589
|
+
*/
|
|
590
|
+
async list(params) {
|
|
591
|
+
return this.http.get("/threads", { params });
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Get detailed information about a specific thread
|
|
595
|
+
*/
|
|
596
|
+
async get(threadId) {
|
|
597
|
+
return this.http.get(`/threads/${encodeURIComponent(threadId)}`);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Get all responses associated with a specific thread
|
|
601
|
+
*/
|
|
602
|
+
async getResponses(threadId, params) {
|
|
603
|
+
return this.http.get(`/threads/${encodeURIComponent(threadId)}/responses`, { params });
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Update thread metadata
|
|
607
|
+
*/
|
|
608
|
+
async update(threadId, data) {
|
|
609
|
+
return this.http.patch(`/threads/${encodeURIComponent(threadId)}`, data);
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Delete a thread and all its associated responses
|
|
613
|
+
*/
|
|
614
|
+
async delete(threadId) {
|
|
615
|
+
await this.http.delete(`/threads/${encodeURIComponent(threadId)}`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
class UsersResource {
|
|
620
|
+
constructor(http) {
|
|
621
|
+
this.http = http;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Create a new user within the tenant
|
|
625
|
+
* Returns existing user with 200 OK if user with same email already exists
|
|
626
|
+
*/
|
|
627
|
+
async create(data) {
|
|
628
|
+
return this.http.post("/users", data);
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* List all users in the tenant with pagination
|
|
632
|
+
*/
|
|
633
|
+
async list(params) {
|
|
634
|
+
const queryParams = new URLSearchParams();
|
|
635
|
+
if (params?.page)
|
|
636
|
+
queryParams.append("page", params.page.toString());
|
|
637
|
+
if (params?.pageSize)
|
|
638
|
+
queryParams.append("page_size", params.pageSize.toString());
|
|
639
|
+
const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
|
|
640
|
+
return this.http.get(`/users${query}`);
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Get user details by ID or email
|
|
644
|
+
*/
|
|
645
|
+
async get(userIdentifier) {
|
|
646
|
+
return this.http.get(`/users/${encodeURIComponent(userIdentifier)}`);
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Update user information by ID or email
|
|
650
|
+
*/
|
|
651
|
+
async update(userIdentifier, data) {
|
|
652
|
+
return this.http.put(`/users/${encodeURIComponent(userIdentifier)}`, data);
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Delete (deactivate) a user by ID or email
|
|
656
|
+
*/
|
|
657
|
+
async delete(userIdentifier) {
|
|
658
|
+
return this.http.delete(`/users/${encodeURIComponent(userIdentifier)}`);
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Get all AI responses generated for a specific user
|
|
662
|
+
*/
|
|
663
|
+
async getResponses(userIdentifier, params) {
|
|
664
|
+
const queryParams = new URLSearchParams();
|
|
665
|
+
if (params?.page)
|
|
666
|
+
queryParams.append("page", params.page.toString());
|
|
667
|
+
if (params?.pageSize)
|
|
668
|
+
queryParams.append("page_size", params.pageSize.toString());
|
|
669
|
+
const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
|
|
670
|
+
return this.http.get(`/users/${encodeURIComponent(userIdentifier)}/responses${query}`);
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Get all conversation threads for a specific user
|
|
674
|
+
*/
|
|
675
|
+
async getThreads(userIdentifier, params) {
|
|
676
|
+
const queryParams = new URLSearchParams();
|
|
677
|
+
if (params?.page)
|
|
678
|
+
queryParams.append("page", params.page.toString());
|
|
679
|
+
if (params?.pageSize)
|
|
680
|
+
queryParams.append("page_size", params.pageSize.toString());
|
|
681
|
+
const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
|
|
682
|
+
return this.http.get(`/users/${encodeURIComponent(userIdentifier)}/threads${query}`);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function toCamel(s) {
|
|
687
|
+
return s.replace(/([-_][a-z])/gi, ($1) => {
|
|
688
|
+
return $1.toUpperCase().replace("-", "").replace("_", "");
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
function toSnake(s) {
|
|
692
|
+
return s.replace(/[A-Z]/g, (letter, index) => {
|
|
693
|
+
return index === 0 ? letter.toLowerCase() : `_${letter.toLowerCase()}`;
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
function convertCase(obj, converter) {
|
|
697
|
+
if (Array.isArray(obj)) {
|
|
698
|
+
return obj.map((v) => convertCase(v, converter));
|
|
699
|
+
} else if (obj !== null && typeof obj === "object") {
|
|
700
|
+
return Object.keys(obj).reduce((acc, key) => {
|
|
701
|
+
acc[converter(key)] = convertCase(obj[key], converter);
|
|
702
|
+
return acc;
|
|
703
|
+
}, {});
|
|
704
|
+
}
|
|
705
|
+
return obj;
|
|
706
|
+
}
|
|
707
|
+
function toCamelCase(obj) {
|
|
708
|
+
return convertCase(obj, toCamel);
|
|
709
|
+
}
|
|
710
|
+
function toSnakeCase(obj) {
|
|
711
|
+
return convertCase(obj, toSnake);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
class Http {
|
|
715
|
+
options;
|
|
716
|
+
constructor(options) {
|
|
717
|
+
this.options = {
|
|
718
|
+
baseUrl: options.baseUrl.replace(/\/$/, ""),
|
|
719
|
+
apiPrefix: options.apiPrefix || "",
|
|
720
|
+
headers: options.headers || {},
|
|
721
|
+
timeoutMs: options.timeoutMs || DEFAULT_TIMEOUT_MS,
|
|
722
|
+
maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
723
|
+
backoffFactor: options.backoffFactor || DEFAULT_BACKOFF_FACTOR
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
async _handleResponse(response) {
|
|
727
|
+
const requestId = response.headers.get("x-request-id");
|
|
728
|
+
if (response.ok) {
|
|
729
|
+
if (response.status === 204)
|
|
730
|
+
return null;
|
|
731
|
+
const contentType = response.headers.get("content-type") || "";
|
|
732
|
+
if (contentType.includes("application/json")) {
|
|
733
|
+
const json = await response.json();
|
|
734
|
+
return toCamelCase(json);
|
|
735
|
+
}
|
|
736
|
+
return await response.text();
|
|
737
|
+
}
|
|
738
|
+
let detail = { raw: await response.text() };
|
|
739
|
+
try {
|
|
740
|
+
if (response.headers.get("content-type")?.includes("application/json"))
|
|
741
|
+
detail = JSON.parse(detail.raw);
|
|
742
|
+
} catch {
|
|
743
|
+
}
|
|
744
|
+
const errorMsg = detail?.error?.message || `Server error: ${response.status}`;
|
|
745
|
+
switch (response.status) {
|
|
746
|
+
case 401:
|
|
747
|
+
throw new AuthenticationError("Invalid or missing API key", { requestId, statusCode: 401, details: detail });
|
|
748
|
+
case 403:
|
|
749
|
+
throw new AuthenticationError("Forbidden - insufficient permissions", { requestId, statusCode: 403, details: detail });
|
|
750
|
+
case 404:
|
|
751
|
+
throw new NotFoundError("Resource not found", { requestId, statusCode: 404, details: detail });
|
|
752
|
+
case 429: {
|
|
753
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
754
|
+
throw new RateLimitError({ requestId, statusCode: 429, details: detail, retryAfter });
|
|
755
|
+
}
|
|
756
|
+
default:
|
|
757
|
+
if (response.status >= 400 && response.status < 500)
|
|
758
|
+
throw new ValidationError(errorMsg, { requestId, statusCode: response.status, details: detail });
|
|
759
|
+
throw new LumnisError(`Server error: ${response.status}`, { requestId, statusCode: response.status, details: detail });
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
async request(path, init = {}) {
|
|
763
|
+
const { body, params, idempotencyKey: idempotencyKeyOption, ...fetchOptions } = init;
|
|
764
|
+
const method = fetchOptions.method || "GET";
|
|
765
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
766
|
+
const fullPath = this.options.apiPrefix ? `${this.options.apiPrefix}${normalizedPath}` : normalizedPath;
|
|
767
|
+
const url = new URL(this.options.baseUrl + fullPath);
|
|
768
|
+
if (params) {
|
|
769
|
+
for (const [key, value] of Object.entries(params)) {
|
|
770
|
+
if (value !== void 0 && value !== null)
|
|
771
|
+
url.searchParams.append(key, String(value));
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
const idempotencyKey = idempotencyKeyOption || (method !== "GET" ? crypto.randomUUID() : void 0);
|
|
775
|
+
const headers = {
|
|
776
|
+
"content-type": "application/json",
|
|
777
|
+
...this.options.headers,
|
|
778
|
+
...fetchOptions.headers,
|
|
779
|
+
...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
|
|
780
|
+
};
|
|
781
|
+
const isIdempotent = method === "GET" || method === "DELETE" || !!idempotencyKey;
|
|
782
|
+
const maxAttempts = isIdempotent ? this.options.maxRetries + 1 : 1;
|
|
783
|
+
let lastError;
|
|
784
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
785
|
+
const controller = new AbortController();
|
|
786
|
+
const timeout = setTimeout(() => controller.abort(), this.options.timeoutMs);
|
|
787
|
+
try {
|
|
788
|
+
const response = await fetch(url.toString(), {
|
|
789
|
+
...fetchOptions,
|
|
790
|
+
method,
|
|
791
|
+
headers,
|
|
792
|
+
body: body ? JSON.stringify(toSnakeCase(body)) : void 0,
|
|
793
|
+
signal: controller.signal
|
|
794
|
+
});
|
|
795
|
+
return await this._handleResponse(response);
|
|
796
|
+
} catch (error) {
|
|
797
|
+
lastError = error;
|
|
798
|
+
if (error instanceof RateLimitError) {
|
|
799
|
+
const backoff = backoffMs(attempt, error.retryAfter);
|
|
800
|
+
await sleep(backoff);
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
if (error instanceof LumnisError && (error.statusCode ?? 0) < 500)
|
|
804
|
+
throw error;
|
|
805
|
+
if (attempt < maxAttempts - 1) {
|
|
806
|
+
const backoff = backoffMs(attempt);
|
|
807
|
+
await sleep(backoff);
|
|
808
|
+
}
|
|
809
|
+
} finally {
|
|
810
|
+
clearTimeout(timeout);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
throw lastError || new LumnisError("Request failed after all retries", {});
|
|
814
|
+
}
|
|
815
|
+
get(path, options) {
|
|
816
|
+
return this.request(path, { ...options, method: "GET" });
|
|
817
|
+
}
|
|
818
|
+
post(path, body, options) {
|
|
819
|
+
return this.request(path, { ...options, method: "POST", body });
|
|
820
|
+
}
|
|
821
|
+
put(path, body, options) {
|
|
822
|
+
return this.request(path, { ...options, method: "PUT", body });
|
|
823
|
+
}
|
|
824
|
+
patch(path, body, options) {
|
|
825
|
+
return this.request(path, { ...options, method: "PATCH", body });
|
|
826
|
+
}
|
|
827
|
+
delete(path, options) {
|
|
828
|
+
return this.request(path, { ...options, method: "DELETE" });
|
|
829
|
+
}
|
|
830
|
+
async warnTenantScope() {
|
|
831
|
+
console.warn(
|
|
832
|
+
"Using TENANT scope bypasses user isolation. Ensure this is intentional and follows security best practices."
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function sleep(ms) {
|
|
837
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
838
|
+
}
|
|
839
|
+
function backoffMs(attempt, retryAfter = null) {
|
|
840
|
+
if (retryAfter) {
|
|
841
|
+
const retryAfterMs = Number(retryAfter) * 1e3;
|
|
842
|
+
if (!Number.isNaN(retryAfterMs))
|
|
843
|
+
return retryAfterMs;
|
|
844
|
+
}
|
|
845
|
+
const jitter = Math.random() * 500;
|
|
846
|
+
return Math.min(1e3 * 2 ** attempt, 1e4) + jitter;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
class LumnisClient {
|
|
850
|
+
http;
|
|
851
|
+
tenantId;
|
|
852
|
+
// Resources
|
|
853
|
+
threads;
|
|
854
|
+
responses;
|
|
855
|
+
users;
|
|
856
|
+
files;
|
|
857
|
+
tenantInfo;
|
|
858
|
+
externalApiKeys;
|
|
859
|
+
integrations;
|
|
860
|
+
modelPreferences;
|
|
861
|
+
mcpServers;
|
|
862
|
+
_scopedUserId;
|
|
863
|
+
_defaultScope;
|
|
864
|
+
constructor(options = {}) {
|
|
865
|
+
const apiKey = options.apiKey || typeof process !== "undefined" && process.env?.LUMNISAI_API_KEY;
|
|
866
|
+
if (!apiKey) {
|
|
867
|
+
throw new Error("API key is required. Provide it via options.apiKey or set LUMNISAI_API_KEY environment variable.");
|
|
868
|
+
}
|
|
869
|
+
this.tenantId = options.tenantId || typeof process !== "undefined" && process.env?.LUMNISAI_TENANT_ID || void 0;
|
|
870
|
+
const baseUrl = options.baseUrl || typeof process !== "undefined" && process.env?.LUMNISAI_BASE_URL || DEFAULT_BASE_URL;
|
|
871
|
+
this._defaultScope = options.scope || "tenant";
|
|
872
|
+
this._scopedUserId = options._scopedUserId;
|
|
873
|
+
this.http = new Http({
|
|
874
|
+
baseUrl,
|
|
875
|
+
apiPrefix: "/v1",
|
|
876
|
+
headers: {
|
|
877
|
+
"X-API-Key": apiKey
|
|
878
|
+
},
|
|
879
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
880
|
+
maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES
|
|
881
|
+
});
|
|
882
|
+
this.threads = new ThreadsResource(this.http);
|
|
883
|
+
this.responses = new ResponsesResource(this.http);
|
|
884
|
+
this.users = new UsersResource(this.http);
|
|
885
|
+
this.files = new FilesResource(this.http);
|
|
886
|
+
this.tenantInfo = new TenantInfoResource(this.http);
|
|
887
|
+
this.externalApiKeys = new ExternalAPIKeysResource(this.http);
|
|
888
|
+
this.integrations = new IntegrationsResource(this.http);
|
|
889
|
+
this.modelPreferences = new ModelPreferencesResource(this.http);
|
|
890
|
+
this.mcpServers = new MCPServersResource(this.http);
|
|
891
|
+
}
|
|
892
|
+
forUser(userId) {
|
|
893
|
+
return new LumnisClient({
|
|
894
|
+
apiKey: this.http.options.headers["X-API-Key"],
|
|
895
|
+
tenantId: this.tenantId,
|
|
896
|
+
baseUrl: this.http.options.baseUrl,
|
|
897
|
+
timeoutMs: this.http.options.timeoutMs,
|
|
898
|
+
maxRetries: this.http.options.maxRetries,
|
|
899
|
+
scope: "user",
|
|
900
|
+
_scopedUserId: userId
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
async invoke(messages, options) {
|
|
904
|
+
const { stream = false, showProgress = true, ...restOptions } = options || {};
|
|
905
|
+
if (stream) {
|
|
906
|
+
if (showProgress)
|
|
907
|
+
console.warn("showProgress is not supported in streaming mode.");
|
|
908
|
+
return this._invokeStream(messages, restOptions);
|
|
909
|
+
} else {
|
|
910
|
+
let progressCallback;
|
|
911
|
+
if (showProgress)
|
|
912
|
+
progressCallback = createSimpleProgressCallback();
|
|
913
|
+
return this._invokeAndWait(messages, restOptions, progressCallback);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
async *_invokeStream(messages, options) {
|
|
917
|
+
const response = await this._createResponse(messages, options);
|
|
918
|
+
console.log(`Response ID: ${response.responseId}`);
|
|
919
|
+
let lastMessageCount = 0;
|
|
920
|
+
while (true) {
|
|
921
|
+
const current = await this.responses.get(response.responseId, { wait: LONG_POLL_TIMEOUT_S });
|
|
922
|
+
const currentMessageCount = current.progress?.length || 0;
|
|
923
|
+
if (currentMessageCount > lastMessageCount && current.progress) {
|
|
924
|
+
for (let i = lastMessageCount; i < currentMessageCount; i++)
|
|
925
|
+
yield current.progress[i];
|
|
926
|
+
lastMessageCount = currentMessageCount;
|
|
927
|
+
}
|
|
928
|
+
if (current.status === "succeeded" || current.status === "failed" || current.status === "cancelled") {
|
|
929
|
+
if (current.status === "succeeded" && current.outputText) {
|
|
930
|
+
const progressEntry = {
|
|
931
|
+
ts: current.completedAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
932
|
+
state: "completed",
|
|
933
|
+
message: "Task completed successfully",
|
|
934
|
+
outputText: current.outputText
|
|
935
|
+
};
|
|
936
|
+
yield progressEntry;
|
|
937
|
+
}
|
|
938
|
+
break;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
async _invokeAndWait(messages, options, progressCallback) {
|
|
943
|
+
const { pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, maxWaitMs = 3e5, ...createOptions } = options || {};
|
|
944
|
+
const response = await this._createResponse(messages, createOptions);
|
|
945
|
+
if (!progressCallback)
|
|
946
|
+
console.log(`Response ID: ${response.responseId}`);
|
|
947
|
+
const startTime = Date.now();
|
|
948
|
+
while (true) {
|
|
949
|
+
const current = await this.responses.get(response.responseId, { wait: LONG_POLL_TIMEOUT_S });
|
|
950
|
+
if (progressCallback)
|
|
951
|
+
progressCallback(current);
|
|
952
|
+
if (current.status === "succeeded" || current.status === "failed" || current.status === "cancelled")
|
|
953
|
+
return current;
|
|
954
|
+
if (Date.now() - startTime > maxWaitMs)
|
|
955
|
+
throw new Error(`Response ${response.responseId} timed out after ${maxWaitMs}ms`);
|
|
956
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
async _createResponse(messages, options) {
|
|
960
|
+
const { scope: optionScope, userId: optionUserId, ...restOptions } = options;
|
|
961
|
+
const effectiveUserId = optionUserId || this._scopedUserId;
|
|
962
|
+
let scope = optionScope || this._defaultScope;
|
|
963
|
+
if (effectiveUserId && scope === "tenant")
|
|
964
|
+
scope = "user";
|
|
965
|
+
if (scope === "user" && !effectiveUserId)
|
|
966
|
+
throw new Error("user_id is required for user scope");
|
|
967
|
+
if (scope === "tenant")
|
|
968
|
+
await this.http.warnTenantScope();
|
|
969
|
+
let messageArray;
|
|
970
|
+
if (typeof messages === "string")
|
|
971
|
+
messageArray = [{ role: "user", content: messages }];
|
|
972
|
+
else if (Array.isArray(messages))
|
|
973
|
+
messageArray = messages;
|
|
974
|
+
else
|
|
975
|
+
messageArray = [messages];
|
|
976
|
+
return this.responses.create({
|
|
977
|
+
messages: messageArray,
|
|
978
|
+
userId: effectiveUserId,
|
|
979
|
+
...restOptions
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
// Thread methods
|
|
983
|
+
async listThreads(params) {
|
|
984
|
+
return this.threads.list(params);
|
|
985
|
+
}
|
|
986
|
+
async createThread(params) {
|
|
987
|
+
return this.threads.create(params);
|
|
988
|
+
}
|
|
989
|
+
async getThread(threadId) {
|
|
990
|
+
return this.threads.get(threadId);
|
|
991
|
+
}
|
|
992
|
+
async deleteThread(threadId) {
|
|
993
|
+
return this.threads.delete(threadId);
|
|
994
|
+
}
|
|
995
|
+
// User methods
|
|
996
|
+
async createUser(params) {
|
|
997
|
+
return this.users.create(params);
|
|
998
|
+
}
|
|
999
|
+
async getUser(userId) {
|
|
1000
|
+
return this.users.get(userId);
|
|
1001
|
+
}
|
|
1002
|
+
async updateUser(userId, params) {
|
|
1003
|
+
return this.users.update(userId, params);
|
|
1004
|
+
}
|
|
1005
|
+
async deleteUser(userId) {
|
|
1006
|
+
return this.users.delete(userId);
|
|
1007
|
+
}
|
|
1008
|
+
async listUsers(params) {
|
|
1009
|
+
return this.users.list(params);
|
|
1010
|
+
}
|
|
1011
|
+
// External API Key methods
|
|
1012
|
+
async addApiKey(params) {
|
|
1013
|
+
return this.externalApiKeys.create(params);
|
|
1014
|
+
}
|
|
1015
|
+
async listApiKeys() {
|
|
1016
|
+
return this.externalApiKeys.list();
|
|
1017
|
+
}
|
|
1018
|
+
async getApiKey(keyId) {
|
|
1019
|
+
return this.externalApiKeys.get(keyId);
|
|
1020
|
+
}
|
|
1021
|
+
async deleteApiKey(provider) {
|
|
1022
|
+
return this.externalApiKeys.delete(provider);
|
|
1023
|
+
}
|
|
1024
|
+
async getApiKeyMode() {
|
|
1025
|
+
return this.externalApiKeys.getMode();
|
|
1026
|
+
}
|
|
1027
|
+
async setApiKeyMode(mode) {
|
|
1028
|
+
return this.externalApiKeys.setMode(mode);
|
|
1029
|
+
}
|
|
1030
|
+
// Integration methods
|
|
1031
|
+
async listApps(params) {
|
|
1032
|
+
return this.integrations.listApps(params);
|
|
1033
|
+
}
|
|
1034
|
+
async isAppEnabled(appName) {
|
|
1035
|
+
return this.integrations.isAppEnabled(appName);
|
|
1036
|
+
}
|
|
1037
|
+
async setAppEnabled(appName, enabled) {
|
|
1038
|
+
return this.integrations.setAppEnabled(appName, { enabled });
|
|
1039
|
+
}
|
|
1040
|
+
async initiateConnection(params) {
|
|
1041
|
+
return this.integrations.initiateConnection(params);
|
|
1042
|
+
}
|
|
1043
|
+
async getConnectionStatus(userId, appName) {
|
|
1044
|
+
return this.integrations.getConnectionStatus(userId, appName);
|
|
1045
|
+
}
|
|
1046
|
+
async listConnections(userId, params) {
|
|
1047
|
+
return this.integrations.listConnections(userId, params);
|
|
1048
|
+
}
|
|
1049
|
+
async getIntegrationTools(userId, params) {
|
|
1050
|
+
return this.integrations.getTools({ userId, appFilter: params?.appFilter });
|
|
1051
|
+
}
|
|
1052
|
+
// Model Preference methods
|
|
1053
|
+
async getModelPreferences(params) {
|
|
1054
|
+
return this.modelPreferences.list(params);
|
|
1055
|
+
}
|
|
1056
|
+
async updateModelPreferences(params) {
|
|
1057
|
+
return this.modelPreferences.updateBulk(params);
|
|
1058
|
+
}
|
|
1059
|
+
// MCP Server methods
|
|
1060
|
+
async createMcpServer(params) {
|
|
1061
|
+
return this.mcpServers.create(params);
|
|
1062
|
+
}
|
|
1063
|
+
async getMcpServer(serverId) {
|
|
1064
|
+
return this.mcpServers.get(serverId);
|
|
1065
|
+
}
|
|
1066
|
+
async listMcpServers(params) {
|
|
1067
|
+
return this.mcpServers.list(params);
|
|
1068
|
+
}
|
|
1069
|
+
async updateMcpServer(serverId, params) {
|
|
1070
|
+
return this.mcpServers.update(serverId, params);
|
|
1071
|
+
}
|
|
1072
|
+
async deleteMcpServer(serverId) {
|
|
1073
|
+
return this.mcpServers.delete(serverId);
|
|
1074
|
+
}
|
|
1075
|
+
async listMcpServerTools(serverId) {
|
|
1076
|
+
return this.mcpServers.listTools(serverId);
|
|
1077
|
+
}
|
|
1078
|
+
async testMcpServer(serverId) {
|
|
1079
|
+
return this.mcpServers.testConnection(serverId);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
function createSimpleProgressCallback() {
|
|
1083
|
+
let lastStatus;
|
|
1084
|
+
const seenMessages = /* @__PURE__ */ new Set();
|
|
1085
|
+
return (response) => {
|
|
1086
|
+
if (response.status !== lastStatus) {
|
|
1087
|
+
console.log(`Status: ${response.status}`);
|
|
1088
|
+
lastStatus = response.status;
|
|
1089
|
+
}
|
|
1090
|
+
if (response.progress) {
|
|
1091
|
+
for (const entry of response.progress) {
|
|
1092
|
+
const messageKey = `${entry.state}:${entry.message}`;
|
|
1093
|
+
if (!seenMessages.has(messageKey)) {
|
|
1094
|
+
console.log(`${entry.state.toUpperCase()}: ${entry.message}`);
|
|
1095
|
+
seenMessages.add(messageKey);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
exports.AuthenticationError = AuthenticationError;
|
|
1103
|
+
exports.InternalServerError = InternalServerError;
|
|
1104
|
+
exports.LocalFileNotSupportedError = LocalFileNotSupportedError;
|
|
1105
|
+
exports.LumnisClient = LumnisClient;
|
|
1106
|
+
exports.LumnisError = LumnisError;
|
|
1107
|
+
exports.NotFoundError = NotFoundError;
|
|
1108
|
+
exports.RateLimitError = RateLimitError;
|
|
1109
|
+
exports.ValidationError = ValidationError;
|
|
1110
|
+
exports.default = LumnisClient;
|