@reverbia/sdk 1.0.0-next.20251124100226 → 1.0.0-next.20251125084024

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.
@@ -40,566 +40,285 @@ module.exports = __toCommonJS(index_exports);
40
40
 
41
41
  // src/react/useChat.ts
42
42
  var import_react = require("react");
43
- var import_client = require("@reverbia/sdk");
44
- function useChat(options) {
45
- const { getToken } = options || {};
46
- const [isLoading, setIsLoading] = (0, import_react.useState)(false);
47
- const sendMessage = (0, import_react.useCallback)(
48
- async ({
49
- messages,
50
- model
51
- }) => {
52
- if (!messages?.length) {
53
- const error = "messages are required to call sendMessage.";
54
- return { data: null, error };
55
- }
56
- if (!model) {
57
- const error = "model is required to call sendMessage.";
58
- return { data: null, error };
59
- }
60
- if (!getToken) {
61
- const error = "Token getter function is required.";
62
- return { data: null, error };
43
+
44
+ // src/client/core/bodySerializer.gen.ts
45
+ var jsonBodySerializer = {
46
+ bodySerializer: (body) => JSON.stringify(
47
+ body,
48
+ (_key, value) => typeof value === "bigint" ? value.toString() : value
49
+ )
50
+ };
51
+
52
+ // src/client/core/params.gen.ts
53
+ var extraPrefixesMap = {
54
+ $body_: "body",
55
+ $headers_: "headers",
56
+ $path_: "path",
57
+ $query_: "query"
58
+ };
59
+ var extraPrefixes = Object.entries(extraPrefixesMap);
60
+
61
+ // src/client/core/serverSentEvents.gen.ts
62
+ var createSseClient = ({
63
+ onRequest,
64
+ onSseError,
65
+ onSseEvent,
66
+ responseTransformer,
67
+ responseValidator,
68
+ sseDefaultRetryDelay,
69
+ sseMaxRetryAttempts,
70
+ sseMaxRetryDelay,
71
+ sseSleepFn,
72
+ url,
73
+ ...options
74
+ }) => {
75
+ let lastEventId;
76
+ const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
77
+ const createStream = async function* () {
78
+ let retryDelay = sseDefaultRetryDelay ?? 3e3;
79
+ let attempt = 0;
80
+ const signal = options.signal ?? new AbortController().signal;
81
+ while (true) {
82
+ if (signal.aborted) break;
83
+ attempt++;
84
+ const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
85
+ if (lastEventId !== void 0) {
86
+ headers.set("Last-Event-ID", lastEventId);
63
87
  }
64
- setIsLoading(true);
65
88
  try {
66
- const token = await getToken();
67
- if (!token) {
68
- const error = "No access token available.";
69
- setIsLoading(false);
70
- return { data: null, error };
89
+ const requestInit = {
90
+ redirect: "follow",
91
+ ...options,
92
+ body: options.serializedBody,
93
+ headers,
94
+ signal
95
+ };
96
+ let request = new Request(url, requestInit);
97
+ if (onRequest) {
98
+ request = await onRequest(url, requestInit);
71
99
  }
72
- const completion = await (0, import_client.postApiV1ChatCompletions)({
73
- body: {
74
- messages,
75
- model
76
- },
77
- headers: {
78
- Authorization: `Bearer ${token}`
100
+ const _fetch = options.fetch ?? globalThis.fetch;
101
+ const response = await _fetch(request);
102
+ if (!response.ok)
103
+ throw new Error(
104
+ `SSE failed: ${response.status} ${response.statusText}`
105
+ );
106
+ if (!response.body) throw new Error("No body in SSE response");
107
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
108
+ let buffer = "";
109
+ const abortHandler = () => {
110
+ try {
111
+ reader.cancel();
112
+ } catch {
79
113
  }
80
- });
81
- if (!completion.data) {
82
- const error = completion.error?.error ?? "API did not return a completion response.";
83
- setIsLoading(false);
84
- return { data: null, error };
114
+ };
115
+ signal.addEventListener("abort", abortHandler);
116
+ try {
117
+ while (true) {
118
+ const { done, value } = await reader.read();
119
+ if (done) break;
120
+ buffer += value;
121
+ const chunks = buffer.split("\n\n");
122
+ buffer = chunks.pop() ?? "";
123
+ for (const chunk of chunks) {
124
+ const lines = chunk.split("\n");
125
+ const dataLines = [];
126
+ let eventName;
127
+ for (const line of lines) {
128
+ if (line.startsWith("data:")) {
129
+ dataLines.push(line.replace(/^data:\s*/, ""));
130
+ } else if (line.startsWith("event:")) {
131
+ eventName = line.replace(/^event:\s*/, "");
132
+ } else if (line.startsWith("id:")) {
133
+ lastEventId = line.replace(/^id:\s*/, "");
134
+ } else if (line.startsWith("retry:")) {
135
+ const parsed = Number.parseInt(
136
+ line.replace(/^retry:\s*/, ""),
137
+ 10
138
+ );
139
+ if (!Number.isNaN(parsed)) {
140
+ retryDelay = parsed;
141
+ }
142
+ }
143
+ }
144
+ let data;
145
+ let parsedJson = false;
146
+ if (dataLines.length) {
147
+ const rawData = dataLines.join("\n");
148
+ try {
149
+ data = JSON.parse(rawData);
150
+ parsedJson = true;
151
+ } catch {
152
+ data = rawData;
153
+ }
154
+ }
155
+ if (parsedJson) {
156
+ if (responseValidator) {
157
+ await responseValidator(data);
158
+ }
159
+ if (responseTransformer) {
160
+ data = await responseTransformer(data);
161
+ }
162
+ }
163
+ onSseEvent?.({
164
+ data,
165
+ event: eventName,
166
+ id: lastEventId,
167
+ retry: retryDelay
168
+ });
169
+ if (dataLines.length) {
170
+ yield data;
171
+ }
172
+ }
173
+ }
174
+ } finally {
175
+ signal.removeEventListener("abort", abortHandler);
176
+ reader.releaseLock();
85
177
  }
86
- if (typeof completion.data === "string") {
87
- const error = "API returned a string response instead of a completion object.";
88
- setIsLoading(false);
89
- return { data: null, error };
178
+ break;
179
+ } catch (error) {
180
+ onSseError?.(error);
181
+ if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
182
+ break;
90
183
  }
91
- setIsLoading(false);
92
- return { data: completion.data, error: null };
93
- } catch (err) {
94
- const error = err instanceof Error ? err.message : "Failed to send message.";
95
- setIsLoading(false);
96
- return { data: null, error };
184
+ const backoff = Math.min(
185
+ retryDelay * 2 ** (attempt - 1),
186
+ sseMaxRetryDelay ?? 3e4
187
+ );
188
+ await sleep(backoff);
97
189
  }
98
- },
99
- [getToken]
100
- );
101
- return {
102
- isLoading,
103
- sendMessage
190
+ }
104
191
  };
105
- }
106
-
107
- // src/react/useMemory.ts
108
- var import_react2 = require("react");
109
- var import_client6 = require("@reverbia/sdk");
110
-
111
- // src/lib/memory/service.ts
112
- var FACT_EXTRACTION_PROMPT = `You are a memory extraction system. Extract durable user memories from chat messages.
113
-
114
- CRITICAL: You MUST respond with ONLY valid JSON. No explanations, no markdown, no code blocks, just pure JSON.
115
-
116
- Only extract facts that will be useful in future conversations, such as identity, stable preferences, ongoing projects, skills, and constraints.
117
-
118
- Do not extract sensitive attributes, temporary things, or single-use instructions.
119
-
120
- If there are no memories to extract, return: {"items": []}
121
-
122
- Response format (JSON only, no other text):
192
+ const stream = createStream();
193
+ return { stream };
194
+ };
123
195
 
124
- {
125
- "items": [
126
- {
127
- "type": "identity",
128
- "namespace": "identity",
129
- "key": "name",
130
- "value": "Charlie",
131
- "rawEvidence": "I'm Charlie",
132
- "confidence": 0.98,
133
- "pii": true
134
- },
135
- {
136
- "type": "identity",
137
- "namespace": "work",
138
- "key": "company",
139
- "value": "ZetaChain",
140
- "rawEvidence": "called ZetaChain",
141
- "confidence": 0.99,
142
- "pii": false
143
- },
144
- {
145
- "type": "preference",
146
- "namespace": "answer_style",
147
- "key": "verbosity",
148
- "value": "concise_direct",
149
- "rawEvidence": "I prefer concise, direct answers",
150
- "confidence": 0.96,
151
- "pii": false
152
- },
153
- {
154
- "type": "identity",
155
- "namespace": "timezone",
156
- "key": "tz",
157
- "value": "America/Los_Angeles",
158
- "rawEvidence": "I'm in PST",
159
- "confidence": 0.9,
160
- "pii": false
161
- }
162
- ]
163
- }`;
164
- var preprocessMemories = (items, minConfidence = 0.6) => {
165
- if (!items || !Array.isArray(items)) {
166
- return [];
196
+ // src/client/core/pathSerializer.gen.ts
197
+ var separatorArrayExplode = (style) => {
198
+ switch (style) {
199
+ case "label":
200
+ return ".";
201
+ case "matrix":
202
+ return ";";
203
+ case "simple":
204
+ return ",";
205
+ default:
206
+ return "&";
167
207
  }
168
- const validItems = items.filter((item) => {
169
- if (item.namespace == null || item.key == null || item.value == null) {
170
- console.warn(
171
- "Dropping memory item with null/undefined namespace, key, or value:",
172
- item
173
- );
174
- return false;
175
- }
176
- const namespace = String(item.namespace).trim();
177
- const key = String(item.key).trim();
178
- const value = String(item.value).trim();
179
- if (namespace === "" || key === "" || value === "") {
180
- console.warn(
181
- "Dropping memory item with empty namespace, key, or value after trimming:",
182
- item
183
- );
184
- return false;
185
- }
186
- if (typeof item.confidence !== "number" || item.confidence < minConfidence) {
187
- console.warn(
188
- `Dropping memory item with confidence ${item.confidence} below threshold ${minConfidence}:`,
189
- item
190
- );
191
- return false;
192
- }
193
- return true;
194
- });
195
- const deduplicatedMap = /* @__PURE__ */ new Map();
196
- for (const item of validItems) {
197
- const uniqueKey = `${item.namespace}:${item.key}:${item.value}`;
198
- const existing = deduplicatedMap.get(uniqueKey);
199
- if (!existing || item.confidence > existing.confidence) {
200
- deduplicatedMap.set(uniqueKey, item);
201
- } else {
202
- console.debug(
203
- `Deduplicating memory item: keeping entry with higher confidence (${existing.confidence} > ${item.confidence})`,
204
- { namespace: item.namespace, key: item.key, value: item.value }
205
- );
206
- }
208
+ };
209
+ var separatorArrayNoExplode = (style) => {
210
+ switch (style) {
211
+ case "form":
212
+ return ",";
213
+ case "pipeDelimited":
214
+ return "|";
215
+ case "spaceDelimited":
216
+ return "%20";
217
+ default:
218
+ return ",";
207
219
  }
208
- return Array.from(deduplicatedMap.values());
209
220
  };
210
-
211
- // src/lib/memory/db.ts
212
- var import_dexie = __toESM(require("dexie"));
213
- var MemoryDatabase = class extends import_dexie.default {
214
- constructor() {
215
- super("MemoryDatabase");
216
- this.version(2).stores({
217
- memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
218
- });
219
- this.version(3).stores({
220
- memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
221
- });
221
+ var separatorObjectExplode = (style) => {
222
+ switch (style) {
223
+ case "label":
224
+ return ".";
225
+ case "matrix":
226
+ return ";";
227
+ case "simple":
228
+ return ",";
229
+ default:
230
+ return "&";
222
231
  }
223
232
  };
224
- var memoryDb = new MemoryDatabase();
225
- var saveMemory = async (memory) => {
226
- const compositeKey = `${memory.namespace}:${memory.key}`;
227
- const uniqueKey = `${memory.namespace}:${memory.key}:${memory.value}`;
228
- const now = Date.now();
229
- const existing = await memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
230
- if (existing) {
231
- const shouldPreserveEmbedding = existing.value === memory.value && existing.rawEvidence === memory.rawEvidence && existing.type === memory.type && existing.namespace === memory.namespace && existing.key === memory.key && existing.embedding !== void 0 && existing.embedding.length > 0;
232
- const updateData = {
233
- ...memory,
234
- compositeKey,
235
- uniqueKey,
236
- updatedAt: now,
237
- createdAt: existing.createdAt
238
- };
239
- if (shouldPreserveEmbedding) {
240
- updateData.embedding = existing.embedding;
241
- updateData.embeddingModel = existing.embeddingModel;
242
- } else {
243
- updateData.embedding = [];
244
- updateData.embeddingModel = void 0;
233
+ var serializeArrayParam = ({
234
+ allowReserved,
235
+ explode,
236
+ name,
237
+ style,
238
+ value
239
+ }) => {
240
+ if (!explode) {
241
+ const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
242
+ switch (style) {
243
+ case "label":
244
+ return `.${joinedValues2}`;
245
+ case "matrix":
246
+ return `;${name}=${joinedValues2}`;
247
+ case "simple":
248
+ return joinedValues2;
249
+ default:
250
+ return `${name}=${joinedValues2}`;
245
251
  }
246
- await memoryDb.memories.update(existing.id, updateData);
247
- } else {
248
- await memoryDb.memories.add({
249
- ...memory,
250
- compositeKey,
251
- uniqueKey,
252
- createdAt: now,
253
- updatedAt: now
254
- });
255
252
  }
253
+ const separator = separatorArrayExplode(style);
254
+ const joinedValues = value.map((v) => {
255
+ if (style === "label" || style === "simple") {
256
+ return allowReserved ? v : encodeURIComponent(v);
257
+ }
258
+ return serializePrimitiveParam({
259
+ allowReserved,
260
+ name,
261
+ value: v
262
+ });
263
+ }).join(separator);
264
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
256
265
  };
257
- var saveMemories = async (memories) => {
258
- await Promise.all(memories.map((memory) => saveMemory(memory)));
259
- };
260
- var getAllMemories = async () => {
261
- return memoryDb.memories.toArray();
262
- };
263
- var cosineSimilarity = (a, b) => {
264
- if (a.length !== b.length) {
265
- throw new Error("Vectors must have the same length");
266
- }
267
- let dotProduct = 0;
268
- let normA = 0;
269
- let normB = 0;
270
- for (let i = 0; i < a.length; i++) {
271
- dotProduct += a[i] * b[i];
272
- normA += a[i] * a[i];
273
- normB += b[i] * b[i];
266
+ var serializePrimitiveParam = ({
267
+ allowReserved,
268
+ name,
269
+ value
270
+ }) => {
271
+ if (value === void 0 || value === null) {
272
+ return "";
274
273
  }
275
- const denominator = Math.sqrt(normA) * Math.sqrt(normB);
276
- if (denominator === 0) {
277
- return 0;
274
+ if (typeof value === "object") {
275
+ throw new Error(
276
+ "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
277
+ );
278
278
  }
279
- return dotProduct / denominator;
279
+ return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
280
280
  };
281
- var searchSimilarMemories = async (queryEmbedding, limit = 10, minSimilarity = 0.6) => {
282
- const allMemories = await getAllMemories();
283
- const memoriesWithEmbeddings = allMemories.filter(
284
- (m) => m.embedding && m.embedding.length > 0
285
- );
286
- console.log(
287
- `[Memory Search] Total memories: ${allMemories.length}, memories with embeddings: ${memoriesWithEmbeddings.length}`
288
- );
289
- if (memoriesWithEmbeddings.length === 0) {
290
- console.warn(
291
- "[Memory Search] No memories with embeddings found. Memories may need embeddings generated. Use generateAndStoreEmbeddings() to generate embeddings for existing memories."
292
- );
293
- return [];
281
+ var serializeObjectParam = ({
282
+ allowReserved,
283
+ explode,
284
+ name,
285
+ style,
286
+ value,
287
+ valueOnly
288
+ }) => {
289
+ if (value instanceof Date) {
290
+ return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
294
291
  }
295
- const allResults = memoriesWithEmbeddings.map((memory) => {
296
- const similarity = cosineSimilarity(queryEmbedding, memory.embedding);
297
- return {
298
- ...memory,
299
- similarity
300
- };
301
- }).sort((a, b) => b.similarity - a.similarity);
302
- console.log(
303
- `[Memory Search] All similarity scores:`,
304
- allResults.map((r) => ({
305
- key: `${r.namespace}:${r.key}`,
306
- value: r.value,
307
- similarity: r.similarity.toFixed(4)
308
- }))
309
- );
310
- const results = allResults.filter((result) => result.similarity >= minSimilarity).slice(0, limit);
311
- if (results.length === 0 && allResults.length > 0) {
312
- const topSimilarity = allResults[0].similarity;
313
- const suggestedThreshold = Math.max(0.3, topSimilarity - 0.1);
314
- console.warn(
315
- `[Memory Search] No memories above threshold ${minSimilarity}. Highest similarity was ${topSimilarity.toFixed(4)}. Consider lowering the threshold to ${suggestedThreshold.toFixed(2)}`
316
- );
317
- } else {
318
- console.log(
319
- `[Memory Search] Found ${results.length} memories above similarity threshold ${minSimilarity}. Top similarity: ${results[0]?.similarity.toFixed(4) || "N/A"}`
320
- );
292
+ if (style !== "deepObject" && !explode) {
293
+ let values = [];
294
+ Object.entries(value).forEach(([key, v]) => {
295
+ values = [
296
+ ...values,
297
+ key,
298
+ allowReserved ? v : encodeURIComponent(v)
299
+ ];
300
+ });
301
+ const joinedValues2 = values.join(",");
302
+ switch (style) {
303
+ case "form":
304
+ return `${name}=${joinedValues2}`;
305
+ case "label":
306
+ return `.${joinedValues2}`;
307
+ case "matrix":
308
+ return `;${name}=${joinedValues2}`;
309
+ default:
310
+ return joinedValues2;
311
+ }
321
312
  }
322
- return results;
323
- };
324
-
325
- // src/client/core/bodySerializer.gen.ts
326
- var jsonBodySerializer = {
327
- bodySerializer: (body) => JSON.stringify(
328
- body,
329
- (_key, value) => typeof value === "bigint" ? value.toString() : value
330
- )
331
- };
332
-
333
- // src/client/core/params.gen.ts
334
- var extraPrefixesMap = {
335
- $body_: "body",
336
- $headers_: "headers",
337
- $path_: "path",
338
- $query_: "query"
339
- };
340
- var extraPrefixes = Object.entries(extraPrefixesMap);
341
-
342
- // src/client/core/serverSentEvents.gen.ts
343
- var createSseClient = ({
344
- onRequest,
345
- onSseError,
346
- onSseEvent,
347
- responseTransformer,
348
- responseValidator,
349
- sseDefaultRetryDelay,
350
- sseMaxRetryAttempts,
351
- sseMaxRetryDelay,
352
- sseSleepFn,
353
- url,
354
- ...options
355
- }) => {
356
- let lastEventId;
357
- const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
358
- const createStream = async function* () {
359
- let retryDelay = sseDefaultRetryDelay ?? 3e3;
360
- let attempt = 0;
361
- const signal = options.signal ?? new AbortController().signal;
362
- while (true) {
363
- if (signal.aborted) break;
364
- attempt++;
365
- const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
366
- if (lastEventId !== void 0) {
367
- headers.set("Last-Event-ID", lastEventId);
368
- }
369
- try {
370
- const requestInit = {
371
- redirect: "follow",
372
- ...options,
373
- body: options.serializedBody,
374
- headers,
375
- signal
376
- };
377
- let request = new Request(url, requestInit);
378
- if (onRequest) {
379
- request = await onRequest(url, requestInit);
380
- }
381
- const _fetch = options.fetch ?? globalThis.fetch;
382
- const response = await _fetch(request);
383
- if (!response.ok)
384
- throw new Error(
385
- `SSE failed: ${response.status} ${response.statusText}`
386
- );
387
- if (!response.body) throw new Error("No body in SSE response");
388
- const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
389
- let buffer = "";
390
- const abortHandler = () => {
391
- try {
392
- reader.cancel();
393
- } catch {
394
- }
395
- };
396
- signal.addEventListener("abort", abortHandler);
397
- try {
398
- while (true) {
399
- const { done, value } = await reader.read();
400
- if (done) break;
401
- buffer += value;
402
- const chunks = buffer.split("\n\n");
403
- buffer = chunks.pop() ?? "";
404
- for (const chunk of chunks) {
405
- const lines = chunk.split("\n");
406
- const dataLines = [];
407
- let eventName;
408
- for (const line of lines) {
409
- if (line.startsWith("data:")) {
410
- dataLines.push(line.replace(/^data:\s*/, ""));
411
- } else if (line.startsWith("event:")) {
412
- eventName = line.replace(/^event:\s*/, "");
413
- } else if (line.startsWith("id:")) {
414
- lastEventId = line.replace(/^id:\s*/, "");
415
- } else if (line.startsWith("retry:")) {
416
- const parsed = Number.parseInt(
417
- line.replace(/^retry:\s*/, ""),
418
- 10
419
- );
420
- if (!Number.isNaN(parsed)) {
421
- retryDelay = parsed;
422
- }
423
- }
424
- }
425
- let data;
426
- let parsedJson = false;
427
- if (dataLines.length) {
428
- const rawData = dataLines.join("\n");
429
- try {
430
- data = JSON.parse(rawData);
431
- parsedJson = true;
432
- } catch {
433
- data = rawData;
434
- }
435
- }
436
- if (parsedJson) {
437
- if (responseValidator) {
438
- await responseValidator(data);
439
- }
440
- if (responseTransformer) {
441
- data = await responseTransformer(data);
442
- }
443
- }
444
- onSseEvent?.({
445
- data,
446
- event: eventName,
447
- id: lastEventId,
448
- retry: retryDelay
449
- });
450
- if (dataLines.length) {
451
- yield data;
452
- }
453
- }
454
- }
455
- } finally {
456
- signal.removeEventListener("abort", abortHandler);
457
- reader.releaseLock();
458
- }
459
- break;
460
- } catch (error) {
461
- onSseError?.(error);
462
- if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
463
- break;
464
- }
465
- const backoff = Math.min(
466
- retryDelay * 2 ** (attempt - 1),
467
- sseMaxRetryDelay ?? 3e4
468
- );
469
- await sleep(backoff);
470
- }
471
- }
472
- };
473
- const stream = createStream();
474
- return { stream };
475
- };
476
-
477
- // src/client/core/pathSerializer.gen.ts
478
- var separatorArrayExplode = (style) => {
479
- switch (style) {
480
- case "label":
481
- return ".";
482
- case "matrix":
483
- return ";";
484
- case "simple":
485
- return ",";
486
- default:
487
- return "&";
488
- }
489
- };
490
- var separatorArrayNoExplode = (style) => {
491
- switch (style) {
492
- case "form":
493
- return ",";
494
- case "pipeDelimited":
495
- return "|";
496
- case "spaceDelimited":
497
- return "%20";
498
- default:
499
- return ",";
500
- }
501
- };
502
- var separatorObjectExplode = (style) => {
503
- switch (style) {
504
- case "label":
505
- return ".";
506
- case "matrix":
507
- return ";";
508
- case "simple":
509
- return ",";
510
- default:
511
- return "&";
512
- }
513
- };
514
- var serializeArrayParam = ({
515
- allowReserved,
516
- explode,
517
- name,
518
- style,
519
- value
520
- }) => {
521
- if (!explode) {
522
- const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
523
- switch (style) {
524
- case "label":
525
- return `.${joinedValues2}`;
526
- case "matrix":
527
- return `;${name}=${joinedValues2}`;
528
- case "simple":
529
- return joinedValues2;
530
- default:
531
- return `${name}=${joinedValues2}`;
532
- }
533
- }
534
- const separator = separatorArrayExplode(style);
535
- const joinedValues = value.map((v) => {
536
- if (style === "label" || style === "simple") {
537
- return allowReserved ? v : encodeURIComponent(v);
538
- }
539
- return serializePrimitiveParam({
540
- allowReserved,
541
- name,
542
- value: v
543
- });
544
- }).join(separator);
545
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
546
- };
547
- var serializePrimitiveParam = ({
548
- allowReserved,
549
- name,
550
- value
551
- }) => {
552
- if (value === void 0 || value === null) {
553
- return "";
554
- }
555
- if (typeof value === "object") {
556
- throw new Error(
557
- "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
558
- );
559
- }
560
- return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
561
- };
562
- var serializeObjectParam = ({
563
- allowReserved,
564
- explode,
565
- name,
566
- style,
567
- value,
568
- valueOnly
569
- }) => {
570
- if (value instanceof Date) {
571
- return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
572
- }
573
- if (style !== "deepObject" && !explode) {
574
- let values = [];
575
- Object.entries(value).forEach(([key, v]) => {
576
- values = [
577
- ...values,
578
- key,
579
- allowReserved ? v : encodeURIComponent(v)
580
- ];
581
- });
582
- const joinedValues2 = values.join(",");
583
- switch (style) {
584
- case "form":
585
- return `${name}=${joinedValues2}`;
586
- case "label":
587
- return `.${joinedValues2}`;
588
- case "matrix":
589
- return `;${name}=${joinedValues2}`;
590
- default:
591
- return joinedValues2;
592
- }
593
- }
594
- const separator = separatorObjectExplode(style);
595
- const joinedValues = Object.entries(value).map(
596
- ([key, v]) => serializePrimitiveParam({
597
- allowReserved,
598
- name: style === "deepObject" ? `${name}[${key}]` : key,
599
- value: v
600
- })
601
- ).join(separator);
602
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
313
+ const separator = separatorObjectExplode(style);
314
+ const joinedValues = Object.entries(value).map(
315
+ ([key, v]) => serializePrimitiveParam({
316
+ allowReserved,
317
+ name: style === "deepObject" ? `${name}[${key}]` : key,
318
+ value: v
319
+ })
320
+ ).join(separator);
321
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
603
322
  };
604
323
 
605
324
  // src/client/core/utils.gen.ts
@@ -1050,91 +769,461 @@ var createClient = (config = {}) => {
1050
769
  ...result
1051
770
  };
1052
771
  }
1053
- const textError = await response.text();
1054
- let jsonError;
1055
- try {
1056
- jsonError = JSON.parse(textError);
1057
- } catch {
772
+ const textError = await response.text();
773
+ let jsonError;
774
+ try {
775
+ jsonError = JSON.parse(textError);
776
+ } catch {
777
+ }
778
+ const error = jsonError ?? textError;
779
+ let finalError = error;
780
+ for (const fn of interceptors.error.fns) {
781
+ if (fn) {
782
+ finalError = await fn(error, response, opts);
783
+ }
784
+ }
785
+ finalError = finalError || {};
786
+ if (opts.throwOnError) {
787
+ throw finalError;
788
+ }
789
+ return {
790
+ error: finalError,
791
+ ...result
792
+ };
793
+ };
794
+ const makeMethodFn = (method) => (options) => request({ ...options, method });
795
+ const makeSseFn = (method) => async (options) => {
796
+ const { opts, url } = await beforeRequest(options);
797
+ return createSseClient({
798
+ ...opts,
799
+ body: opts.body,
800
+ headers: opts.headers,
801
+ method,
802
+ onRequest: async (url2, init) => {
803
+ let request2 = new Request(url2, init);
804
+ const requestInit = {
805
+ ...init,
806
+ method: init.method,
807
+ url: url2
808
+ };
809
+ for (const fn of interceptors.request.fns) {
810
+ if (fn) {
811
+ await fn(requestInit);
812
+ request2 = new Request(requestInit.url, requestInit);
813
+ }
814
+ }
815
+ return request2;
816
+ },
817
+ url
818
+ });
819
+ };
820
+ return {
821
+ buildUrl,
822
+ connect: makeMethodFn("CONNECT"),
823
+ delete: makeMethodFn("DELETE"),
824
+ get: makeMethodFn("GET"),
825
+ getConfig,
826
+ head: makeMethodFn("HEAD"),
827
+ interceptors,
828
+ options: makeMethodFn("OPTIONS"),
829
+ patch: makeMethodFn("PATCH"),
830
+ post: makeMethodFn("POST"),
831
+ put: makeMethodFn("PUT"),
832
+ request,
833
+ setConfig,
834
+ sse: {
835
+ connect: makeSseFn("CONNECT"),
836
+ delete: makeSseFn("DELETE"),
837
+ get: makeSseFn("GET"),
838
+ head: makeSseFn("HEAD"),
839
+ options: makeSseFn("OPTIONS"),
840
+ patch: makeSseFn("PATCH"),
841
+ post: makeSseFn("POST"),
842
+ put: makeSseFn("PUT"),
843
+ trace: makeSseFn("TRACE")
844
+ },
845
+ trace: makeMethodFn("TRACE")
846
+ };
847
+ };
848
+
849
+ // src/clientConfig.ts
850
+ var createClientConfig = (config) => ({
851
+ ...config,
852
+ baseUrl: "https://ai-portal-dev.zetachain.com"
853
+ });
854
+
855
+ // src/client/client.gen.ts
856
+ var client = createClient(createClientConfig(createConfig()));
857
+
858
+ // src/react/useChat.ts
859
+ function useChat(options) {
860
+ const { getToken, onData: globalOnData, onFinish, onError } = options || {};
861
+ const [isLoading, setIsLoading] = (0, import_react.useState)(false);
862
+ const abortControllerRef = (0, import_react.useRef)(null);
863
+ const stop = (0, import_react.useCallback)(() => {
864
+ if (abortControllerRef.current) {
865
+ abortControllerRef.current.abort();
866
+ abortControllerRef.current = null;
867
+ }
868
+ }, []);
869
+ (0, import_react.useEffect)(() => {
870
+ return () => {
871
+ if (abortControllerRef.current) {
872
+ abortControllerRef.current.abort();
873
+ abortControllerRef.current = null;
874
+ }
875
+ };
876
+ }, []);
877
+ const sendMessage = (0, import_react.useCallback)(
878
+ async ({
879
+ messages,
880
+ model,
881
+ onData
882
+ }) => {
883
+ if (!messages?.length) {
884
+ const errorMsg = "messages are required to call sendMessage.";
885
+ if (onError) onError(new Error(errorMsg));
886
+ return { data: null, error: errorMsg };
887
+ }
888
+ if (!model) {
889
+ const errorMsg = "model is required to call sendMessage.";
890
+ if (onError) onError(new Error(errorMsg));
891
+ return { data: null, error: errorMsg };
892
+ }
893
+ if (!getToken) {
894
+ const errorMsg = "Token getter function is required.";
895
+ if (onError) onError(new Error(errorMsg));
896
+ return { data: null, error: errorMsg };
897
+ }
898
+ if (abortControllerRef.current) {
899
+ abortControllerRef.current.abort();
900
+ }
901
+ const abortController = new AbortController();
902
+ abortControllerRef.current = abortController;
903
+ setIsLoading(true);
904
+ try {
905
+ const token = await getToken();
906
+ if (!token) {
907
+ const errorMsg = "No access token available.";
908
+ setIsLoading(false);
909
+ if (onError) onError(new Error(errorMsg));
910
+ return { data: null, error: errorMsg };
911
+ }
912
+ const sseResult = await client.sse.post({
913
+ url: "/api/v1/chat/completions",
914
+ body: {
915
+ messages,
916
+ model,
917
+ stream: true
918
+ },
919
+ headers: {
920
+ "Content-Type": "application/json",
921
+ Authorization: `Bearer ${token}`
922
+ },
923
+ signal: abortController.signal
924
+ });
925
+ let accumulatedContent = "";
926
+ let completionId = "";
927
+ let completionModel = "";
928
+ let usage;
929
+ let finishReason;
930
+ for await (const chunk of sseResult.stream) {
931
+ if (typeof chunk === "string" && (chunk.trim() === "[DONE]" || chunk.includes("[DONE]"))) {
932
+ continue;
933
+ }
934
+ if (chunk && typeof chunk === "object") {
935
+ const chunkData = chunk;
936
+ if (chunkData.id && !completionId) {
937
+ completionId = chunkData.id;
938
+ }
939
+ if (chunkData.model && !completionModel) {
940
+ completionModel = chunkData.model;
941
+ }
942
+ if (chunkData.usage) {
943
+ usage = chunkData.usage;
944
+ }
945
+ if (chunkData.choices && Array.isArray(chunkData.choices) && chunkData.choices.length > 0) {
946
+ const choice = chunkData.choices[0];
947
+ if (choice.delta?.content) {
948
+ const content = choice.delta.content;
949
+ accumulatedContent += content;
950
+ if (onData) {
951
+ onData(content);
952
+ }
953
+ if (globalOnData) {
954
+ globalOnData(content);
955
+ }
956
+ }
957
+ if (choice.finish_reason) {
958
+ finishReason = choice.finish_reason;
959
+ }
960
+ }
961
+ }
962
+ }
963
+ const completion = {
964
+ id: completionId,
965
+ model: completionModel,
966
+ choices: [
967
+ {
968
+ index: 0,
969
+ message: {
970
+ role: "assistant",
971
+ content: accumulatedContent
972
+ },
973
+ finish_reason: finishReason
974
+ }
975
+ ],
976
+ usage
977
+ };
978
+ setIsLoading(false);
979
+ if (onFinish) {
980
+ onFinish(completion);
981
+ }
982
+ return { data: completion, error: null };
983
+ } catch (err) {
984
+ if (err instanceof Error && err.name === "AbortError") {
985
+ setIsLoading(false);
986
+ return { data: null, error: "Request aborted" };
987
+ }
988
+ const errorMsg = err instanceof Error ? err.message : "Failed to send message.";
989
+ const errorObj = err instanceof Error ? err : new Error(errorMsg);
990
+ setIsLoading(false);
991
+ if (onError) {
992
+ onError(errorObj);
993
+ }
994
+ return { data: null, error: errorMsg };
995
+ } finally {
996
+ if (abortControllerRef.current === abortController) {
997
+ abortControllerRef.current = null;
998
+ }
999
+ }
1000
+ },
1001
+ [getToken, globalOnData, onFinish, onError]
1002
+ );
1003
+ return {
1004
+ isLoading,
1005
+ sendMessage,
1006
+ stop
1007
+ };
1008
+ }
1009
+
1010
+ // src/react/useMemory.ts
1011
+ var import_react2 = require("react");
1012
+ var import_client6 = require("@reverbia/sdk");
1013
+
1014
+ // src/lib/memory/service.ts
1015
+ var FACT_EXTRACTION_PROMPT = `You are a memory extraction system. Extract durable user memories from chat messages.
1016
+
1017
+ CRITICAL: You MUST respond with ONLY valid JSON. No explanations, no markdown, no code blocks, just pure JSON.
1018
+
1019
+ Only extract facts that will be useful in future conversations, such as identity, stable preferences, ongoing projects, skills, and constraints.
1020
+
1021
+ Do not extract sensitive attributes, temporary things, or single-use instructions.
1022
+
1023
+ If there are no memories to extract, return: {"items": []}
1024
+
1025
+ Response format (JSON only, no other text):
1026
+
1027
+ {
1028
+ "items": [
1029
+ {
1030
+ "type": "identity",
1031
+ "namespace": "identity",
1032
+ "key": "name",
1033
+ "value": "Charlie",
1034
+ "rawEvidence": "I'm Charlie",
1035
+ "confidence": 0.98,
1036
+ "pii": true
1037
+ },
1038
+ {
1039
+ "type": "identity",
1040
+ "namespace": "work",
1041
+ "key": "company",
1042
+ "value": "ZetaChain",
1043
+ "rawEvidence": "called ZetaChain",
1044
+ "confidence": 0.99,
1045
+ "pii": false
1046
+ },
1047
+ {
1048
+ "type": "preference",
1049
+ "namespace": "answer_style",
1050
+ "key": "verbosity",
1051
+ "value": "concise_direct",
1052
+ "rawEvidence": "I prefer concise, direct answers",
1053
+ "confidence": 0.96,
1054
+ "pii": false
1055
+ },
1056
+ {
1057
+ "type": "identity",
1058
+ "namespace": "timezone",
1059
+ "key": "tz",
1060
+ "value": "America/Los_Angeles",
1061
+ "rawEvidence": "I'm in PST",
1062
+ "confidence": 0.9,
1063
+ "pii": false
1064
+ }
1065
+ ]
1066
+ }`;
1067
+ var preprocessMemories = (items, minConfidence = 0.6) => {
1068
+ if (!items || !Array.isArray(items)) {
1069
+ return [];
1070
+ }
1071
+ const validItems = items.filter((item) => {
1072
+ if (item.namespace == null || item.key == null || item.value == null) {
1073
+ console.warn(
1074
+ "Dropping memory item with null/undefined namespace, key, or value:",
1075
+ item
1076
+ );
1077
+ return false;
1058
1078
  }
1059
- const error = jsonError ?? textError;
1060
- let finalError = error;
1061
- for (const fn of interceptors.error.fns) {
1062
- if (fn) {
1063
- finalError = await fn(error, response, opts);
1064
- }
1079
+ const namespace = String(item.namespace).trim();
1080
+ const key = String(item.key).trim();
1081
+ const value = String(item.value).trim();
1082
+ if (namespace === "" || key === "" || value === "") {
1083
+ console.warn(
1084
+ "Dropping memory item with empty namespace, key, or value after trimming:",
1085
+ item
1086
+ );
1087
+ return false;
1065
1088
  }
1066
- finalError = finalError || {};
1067
- if (opts.throwOnError) {
1068
- throw finalError;
1089
+ if (typeof item.confidence !== "number" || item.confidence < minConfidence) {
1090
+ console.warn(
1091
+ `Dropping memory item with confidence ${item.confidence} below threshold ${minConfidence}:`,
1092
+ item
1093
+ );
1094
+ return false;
1069
1095
  }
1070
- return {
1071
- error: finalError,
1072
- ...result
1096
+ return true;
1097
+ });
1098
+ const deduplicatedMap = /* @__PURE__ */ new Map();
1099
+ for (const item of validItems) {
1100
+ const uniqueKey = `${item.namespace}:${item.key}:${item.value}`;
1101
+ const existing = deduplicatedMap.get(uniqueKey);
1102
+ if (!existing || item.confidence > existing.confidence) {
1103
+ deduplicatedMap.set(uniqueKey, item);
1104
+ } else {
1105
+ console.debug(
1106
+ `Deduplicating memory item: keeping entry with higher confidence (${existing.confidence} > ${item.confidence})`,
1107
+ { namespace: item.namespace, key: item.key, value: item.value }
1108
+ );
1109
+ }
1110
+ }
1111
+ return Array.from(deduplicatedMap.values());
1112
+ };
1113
+
1114
+ // src/lib/memory/db.ts
1115
+ var import_dexie = __toESM(require("dexie"));
1116
+ var MemoryDatabase = class extends import_dexie.default {
1117
+ constructor() {
1118
+ super("MemoryDatabase");
1119
+ this.version(2).stores({
1120
+ memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
1121
+ });
1122
+ this.version(3).stores({
1123
+ memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
1124
+ });
1125
+ }
1126
+ };
1127
+ var memoryDb = new MemoryDatabase();
1128
+ var saveMemory = async (memory) => {
1129
+ const compositeKey = `${memory.namespace}:${memory.key}`;
1130
+ const uniqueKey = `${memory.namespace}:${memory.key}:${memory.value}`;
1131
+ const now = Date.now();
1132
+ const existing = await memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
1133
+ if (existing) {
1134
+ const shouldPreserveEmbedding = existing.value === memory.value && existing.rawEvidence === memory.rawEvidence && existing.type === memory.type && existing.namespace === memory.namespace && existing.key === memory.key && existing.embedding !== void 0 && existing.embedding.length > 0;
1135
+ const updateData = {
1136
+ ...memory,
1137
+ compositeKey,
1138
+ uniqueKey,
1139
+ updatedAt: now,
1140
+ createdAt: existing.createdAt
1073
1141
  };
1074
- };
1075
- const makeMethodFn = (method) => (options) => request({ ...options, method });
1076
- const makeSseFn = (method) => async (options) => {
1077
- const { opts, url } = await beforeRequest(options);
1078
- return createSseClient({
1079
- ...opts,
1080
- body: opts.body,
1081
- headers: opts.headers,
1082
- method,
1083
- onRequest: async (url2, init) => {
1084
- let request2 = new Request(url2, init);
1085
- const requestInit = {
1086
- ...init,
1087
- method: init.method,
1088
- url: url2
1089
- };
1090
- for (const fn of interceptors.request.fns) {
1091
- if (fn) {
1092
- await fn(requestInit);
1093
- request2 = new Request(requestInit.url, requestInit);
1094
- }
1095
- }
1096
- return request2;
1097
- },
1098
- url
1142
+ if (shouldPreserveEmbedding) {
1143
+ updateData.embedding = existing.embedding;
1144
+ updateData.embeddingModel = existing.embeddingModel;
1145
+ } else {
1146
+ updateData.embedding = [];
1147
+ updateData.embeddingModel = void 0;
1148
+ }
1149
+ await memoryDb.memories.update(existing.id, updateData);
1150
+ } else {
1151
+ await memoryDb.memories.add({
1152
+ ...memory,
1153
+ compositeKey,
1154
+ uniqueKey,
1155
+ createdAt: now,
1156
+ updatedAt: now
1099
1157
  });
1100
- };
1101
- return {
1102
- buildUrl,
1103
- connect: makeMethodFn("CONNECT"),
1104
- delete: makeMethodFn("DELETE"),
1105
- get: makeMethodFn("GET"),
1106
- getConfig,
1107
- head: makeMethodFn("HEAD"),
1108
- interceptors,
1109
- options: makeMethodFn("OPTIONS"),
1110
- patch: makeMethodFn("PATCH"),
1111
- post: makeMethodFn("POST"),
1112
- put: makeMethodFn("PUT"),
1113
- request,
1114
- setConfig,
1115
- sse: {
1116
- connect: makeSseFn("CONNECT"),
1117
- delete: makeSseFn("DELETE"),
1118
- get: makeSseFn("GET"),
1119
- head: makeSseFn("HEAD"),
1120
- options: makeSseFn("OPTIONS"),
1121
- patch: makeSseFn("PATCH"),
1122
- post: makeSseFn("POST"),
1123
- put: makeSseFn("PUT"),
1124
- trace: makeSseFn("TRACE")
1125
- },
1126
- trace: makeMethodFn("TRACE")
1127
- };
1158
+ }
1159
+ };
1160
+ var saveMemories = async (memories) => {
1161
+ await Promise.all(memories.map((memory) => saveMemory(memory)));
1162
+ };
1163
+ var getAllMemories = async () => {
1164
+ return memoryDb.memories.toArray();
1165
+ };
1166
+ var cosineSimilarity = (a, b) => {
1167
+ if (a.length !== b.length) {
1168
+ throw new Error("Vectors must have the same length");
1169
+ }
1170
+ let dotProduct = 0;
1171
+ let normA = 0;
1172
+ let normB = 0;
1173
+ for (let i = 0; i < a.length; i++) {
1174
+ dotProduct += a[i] * b[i];
1175
+ normA += a[i] * a[i];
1176
+ normB += b[i] * b[i];
1177
+ }
1178
+ const denominator = Math.sqrt(normA) * Math.sqrt(normB);
1179
+ if (denominator === 0) {
1180
+ return 0;
1181
+ }
1182
+ return dotProduct / denominator;
1183
+ };
1184
+ var searchSimilarMemories = async (queryEmbedding, limit = 10, minSimilarity = 0.6) => {
1185
+ const allMemories = await getAllMemories();
1186
+ const memoriesWithEmbeddings = allMemories.filter(
1187
+ (m) => m.embedding && m.embedding.length > 0
1188
+ );
1189
+ console.log(
1190
+ `[Memory Search] Total memories: ${allMemories.length}, memories with embeddings: ${memoriesWithEmbeddings.length}`
1191
+ );
1192
+ if (memoriesWithEmbeddings.length === 0) {
1193
+ console.warn(
1194
+ "[Memory Search] No memories with embeddings found. Memories may need embeddings generated. Use generateAndStoreEmbeddings() to generate embeddings for existing memories."
1195
+ );
1196
+ return [];
1197
+ }
1198
+ const allResults = memoriesWithEmbeddings.map((memory) => {
1199
+ const similarity = cosineSimilarity(queryEmbedding, memory.embedding);
1200
+ return {
1201
+ ...memory,
1202
+ similarity
1203
+ };
1204
+ }).sort((a, b) => b.similarity - a.similarity);
1205
+ console.log(
1206
+ `[Memory Search] All similarity scores:`,
1207
+ allResults.map((r) => ({
1208
+ key: `${r.namespace}:${r.key}`,
1209
+ value: r.value,
1210
+ similarity: r.similarity.toFixed(4)
1211
+ }))
1212
+ );
1213
+ const results = allResults.filter((result) => result.similarity >= minSimilarity).slice(0, limit);
1214
+ if (results.length === 0 && allResults.length > 0) {
1215
+ const topSimilarity = allResults[0].similarity;
1216
+ const suggestedThreshold = Math.max(0.3, topSimilarity - 0.1);
1217
+ console.warn(
1218
+ `[Memory Search] No memories above threshold ${minSimilarity}. Highest similarity was ${topSimilarity.toFixed(4)}. Consider lowering the threshold to ${suggestedThreshold.toFixed(2)}`
1219
+ );
1220
+ } else {
1221
+ console.log(
1222
+ `[Memory Search] Found ${results.length} memories above similarity threshold ${minSimilarity}. Top similarity: ${results[0]?.similarity.toFixed(4) || "N/A"}`
1223
+ );
1224
+ }
1225
+ return results;
1128
1226
  };
1129
-
1130
- // src/clientConfig.ts
1131
- var createClientConfig = (config) => ({
1132
- ...config,
1133
- baseUrl: "https://ai-portal-dev.zetachain.com"
1134
- });
1135
-
1136
- // src/client/client.gen.ts
1137
- var client = createClient(createClientConfig(createConfig()));
1138
1227
 
1139
1228
  // src/client/sdk.gen.ts
1140
1229
  var postApiV1Embeddings = (options) => {