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