@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.
- package/dist/react/index.cjs +706 -617
- package/dist/react/index.d.mts +57 -3
- package/dist/react/index.d.ts +57 -3
- package/dist/react/index.mjs +452 -365
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
178
|
+
break;
|
|
179
|
+
} catch (error) {
|
|
180
|
+
onSseError?.(error);
|
|
181
|
+
if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
|
|
182
|
+
break;
|
|
90
183
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
"
|
|
133
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
|
279
|
+
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
280
280
|
};
|
|
281
|
-
var
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (
|
|
290
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
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
|
-
|
|
1072
|
-
|
|
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
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
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
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
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) => {
|