@mnexium/sdk 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 +21 -0
- package/README.md +401 -0
- package/dist/index.d.mts +944 -0
- package/dist/index.d.ts +944 -0
- package/dist/index.js +1110 -0
- package/dist/index.mjs +1074 -0
- package/package.json +67 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
APIError: () => APIError,
|
|
24
|
+
AuthenticationError: () => AuthenticationError,
|
|
25
|
+
Chat: () => Chat,
|
|
26
|
+
ChatSession: () => Chat,
|
|
27
|
+
EventStream: () => EventStream,
|
|
28
|
+
Mnexium: () => Mnexium,
|
|
29
|
+
MnexiumError: () => MnexiumError,
|
|
30
|
+
RateLimitError: () => RateLimitError,
|
|
31
|
+
StreamResponse: () => StreamResponse,
|
|
32
|
+
Subject: () => Subject
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
|
|
36
|
+
// src/errors.ts
|
|
37
|
+
var MnexiumError = class extends Error {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = "MnexiumError";
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var AuthenticationError = class extends MnexiumError {
|
|
44
|
+
constructor(message = "Authentication failed") {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "AuthenticationError";
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var RateLimitError = class extends MnexiumError {
|
|
50
|
+
constructor(message = "Rate limit exceeded", options) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = "RateLimitError";
|
|
53
|
+
this.retryAfter = options?.retryAfter;
|
|
54
|
+
this.current = options?.current;
|
|
55
|
+
this.limit = options?.limit;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var APIError = class extends MnexiumError {
|
|
59
|
+
constructor(message, status, code) {
|
|
60
|
+
super(message);
|
|
61
|
+
this.name = "APIError";
|
|
62
|
+
this.status = status;
|
|
63
|
+
this.code = code;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var NotFoundError = class extends APIError {
|
|
67
|
+
constructor(message = "Resource not found") {
|
|
68
|
+
super(message, 404, "not_found");
|
|
69
|
+
this.name = "NotFoundError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// src/chat.ts
|
|
74
|
+
var Chat = class {
|
|
75
|
+
constructor(client, subjectId, options = {}) {
|
|
76
|
+
this.client = client;
|
|
77
|
+
this.subjectId = subjectId;
|
|
78
|
+
this.id = options.chatId || crypto.randomUUID();
|
|
79
|
+
this.options = options;
|
|
80
|
+
}
|
|
81
|
+
async process(input) {
|
|
82
|
+
const options = typeof input === "string" ? { content: input } : input;
|
|
83
|
+
return this.client.process({
|
|
84
|
+
content: options.content,
|
|
85
|
+
chatId: this.id,
|
|
86
|
+
subjectId: this.subjectId,
|
|
87
|
+
model: options.model ?? this.options.model,
|
|
88
|
+
log: options.log ?? this.options.log,
|
|
89
|
+
learn: options.learn ?? this.options.learn,
|
|
90
|
+
recall: options.recall ?? this.options.recall,
|
|
91
|
+
profile: options.profile ?? this.options.profile,
|
|
92
|
+
history: options.history ?? this.options.history,
|
|
93
|
+
summarize: options.summarize ?? this.options.summarize,
|
|
94
|
+
systemPrompt: options.systemPrompt ?? this.options.systemPrompt,
|
|
95
|
+
maxTokens: options.maxTokens ?? this.options.maxTokens,
|
|
96
|
+
temperature: options.temperature ?? this.options.temperature,
|
|
97
|
+
stream: options.stream,
|
|
98
|
+
metadata: options.metadata ?? this.options.metadata,
|
|
99
|
+
regenerateKey: options.regenerateKey
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// src/events.ts
|
|
105
|
+
var EventStream = class {
|
|
106
|
+
constructor(client, subjectId, options) {
|
|
107
|
+
this.client = client;
|
|
108
|
+
this.subjectId = subjectId;
|
|
109
|
+
this.reader = null;
|
|
110
|
+
this.decoder = new TextDecoder();
|
|
111
|
+
this.connected = false;
|
|
112
|
+
this.abortController = new AbortController();
|
|
113
|
+
if (options?.signal) {
|
|
114
|
+
options.signal.addEventListener("abort", () => this.close());
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async *[Symbol.asyncIterator]() {
|
|
118
|
+
const response = await this.client._requestRaw("GET", "/events/memories", {
|
|
119
|
+
query: { subject_id: this.subjectId }
|
|
120
|
+
});
|
|
121
|
+
if (!response.body) {
|
|
122
|
+
throw new Error("Response body is null \u2014 SSE not supported");
|
|
123
|
+
}
|
|
124
|
+
this.reader = response.body.getReader();
|
|
125
|
+
this.connected = true;
|
|
126
|
+
let buffer = "";
|
|
127
|
+
let currentEvent = "";
|
|
128
|
+
try {
|
|
129
|
+
while (true) {
|
|
130
|
+
const { value, done } = await this.reader.read();
|
|
131
|
+
if (done) break;
|
|
132
|
+
buffer += this.decoder.decode(value, { stream: true });
|
|
133
|
+
const lines = buffer.split("\n");
|
|
134
|
+
buffer = lines.pop() ?? "";
|
|
135
|
+
for (const line of lines) {
|
|
136
|
+
const trimmed = line.trim();
|
|
137
|
+
if (trimmed.startsWith("event:")) {
|
|
138
|
+
currentEvent = trimmed.slice(6).trim();
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (trimmed.startsWith("data:")) {
|
|
142
|
+
const data = trimmed.slice(5).trim();
|
|
143
|
+
if (!data) continue;
|
|
144
|
+
try {
|
|
145
|
+
const parsed = JSON.parse(data);
|
|
146
|
+
const eventType = currentEvent || "unknown";
|
|
147
|
+
currentEvent = "";
|
|
148
|
+
yield {
|
|
149
|
+
type: eventType,
|
|
150
|
+
data: parsed
|
|
151
|
+
};
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (trimmed === "") {
|
|
156
|
+
currentEvent = "";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} finally {
|
|
161
|
+
this.connected = false;
|
|
162
|
+
if (this.reader) {
|
|
163
|
+
this.reader.releaseLock();
|
|
164
|
+
this.reader = null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** Close the event stream */
|
|
169
|
+
close() {
|
|
170
|
+
this.abortController.abort();
|
|
171
|
+
if (this.reader) {
|
|
172
|
+
this.reader.cancel().catch(() => {
|
|
173
|
+
});
|
|
174
|
+
this.reader = null;
|
|
175
|
+
}
|
|
176
|
+
this.connected = false;
|
|
177
|
+
}
|
|
178
|
+
/** Whether the stream is currently connected */
|
|
179
|
+
get isConnected() {
|
|
180
|
+
return this.connected;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/subject.ts
|
|
185
|
+
var SubjectMemoriesResource = class {
|
|
186
|
+
constructor(client, subjectId) {
|
|
187
|
+
this.client = client;
|
|
188
|
+
this.subjectId = subjectId;
|
|
189
|
+
}
|
|
190
|
+
async search(query, options) {
|
|
191
|
+
const response = await this.client._request("GET", "/memories/search", {
|
|
192
|
+
query: {
|
|
193
|
+
subject_id: this.subjectId,
|
|
194
|
+
q: query,
|
|
195
|
+
limit: options?.limit,
|
|
196
|
+
min_score: options?.minScore
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return response.data || [];
|
|
200
|
+
}
|
|
201
|
+
async add(text, options) {
|
|
202
|
+
return this.client._request("POST", "/memories", {
|
|
203
|
+
body: {
|
|
204
|
+
subject_id: this.subjectId,
|
|
205
|
+
text,
|
|
206
|
+
source: options?.source,
|
|
207
|
+
visibility: options?.visibility,
|
|
208
|
+
metadata: options?.metadata
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async list(options) {
|
|
213
|
+
const response = await this.client._request("GET", "/memories", {
|
|
214
|
+
query: {
|
|
215
|
+
subject_id: this.subjectId,
|
|
216
|
+
limit: options?.limit,
|
|
217
|
+
offset: options?.offset
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
return response.data || [];
|
|
221
|
+
}
|
|
222
|
+
async get(memoryId) {
|
|
223
|
+
return this.client._request("GET", `/memories/${memoryId}`);
|
|
224
|
+
}
|
|
225
|
+
async update(memoryId, updates) {
|
|
226
|
+
return this.client._request("PATCH", `/memories/${memoryId}`, {
|
|
227
|
+
body: updates
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
async delete(memoryId) {
|
|
231
|
+
await this.client._request("DELETE", `/memories/${memoryId}`);
|
|
232
|
+
}
|
|
233
|
+
async superseded(options) {
|
|
234
|
+
const response = await this.client._request("GET", "/memories/superseded", {
|
|
235
|
+
query: {
|
|
236
|
+
subject_id: this.subjectId,
|
|
237
|
+
limit: options?.limit,
|
|
238
|
+
offset: options?.offset
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
return response.data || [];
|
|
242
|
+
}
|
|
243
|
+
async restore(memoryId) {
|
|
244
|
+
return this.client._request("POST", `/memories/${memoryId}/restore`);
|
|
245
|
+
}
|
|
246
|
+
async recalls(options) {
|
|
247
|
+
const response = await this.client._request("GET", "/memories/recalls", {
|
|
248
|
+
query: {
|
|
249
|
+
chat_id: options.chatId,
|
|
250
|
+
memory_id: options.memoryId
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
return response.data || [];
|
|
254
|
+
}
|
|
255
|
+
subscribe(options) {
|
|
256
|
+
return new EventStream(this.client, this.subjectId, options);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
var SubjectProfileResource = class {
|
|
260
|
+
constructor(client, subjectId) {
|
|
261
|
+
this.client = client;
|
|
262
|
+
this.subjectId = subjectId;
|
|
263
|
+
}
|
|
264
|
+
async get() {
|
|
265
|
+
return this.client._request("GET", "/profiles", {
|
|
266
|
+
query: { subject_id: this.subjectId }
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
async update(updates) {
|
|
270
|
+
return this.client._request("PATCH", "/profiles", {
|
|
271
|
+
body: {
|
|
272
|
+
subject_id: this.subjectId,
|
|
273
|
+
updates
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
async deleteField(fieldKey) {
|
|
278
|
+
await this.client._request("DELETE", "/profiles", {
|
|
279
|
+
body: {
|
|
280
|
+
subject_id: this.subjectId,
|
|
281
|
+
field_key: fieldKey
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
var SubjectStateResource = class {
|
|
287
|
+
constructor(client, subjectId) {
|
|
288
|
+
this.client = client;
|
|
289
|
+
this.subjectId = subjectId;
|
|
290
|
+
}
|
|
291
|
+
async get(key) {
|
|
292
|
+
try {
|
|
293
|
+
return await this.client._request("GET", `/state/${key}`, {
|
|
294
|
+
headers: { "x-subject-id": this.subjectId }
|
|
295
|
+
});
|
|
296
|
+
} catch (error) {
|
|
297
|
+
if (error?.status === 404) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async set(key, value, options) {
|
|
304
|
+
return this.client._request("PUT", `/state/${key}`, {
|
|
305
|
+
headers: { "x-subject-id": this.subjectId },
|
|
306
|
+
body: {
|
|
307
|
+
value,
|
|
308
|
+
ttl_seconds: options?.ttlSeconds
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
async delete(key) {
|
|
313
|
+
await this.client._request("DELETE", `/state/${key}`, {
|
|
314
|
+
headers: { "x-subject-id": this.subjectId }
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var SubjectClaimsResource = class {
|
|
319
|
+
constructor(client, subjectId) {
|
|
320
|
+
this.client = client;
|
|
321
|
+
this.subjectId = subjectId;
|
|
322
|
+
}
|
|
323
|
+
async get(slot) {
|
|
324
|
+
try {
|
|
325
|
+
return await this.client._request("GET", `/claims/subject/${this.subjectId}/slot/${slot}`);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (error?.status === 404) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async set(predicate, value, options) {
|
|
334
|
+
return this.client._request("POST", "/claims", {
|
|
335
|
+
body: {
|
|
336
|
+
subject_id: this.subjectId,
|
|
337
|
+
predicate,
|
|
338
|
+
object_value: value,
|
|
339
|
+
confidence: options?.confidence,
|
|
340
|
+
source_type: options?.source
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
async list() {
|
|
345
|
+
return this.client._request("GET", `/claims/subject/${this.subjectId}/slots`);
|
|
346
|
+
}
|
|
347
|
+
async truth() {
|
|
348
|
+
return this.client._request("GET", `/claims/subject/${this.subjectId}/truth`);
|
|
349
|
+
}
|
|
350
|
+
async history() {
|
|
351
|
+
const response = await this.client._request("GET", `/claims/subject/${this.subjectId}/history`);
|
|
352
|
+
return response.data || response.claims || [];
|
|
353
|
+
}
|
|
354
|
+
async retract(claimId) {
|
|
355
|
+
return this.client._request("POST", `/claims/${claimId}/retract`);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
var SubjectChatsResource = class {
|
|
359
|
+
constructor(client, subjectId) {
|
|
360
|
+
this.client = client;
|
|
361
|
+
this.subjectId = subjectId;
|
|
362
|
+
}
|
|
363
|
+
async list(options) {
|
|
364
|
+
const response = await this.client._request("GET", "/chat/history/list", {
|
|
365
|
+
query: {
|
|
366
|
+
subject_id: this.subjectId,
|
|
367
|
+
limit: options?.limit,
|
|
368
|
+
offset: options?.offset
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
return response.chats;
|
|
372
|
+
}
|
|
373
|
+
async read(chatId) {
|
|
374
|
+
const response = await this.client._request("GET", "/chat/history/read", {
|
|
375
|
+
query: {
|
|
376
|
+
subject_id: this.subjectId,
|
|
377
|
+
chat_id: chatId
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
return response.data || [];
|
|
381
|
+
}
|
|
382
|
+
async delete(chatId) {
|
|
383
|
+
await this.client._request("DELETE", "/chat/history/delete", {
|
|
384
|
+
query: {
|
|
385
|
+
subject_id: this.subjectId,
|
|
386
|
+
chat_id: chatId
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
var Subject = class {
|
|
392
|
+
constructor(client, subjectId) {
|
|
393
|
+
this.client = client;
|
|
394
|
+
this.id = subjectId;
|
|
395
|
+
this.memories = new SubjectMemoriesResource(client, subjectId);
|
|
396
|
+
this.profile = new SubjectProfileResource(client, subjectId);
|
|
397
|
+
this.state = new SubjectStateResource(client, subjectId);
|
|
398
|
+
this.claims = new SubjectClaimsResource(client, subjectId);
|
|
399
|
+
this.chats = new SubjectChatsResource(client, subjectId);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Process a message with an ephemeral chat (no persistent chatId)
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* const response = await alice.process("What's my favorite color?");
|
|
406
|
+
*/
|
|
407
|
+
async process(input) {
|
|
408
|
+
const options = typeof input === "string" ? { content: input } : input;
|
|
409
|
+
return this.client.process({
|
|
410
|
+
...options,
|
|
411
|
+
subjectId: this.id
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Create a chat session for multi-turn conversation
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* const chat = alice.createChat({ history: true });
|
|
419
|
+
* await chat.process("Hello!");
|
|
420
|
+
* await chat.process("What did I just say?");
|
|
421
|
+
*/
|
|
422
|
+
createChat(options) {
|
|
423
|
+
return this.client.createChat(this, options);
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// src/providers.ts
|
|
428
|
+
function detectProvider(model) {
|
|
429
|
+
const lowerModel = model.toLowerCase();
|
|
430
|
+
if (lowerModel.includes("claude")) {
|
|
431
|
+
return "anthropic";
|
|
432
|
+
}
|
|
433
|
+
if (lowerModel.includes("gemini") || lowerModel.includes("palm")) {
|
|
434
|
+
return "google";
|
|
435
|
+
}
|
|
436
|
+
if (lowerModel.includes("gpt") || lowerModel.includes("o1") || lowerModel.includes("o3") || lowerModel.includes("davinci")) {
|
|
437
|
+
return "openai";
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
function extractResponseContent(raw) {
|
|
442
|
+
if (raw.content && Array.isArray(raw.content)) {
|
|
443
|
+
let content = "";
|
|
444
|
+
for (const block of raw.content) {
|
|
445
|
+
if (block.type === "text") {
|
|
446
|
+
content += block.text || "";
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return {
|
|
450
|
+
content,
|
|
451
|
+
usage: raw.usage ? {
|
|
452
|
+
prompt_tokens: raw.usage.input_tokens || 0,
|
|
453
|
+
completion_tokens: raw.usage.output_tokens || 0,
|
|
454
|
+
total_tokens: (raw.usage.input_tokens || 0) + (raw.usage.output_tokens || 0)
|
|
455
|
+
} : null
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
if (raw.candidates && Array.isArray(raw.candidates)) {
|
|
459
|
+
let content = "";
|
|
460
|
+
const parts = raw.candidates[0]?.content?.parts || [];
|
|
461
|
+
for (const part of parts) {
|
|
462
|
+
if (part.text) {
|
|
463
|
+
content += part.text;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
content,
|
|
468
|
+
usage: raw.usageMetadata ? {
|
|
469
|
+
prompt_tokens: raw.usageMetadata.promptTokenCount || 0,
|
|
470
|
+
completion_tokens: raw.usageMetadata.candidatesTokenCount || 0,
|
|
471
|
+
total_tokens: raw.usageMetadata.totalTokenCount || 0
|
|
472
|
+
} : null
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
return {
|
|
476
|
+
content: raw.choices?.[0]?.message?.content || "",
|
|
477
|
+
usage: raw.usage || null
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/streaming.ts
|
|
482
|
+
var StreamResponse = class {
|
|
483
|
+
constructor(response, metadata) {
|
|
484
|
+
/** The full accumulated content after streaming completes */
|
|
485
|
+
this.totalContent = "";
|
|
486
|
+
this.consumed = false;
|
|
487
|
+
if (!response.body) {
|
|
488
|
+
throw new Error("Response body is null \u2014 streaming not supported");
|
|
489
|
+
}
|
|
490
|
+
this.reader = response.body.getReader();
|
|
491
|
+
this.decoder = new TextDecoder();
|
|
492
|
+
this.chatId = metadata.chatId;
|
|
493
|
+
this.subjectId = metadata.subjectId;
|
|
494
|
+
this.model = metadata.model;
|
|
495
|
+
this.provisionedKey = metadata.provisionedKey;
|
|
496
|
+
this.claimUrl = metadata.claimUrl;
|
|
497
|
+
}
|
|
498
|
+
async *[Symbol.asyncIterator]() {
|
|
499
|
+
if (this.consumed) {
|
|
500
|
+
throw new Error("StreamResponse has already been consumed");
|
|
501
|
+
}
|
|
502
|
+
this.consumed = true;
|
|
503
|
+
let buffer = "";
|
|
504
|
+
try {
|
|
505
|
+
while (true) {
|
|
506
|
+
const { value, done } = await this.reader.read();
|
|
507
|
+
if (done) break;
|
|
508
|
+
buffer += this.decoder.decode(value, { stream: true });
|
|
509
|
+
const lines = buffer.split("\n");
|
|
510
|
+
buffer = lines.pop() ?? "";
|
|
511
|
+
for (const line of lines) {
|
|
512
|
+
const trimmed = line.trim();
|
|
513
|
+
if (trimmed.startsWith("event:") || !trimmed.startsWith("data:")) continue;
|
|
514
|
+
const data = trimmed.slice(5).trim();
|
|
515
|
+
if (!data || data === "[DONE]") continue;
|
|
516
|
+
try {
|
|
517
|
+
const json = JSON.parse(data);
|
|
518
|
+
const chunk = this._extractChunk(json);
|
|
519
|
+
if (chunk) {
|
|
520
|
+
this.totalContent += chunk.content;
|
|
521
|
+
yield chunk;
|
|
522
|
+
}
|
|
523
|
+
this._extractUsage(json);
|
|
524
|
+
} catch {
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
} finally {
|
|
529
|
+
this.reader.releaseLock();
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Convenience: collect the full response as a string.
|
|
534
|
+
* Consumes the stream if not already consumed.
|
|
535
|
+
*/
|
|
536
|
+
async text() {
|
|
537
|
+
if (!this.consumed) {
|
|
538
|
+
for await (const _ of this) {
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return this.totalContent;
|
|
542
|
+
}
|
|
543
|
+
_extractChunk(json) {
|
|
544
|
+
const delta = json?.choices?.[0]?.delta;
|
|
545
|
+
if (delta?.content) {
|
|
546
|
+
return { content: delta.content, raw: json };
|
|
547
|
+
}
|
|
548
|
+
if (json?.type === "content_block_delta" && json?.delta?.type === "text_delta") {
|
|
549
|
+
return { content: json.delta.text || "", raw: json };
|
|
550
|
+
}
|
|
551
|
+
const parts = json?.candidates?.[0]?.content?.parts;
|
|
552
|
+
if (Array.isArray(parts)) {
|
|
553
|
+
const text = parts.map((p) => p.text || "").join("");
|
|
554
|
+
if (text) {
|
|
555
|
+
return { content: text, raw: json };
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
_extractUsage(json) {
|
|
561
|
+
if (json?.usage) {
|
|
562
|
+
this.usage = {
|
|
563
|
+
promptTokens: json.usage.prompt_tokens || 0,
|
|
564
|
+
completionTokens: json.usage.completion_tokens || 0,
|
|
565
|
+
totalTokens: json.usage.total_tokens || 0
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
if (json?.type === "message_delta" && json?.usage) {
|
|
569
|
+
this.usage = {
|
|
570
|
+
promptTokens: json.usage.input_tokens || 0,
|
|
571
|
+
completionTokens: json.usage.output_tokens || 0,
|
|
572
|
+
totalTokens: (json.usage.input_tokens || 0) + (json.usage.output_tokens || 0)
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
if (json?.usageMetadata) {
|
|
576
|
+
this.usage = {
|
|
577
|
+
promptTokens: json.usageMetadata.promptTokenCount || 0,
|
|
578
|
+
completionTokens: json.usageMetadata.candidatesTokenCount || 0,
|
|
579
|
+
totalTokens: json.usageMetadata.totalTokenCount || 0
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
// src/resources/chat.ts
|
|
586
|
+
var ChatResource = class {
|
|
587
|
+
constructor(client) {
|
|
588
|
+
this.completions = new ChatCompletionsResource(client);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
var ChatCompletionsResource = class {
|
|
592
|
+
constructor(client) {
|
|
593
|
+
this.client = client;
|
|
594
|
+
}
|
|
595
|
+
async create(options) {
|
|
596
|
+
const headers = {};
|
|
597
|
+
if (options.openaiKey) {
|
|
598
|
+
headers["x-openai-key"] = options.openaiKey;
|
|
599
|
+
} else if (options.anthropicKey) {
|
|
600
|
+
headers["x-anthropic-key"] = options.anthropicKey;
|
|
601
|
+
} else if (options.googleKey) {
|
|
602
|
+
headers["x-google-key"] = options.googleKey;
|
|
603
|
+
}
|
|
604
|
+
const body = {
|
|
605
|
+
model: options.model,
|
|
606
|
+
messages: options.messages,
|
|
607
|
+
stream: options.stream || false,
|
|
608
|
+
max_tokens: options.maxTokens,
|
|
609
|
+
temperature: options.temperature,
|
|
610
|
+
top_p: options.topP,
|
|
611
|
+
stop: options.stop,
|
|
612
|
+
mnx: {
|
|
613
|
+
subject_id: options.subjectId,
|
|
614
|
+
chat_id: options.chatId,
|
|
615
|
+
learn: options.learn,
|
|
616
|
+
recall: options.recall,
|
|
617
|
+
history: options.history,
|
|
618
|
+
log: options.log,
|
|
619
|
+
state: options.state,
|
|
620
|
+
system_prompt: options.systemPrompt,
|
|
621
|
+
metadata: options.metadata,
|
|
622
|
+
regenerate_key: options.regenerateKey
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
return this.client._request("POST", "/chat/completions", {
|
|
626
|
+
body,
|
|
627
|
+
headers
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
// src/resources/memories.ts
|
|
633
|
+
var MemoriesResource = class {
|
|
634
|
+
constructor(client) {
|
|
635
|
+
this.client = client;
|
|
636
|
+
}
|
|
637
|
+
async create(options) {
|
|
638
|
+
return this.client._request("POST", "/memories", {
|
|
639
|
+
body: {
|
|
640
|
+
subject_id: options.subjectId,
|
|
641
|
+
text: options.text,
|
|
642
|
+
source: options.source,
|
|
643
|
+
visibility: options.visibility,
|
|
644
|
+
metadata: options.metadata
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
async get(id) {
|
|
649
|
+
return this.client._request("GET", `/memories/${id}`);
|
|
650
|
+
}
|
|
651
|
+
async list(subjectId, options) {
|
|
652
|
+
const response = await this.client._request("GET", "/memories", {
|
|
653
|
+
query: {
|
|
654
|
+
subject_id: subjectId,
|
|
655
|
+
limit: options?.limit,
|
|
656
|
+
offset: options?.offset
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
return response.memories;
|
|
660
|
+
}
|
|
661
|
+
async search(options) {
|
|
662
|
+
const response = await this.client._request("POST", "/memories/search", {
|
|
663
|
+
body: {
|
|
664
|
+
subject_id: options.subjectId,
|
|
665
|
+
query: options.query,
|
|
666
|
+
limit: options.limit,
|
|
667
|
+
min_score: options.minScore,
|
|
668
|
+
include_deleted: options.includeDeleted,
|
|
669
|
+
include_superseded: options.includeSuperseded
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
return response.results;
|
|
673
|
+
}
|
|
674
|
+
async delete(id) {
|
|
675
|
+
await this.client._request("DELETE", `/memories/${id}`);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
// src/resources/claims.ts
|
|
680
|
+
var ClaimsResource = class {
|
|
681
|
+
constructor(client) {
|
|
682
|
+
this.client = client;
|
|
683
|
+
}
|
|
684
|
+
async create(options) {
|
|
685
|
+
return this.client._request("POST", "/claims", {
|
|
686
|
+
body: {
|
|
687
|
+
subject_id: options.subjectId,
|
|
688
|
+
slot: options.slot,
|
|
689
|
+
value: options.value,
|
|
690
|
+
confidence: options.confidence,
|
|
691
|
+
source: options.source,
|
|
692
|
+
source_memory_id: options.sourceMemoryId
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
async get(id) {
|
|
697
|
+
return this.client._request("GET", `/claims/${id}`);
|
|
698
|
+
}
|
|
699
|
+
async getBySlot(subjectId, slot) {
|
|
700
|
+
try {
|
|
701
|
+
return await this.client._request("GET", `/claims/subject/${subjectId}/slot/${slot}`);
|
|
702
|
+
} catch (error) {
|
|
703
|
+
if (error instanceof NotFoundError) {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
throw error;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
async listSlots(subjectId) {
|
|
710
|
+
return this.client._request("GET", `/claims/subject/${subjectId}/slots`);
|
|
711
|
+
}
|
|
712
|
+
async retract(id) {
|
|
713
|
+
await this.client._request("POST", `/claims/${id}/retract`);
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
// src/resources/profiles.ts
|
|
718
|
+
var ProfilesResource = class {
|
|
719
|
+
constructor(client) {
|
|
720
|
+
this.client = client;
|
|
721
|
+
}
|
|
722
|
+
async get(subjectId) {
|
|
723
|
+
return this.client._request("GET", "/profiles", {
|
|
724
|
+
query: { subject_id: subjectId }
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
// src/resources/state.ts
|
|
730
|
+
var StateResource = class {
|
|
731
|
+
constructor(client) {
|
|
732
|
+
this.client = client;
|
|
733
|
+
}
|
|
734
|
+
async get(key, subjectId) {
|
|
735
|
+
try {
|
|
736
|
+
return await this.client._request("GET", `/state/${key}`, {
|
|
737
|
+
query: subjectId ? { subject_id: subjectId } : void 0
|
|
738
|
+
});
|
|
739
|
+
} catch (error) {
|
|
740
|
+
if (error instanceof NotFoundError) {
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
throw error;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
async set(options) {
|
|
747
|
+
return this.client._request("POST", `/state/${options.key}`, {
|
|
748
|
+
body: {
|
|
749
|
+
value: options.value,
|
|
750
|
+
subject_id: options.subjectId,
|
|
751
|
+
ttl_seconds: options.ttlSeconds
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
async delete(key, subjectId) {
|
|
756
|
+
await this.client._request("DELETE", `/state/${key}`, {
|
|
757
|
+
query: subjectId ? { subject_id: subjectId } : void 0
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// src/resources/prompts.ts
|
|
763
|
+
var PromptsResource = class {
|
|
764
|
+
constructor(client) {
|
|
765
|
+
this.client = client;
|
|
766
|
+
}
|
|
767
|
+
async create(options) {
|
|
768
|
+
const response = await this.client._request("POST", "/prompts", {
|
|
769
|
+
body: {
|
|
770
|
+
name: options.name,
|
|
771
|
+
prompt_text: options.promptText,
|
|
772
|
+
is_default: options.isDefault
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
return response.prompt;
|
|
776
|
+
}
|
|
777
|
+
async get(id) {
|
|
778
|
+
return this.client._request("GET", `/prompts/${id}`);
|
|
779
|
+
}
|
|
780
|
+
async list() {
|
|
781
|
+
const response = await this.client._request("GET", "/prompts");
|
|
782
|
+
return response.prompts;
|
|
783
|
+
}
|
|
784
|
+
async update(id, options) {
|
|
785
|
+
return this.client._request("PATCH", `/prompts/${id}`, {
|
|
786
|
+
body: {
|
|
787
|
+
name: options.name,
|
|
788
|
+
prompt_text: options.promptText,
|
|
789
|
+
is_default: options.isDefault
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
async delete(id) {
|
|
794
|
+
await this.client._request("DELETE", `/prompts/${id}`);
|
|
795
|
+
}
|
|
796
|
+
async resolve(options) {
|
|
797
|
+
return this.client._request("GET", "/prompts/resolve", {
|
|
798
|
+
query: {
|
|
799
|
+
subject_id: options?.subjectId,
|
|
800
|
+
chat_id: options?.chatId,
|
|
801
|
+
combined: options?.combined
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
// src/client.ts
|
|
808
|
+
var DEFAULT_BASE_URL = "https://mnexium.com/api/v1";
|
|
809
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
810
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
811
|
+
var Mnexium = class {
|
|
812
|
+
constructor(config = {}) {
|
|
813
|
+
this.apiKey = config.apiKey;
|
|
814
|
+
this.baseUrl = config.baseUrl?.replace(/\/$/, "") || DEFAULT_BASE_URL;
|
|
815
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
816
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
817
|
+
this.openaiConfig = config.openai;
|
|
818
|
+
this.anthropicConfig = config.anthropic;
|
|
819
|
+
this.googleConfig = config.google;
|
|
820
|
+
this.defaults = {
|
|
821
|
+
model: config.defaults?.model || "gpt-4o-mini",
|
|
822
|
+
log: config.defaults?.log ?? true,
|
|
823
|
+
learn: config.defaults?.learn ?? true,
|
|
824
|
+
recall: config.defaults?.recall ?? false,
|
|
825
|
+
history: config.defaults?.history ?? true,
|
|
826
|
+
summarize: config.defaults?.summarize ?? false,
|
|
827
|
+
systemPrompt: config.defaults?.systemPrompt ?? true,
|
|
828
|
+
...config.defaults
|
|
829
|
+
};
|
|
830
|
+
this.chat = new ChatResource(this);
|
|
831
|
+
this.memories = new MemoriesResource(this);
|
|
832
|
+
this.claims = new ClaimsResource(this);
|
|
833
|
+
this.profiles = new ProfilesResource(this);
|
|
834
|
+
this.state = new StateResource(this);
|
|
835
|
+
this.prompts = new PromptsResource(this);
|
|
836
|
+
}
|
|
837
|
+
async process(input) {
|
|
838
|
+
const options = typeof input === "string" ? { content: input } : input;
|
|
839
|
+
const model = options.model || this.defaults.model || "gpt-4o-mini";
|
|
840
|
+
const subjectId = options.subjectId || this.defaults.subjectId;
|
|
841
|
+
const chatId = options.chatId || this.defaults.chatId;
|
|
842
|
+
const log = options.log ?? this.defaults.log ?? true;
|
|
843
|
+
const learn = options.learn ?? this.defaults.learn ?? true;
|
|
844
|
+
const recall = options.recall ?? this.defaults.recall ?? false;
|
|
845
|
+
const profile = options.profile ?? this.defaults.profile ?? false;
|
|
846
|
+
const history = options.history ?? this.defaults.history ?? true;
|
|
847
|
+
const summarize = options.summarize ?? this.defaults.summarize ?? false;
|
|
848
|
+
const systemPrompt = options.systemPrompt ?? this.defaults.systemPrompt ?? true;
|
|
849
|
+
const metadata = options.metadata || this.defaults.metadata;
|
|
850
|
+
const maxTokens = options.maxTokens || this.defaults.maxTokens;
|
|
851
|
+
const temperature = options.temperature ?? this.defaults.temperature;
|
|
852
|
+
const regenerateKey = options.regenerateKey ?? this.defaults.regenerateKey ?? false;
|
|
853
|
+
const headers = {};
|
|
854
|
+
const provider = detectProvider(model);
|
|
855
|
+
if (provider === "anthropic" && this.anthropicConfig?.apiKey) {
|
|
856
|
+
headers["x-anthropic-key"] = this.anthropicConfig.apiKey;
|
|
857
|
+
} else if (provider === "google" && this.googleConfig?.apiKey) {
|
|
858
|
+
headers["x-google-key"] = this.googleConfig.apiKey;
|
|
859
|
+
} else if (this.openaiConfig?.apiKey) {
|
|
860
|
+
headers["x-openai-key"] = this.openaiConfig.apiKey;
|
|
861
|
+
} else if (this.anthropicConfig?.apiKey) {
|
|
862
|
+
headers["x-anthropic-key"] = this.anthropicConfig.apiKey;
|
|
863
|
+
} else if (this.googleConfig?.apiKey) {
|
|
864
|
+
headers["x-google-key"] = this.googleConfig.apiKey;
|
|
865
|
+
}
|
|
866
|
+
const body = {
|
|
867
|
+
model,
|
|
868
|
+
messages: [{ role: "user", content: options.content }],
|
|
869
|
+
stream: options.stream || false,
|
|
870
|
+
max_tokens: maxTokens,
|
|
871
|
+
temperature,
|
|
872
|
+
mnx: {
|
|
873
|
+
subject_id: subjectId,
|
|
874
|
+
chat_id: chatId,
|
|
875
|
+
log,
|
|
876
|
+
learn,
|
|
877
|
+
recall,
|
|
878
|
+
profile,
|
|
879
|
+
history,
|
|
880
|
+
summarize,
|
|
881
|
+
system_prompt: systemPrompt,
|
|
882
|
+
metadata,
|
|
883
|
+
regenerate_key: regenerateKey
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
if (options.stream) {
|
|
887
|
+
const response = await this._requestRaw("POST", "/chat/completions", {
|
|
888
|
+
body,
|
|
889
|
+
headers
|
|
890
|
+
});
|
|
891
|
+
return new StreamResponse(response, {
|
|
892
|
+
chatId: response.headers.get("X-Mnx-Chat-Id") || chatId || "",
|
|
893
|
+
subjectId: response.headers.get("X-Mnx-Subject-Id") || subjectId || "",
|
|
894
|
+
model,
|
|
895
|
+
provisionedKey: response.headers.get("X-Mnx-Key-Provisioned") || void 0,
|
|
896
|
+
claimUrl: response.headers.get("X-Mnx-Claim-Url") || void 0
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
const raw = await this._request("POST", "/chat/completions", {
|
|
900
|
+
body,
|
|
901
|
+
headers
|
|
902
|
+
});
|
|
903
|
+
const { content: extractedContent, usage: extractedUsage } = extractResponseContent(raw);
|
|
904
|
+
return {
|
|
905
|
+
content: extractedContent,
|
|
906
|
+
chatId: raw.mnx.chat_id,
|
|
907
|
+
subjectId: raw.mnx.subject_id,
|
|
908
|
+
model: raw.model,
|
|
909
|
+
usage: extractedUsage ? {
|
|
910
|
+
promptTokens: extractedUsage.prompt_tokens,
|
|
911
|
+
completionTokens: extractedUsage.completion_tokens,
|
|
912
|
+
totalTokens: extractedUsage.total_tokens
|
|
913
|
+
} : void 0,
|
|
914
|
+
provisionedKey: raw.mnx.provisioned_key,
|
|
915
|
+
claimUrl: raw.mnx.claim_url,
|
|
916
|
+
raw
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Get the provisioned trial key (if auto-provisioned)
|
|
921
|
+
* @deprecated Use getTrialInfo() instead
|
|
922
|
+
*/
|
|
923
|
+
getProvisionedKey() {
|
|
924
|
+
return this.provisionedKey;
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Get trial key info including the key and claim URL
|
|
928
|
+
*
|
|
929
|
+
* @example
|
|
930
|
+
* const trial = mnx.getTrialInfo();
|
|
931
|
+
* if (trial) {
|
|
932
|
+
* console.log('Key:', trial.key);
|
|
933
|
+
* console.log('Claim at:', trial.claimUrl);
|
|
934
|
+
* }
|
|
935
|
+
*/
|
|
936
|
+
getTrialInfo() {
|
|
937
|
+
if (!this.provisionedKey) {
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
key: this.provisionedKey,
|
|
942
|
+
claimUrl: "https://mnexium.com/claim"
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Get a Subject handle for a given subject ID
|
|
947
|
+
*
|
|
948
|
+
* Creating a Subject does NOT make a network call - it's a lightweight scoped handle.
|
|
949
|
+
*
|
|
950
|
+
* @example
|
|
951
|
+
* const alice = mnx.subject("user_123");
|
|
952
|
+
* await alice.process("Hello!");
|
|
953
|
+
* await alice.memories.search("hobbies");
|
|
954
|
+
*/
|
|
955
|
+
subject(subjectId) {
|
|
956
|
+
return new Subject(this, subjectId || crypto.randomUUID());
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Create a chat for a subject
|
|
960
|
+
*
|
|
961
|
+
* @example
|
|
962
|
+
* const alice = mnx.subject("user_123");
|
|
963
|
+
* const chat = mnx.createChat(alice, { history: true });
|
|
964
|
+
* // or with string:
|
|
965
|
+
* const chat = mnx.createChat("user_123", { history: true });
|
|
966
|
+
*/
|
|
967
|
+
createChat(subject, options) {
|
|
968
|
+
const subjectId = typeof subject === "string" ? subject : subject.id;
|
|
969
|
+
return new Chat(this, subjectId, options);
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* @deprecated Use createChat(subject, options) instead
|
|
973
|
+
*/
|
|
974
|
+
createChatSession(options = {}) {
|
|
975
|
+
const subjectId = options.subjectId || crypto.randomUUID();
|
|
976
|
+
return new Chat(this, subjectId, options);
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Internal: Set provisioned key from response
|
|
980
|
+
*/
|
|
981
|
+
_setProvisionedKey(key) {
|
|
982
|
+
this.provisionedKey = key;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Internal: Make a raw API request (returns Response, used for streaming)
|
|
986
|
+
*/
|
|
987
|
+
async _requestRaw(method, path, options = {}) {
|
|
988
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
989
|
+
if (options.query) {
|
|
990
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
991
|
+
if (value !== void 0) {
|
|
992
|
+
url.searchParams.set(key, String(value));
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
const headers = {
|
|
997
|
+
"Content-Type": "application/json",
|
|
998
|
+
...options.headers
|
|
999
|
+
};
|
|
1000
|
+
const effectiveKey = this.apiKey || this.provisionedKey;
|
|
1001
|
+
if (effectiveKey) {
|
|
1002
|
+
headers["x-mnexium-key"] = effectiveKey;
|
|
1003
|
+
}
|
|
1004
|
+
const controller = new AbortController();
|
|
1005
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
1006
|
+
const response = await fetch(url.toString(), {
|
|
1007
|
+
method,
|
|
1008
|
+
headers,
|
|
1009
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
1010
|
+
signal: controller.signal
|
|
1011
|
+
});
|
|
1012
|
+
clearTimeout(timeoutId);
|
|
1013
|
+
const provisionedKey = response.headers.get("x-mnx-key-provisioned");
|
|
1014
|
+
if (provisionedKey) {
|
|
1015
|
+
this._setProvisionedKey(provisionedKey);
|
|
1016
|
+
}
|
|
1017
|
+
if (!response.ok) {
|
|
1018
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
1019
|
+
throw this._handleErrorResponse(response.status, errorBody);
|
|
1020
|
+
}
|
|
1021
|
+
return response;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Internal: Make an API request
|
|
1025
|
+
*/
|
|
1026
|
+
async _request(method, path, options = {}) {
|
|
1027
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
1028
|
+
if (options.query) {
|
|
1029
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
1030
|
+
if (value !== void 0) {
|
|
1031
|
+
url.searchParams.set(key, String(value));
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
const headers = {
|
|
1036
|
+
"Content-Type": "application/json",
|
|
1037
|
+
...options.headers
|
|
1038
|
+
};
|
|
1039
|
+
const effectiveKey = this.apiKey || this.provisionedKey;
|
|
1040
|
+
if (effectiveKey) {
|
|
1041
|
+
headers["x-mnexium-key"] = effectiveKey;
|
|
1042
|
+
}
|
|
1043
|
+
let lastError;
|
|
1044
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
1045
|
+
try {
|
|
1046
|
+
const controller = new AbortController();
|
|
1047
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
1048
|
+
const response = await fetch(url.toString(), {
|
|
1049
|
+
method,
|
|
1050
|
+
headers,
|
|
1051
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
1052
|
+
signal: controller.signal
|
|
1053
|
+
});
|
|
1054
|
+
clearTimeout(timeoutId);
|
|
1055
|
+
const provisionedKey = response.headers.get("x-mnx-key-provisioned");
|
|
1056
|
+
if (provisionedKey) {
|
|
1057
|
+
this._setProvisionedKey(provisionedKey);
|
|
1058
|
+
}
|
|
1059
|
+
if (!response.ok) {
|
|
1060
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
1061
|
+
throw this._handleErrorResponse(response.status, errorBody);
|
|
1062
|
+
}
|
|
1063
|
+
return await response.json();
|
|
1064
|
+
} catch (error) {
|
|
1065
|
+
lastError = error;
|
|
1066
|
+
if (error instanceof APIError && error.status < 500 && !(error instanceof RateLimitError)) {
|
|
1067
|
+
throw error;
|
|
1068
|
+
}
|
|
1069
|
+
if (attempt === this.maxRetries) {
|
|
1070
|
+
throw error;
|
|
1071
|
+
}
|
|
1072
|
+
await this._sleep(Math.pow(2, attempt) * 1e3);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
throw lastError || new MnexiumError("Request failed");
|
|
1076
|
+
}
|
|
1077
|
+
_handleErrorResponse(status, body) {
|
|
1078
|
+
const message = body.message || body.error || "Unknown error";
|
|
1079
|
+
const code = body.error;
|
|
1080
|
+
switch (status) {
|
|
1081
|
+
case 401:
|
|
1082
|
+
return new AuthenticationError(message);
|
|
1083
|
+
case 404:
|
|
1084
|
+
return new NotFoundError(message);
|
|
1085
|
+
case 429:
|
|
1086
|
+
return new RateLimitError(message, {
|
|
1087
|
+
current: body.current,
|
|
1088
|
+
limit: body.limit
|
|
1089
|
+
});
|
|
1090
|
+
default:
|
|
1091
|
+
return new APIError(message, status, code);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
_sleep(ms) {
|
|
1095
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1096
|
+
}
|
|
1097
|
+
};
|
|
1098
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1099
|
+
0 && (module.exports = {
|
|
1100
|
+
APIError,
|
|
1101
|
+
AuthenticationError,
|
|
1102
|
+
Chat,
|
|
1103
|
+
ChatSession,
|
|
1104
|
+
EventStream,
|
|
1105
|
+
Mnexium,
|
|
1106
|
+
MnexiumError,
|
|
1107
|
+
RateLimitError,
|
|
1108
|
+
StreamResponse,
|
|
1109
|
+
Subject
|
|
1110
|
+
});
|