@nexusm/sdk 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/index.d.mts +2572 -0
- package/dist/index.d.ts +2572 -0
- package/dist/index.js +1513 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1444 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +64 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1444 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
var DEFAULT_CACHE = {
|
|
3
|
+
max: 1e3,
|
|
4
|
+
ttl: 300
|
|
5
|
+
// 5 minutes
|
|
6
|
+
};
|
|
7
|
+
var DEFAULT_RETRY = {
|
|
8
|
+
maxRetries: 3,
|
|
9
|
+
initialDelay: 1e3,
|
|
10
|
+
maxDelay: 1e4,
|
|
11
|
+
backoffFactor: 2
|
|
12
|
+
};
|
|
13
|
+
var DEFAULT_CONFIG = {
|
|
14
|
+
baseUrl: "http://localhost:8001/v1",
|
|
15
|
+
timeout: 3e4,
|
|
16
|
+
// 30 seconds
|
|
17
|
+
cache: DEFAULT_CACHE,
|
|
18
|
+
retry: DEFAULT_RETRY
|
|
19
|
+
};
|
|
20
|
+
function resolveConfig(userConfig) {
|
|
21
|
+
if (!userConfig.apiKey) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
'NexusConfig: "apiKey" is required and must be a non-empty string.'
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
let cache;
|
|
27
|
+
if (userConfig.cache === false) {
|
|
28
|
+
cache = false;
|
|
29
|
+
} else if (userConfig.cache) {
|
|
30
|
+
cache = { ...DEFAULT_CACHE, ...userConfig.cache };
|
|
31
|
+
} else {
|
|
32
|
+
cache = { ...DEFAULT_CACHE };
|
|
33
|
+
}
|
|
34
|
+
let retry;
|
|
35
|
+
if (userConfig.retry === false) {
|
|
36
|
+
retry = false;
|
|
37
|
+
} else if (userConfig.retry) {
|
|
38
|
+
retry = { ...DEFAULT_RETRY, ...userConfig.retry };
|
|
39
|
+
} else {
|
|
40
|
+
retry = { ...DEFAULT_RETRY };
|
|
41
|
+
}
|
|
42
|
+
const rawBaseUrl = userConfig.baseUrl ?? DEFAULT_CONFIG.baseUrl;
|
|
43
|
+
const baseUrl = rawBaseUrl.replace(/\/+$/, "");
|
|
44
|
+
return {
|
|
45
|
+
apiKey: userConfig.apiKey,
|
|
46
|
+
tenantId: userConfig.tenantId,
|
|
47
|
+
baseUrl,
|
|
48
|
+
timeout: userConfig.timeout ?? DEFAULT_CONFIG.timeout,
|
|
49
|
+
cache,
|
|
50
|
+
retry,
|
|
51
|
+
offline: userConfig.offline,
|
|
52
|
+
autoErrorReport: userConfig.autoErrorReport ?? false
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/http/client.ts
|
|
57
|
+
import axios from "axios";
|
|
58
|
+
|
|
59
|
+
// src/errors/base.ts
|
|
60
|
+
var NexusError = class extends Error {
|
|
61
|
+
constructor(message, code, cause) {
|
|
62
|
+
super(message);
|
|
63
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
64
|
+
this.name = "NexusError";
|
|
65
|
+
this.code = code;
|
|
66
|
+
this.cause = cause;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var ConfigurationError = class extends NexusError {
|
|
70
|
+
constructor(message, cause) {
|
|
71
|
+
super(message, "NEXUS_CONFIGURATION_ERROR", cause);
|
|
72
|
+
this.name = "ConfigurationError";
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var NetworkError = class extends NexusError {
|
|
76
|
+
constructor(message, cause) {
|
|
77
|
+
super(message, "NEXUS_NETWORK_ERROR", cause);
|
|
78
|
+
this.name = "NetworkError";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
var TimeoutError = class extends NexusError {
|
|
82
|
+
constructor(message, cause) {
|
|
83
|
+
super(message, "NEXUS_TIMEOUT_ERROR", cause);
|
|
84
|
+
this.name = "TimeoutError";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/errors/api.ts
|
|
89
|
+
function extractMessage(data, fallback) {
|
|
90
|
+
if (data && typeof data === "object") {
|
|
91
|
+
const body = data;
|
|
92
|
+
return body.detail ?? body.message ?? fallback;
|
|
93
|
+
}
|
|
94
|
+
return fallback;
|
|
95
|
+
}
|
|
96
|
+
var ApiError = class _ApiError extends NexusError {
|
|
97
|
+
constructor(message, statusCode, response, code = "NEXUS_API_ERROR") {
|
|
98
|
+
super(message, code);
|
|
99
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
100
|
+
this.name = "ApiError";
|
|
101
|
+
this.statusCode = statusCode;
|
|
102
|
+
this.response = response;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create the most specific `ApiError` subclass from an Axios response.
|
|
106
|
+
*
|
|
107
|
+
* | Status | Error class |
|
|
108
|
+
* |--------|------------------------|
|
|
109
|
+
* | 400 | `ValidationError` |
|
|
110
|
+
* | 401 | `AuthenticationError` |
|
|
111
|
+
* | 404 | `NotFoundError` |
|
|
112
|
+
* | 429 | `RateLimitError` |
|
|
113
|
+
* | other | `ApiError` |
|
|
114
|
+
*/
|
|
115
|
+
static fromResponse(response) {
|
|
116
|
+
const { status, data, headers } = response;
|
|
117
|
+
switch (status) {
|
|
118
|
+
case 400: {
|
|
119
|
+
const msg = extractMessage(data, "Validation failed");
|
|
120
|
+
const details = data && typeof data === "object" ? data.errors : void 0;
|
|
121
|
+
return new ValidationError(msg, details, data);
|
|
122
|
+
}
|
|
123
|
+
case 401: {
|
|
124
|
+
const msg = extractMessage(data, "Authentication failed");
|
|
125
|
+
return new AuthenticationError(msg, data);
|
|
126
|
+
}
|
|
127
|
+
case 404: {
|
|
128
|
+
const msg = extractMessage(data, "Resource not found");
|
|
129
|
+
return new NotFoundError(msg, data);
|
|
130
|
+
}
|
|
131
|
+
case 429: {
|
|
132
|
+
const msg = extractMessage(data, "Rate limit exceeded");
|
|
133
|
+
const retryAfter = headers?.["retry-after"] ? Number(headers["retry-after"]) : void 0;
|
|
134
|
+
return new RateLimitError(msg, retryAfter, data);
|
|
135
|
+
}
|
|
136
|
+
default: {
|
|
137
|
+
const msg = extractMessage(
|
|
138
|
+
data,
|
|
139
|
+
`API request failed with status ${status}`
|
|
140
|
+
);
|
|
141
|
+
return new _ApiError(msg, status, data);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var AuthenticationError = class extends ApiError {
|
|
147
|
+
constructor(message, response) {
|
|
148
|
+
super(message, 401, response, "NEXUS_AUTHENTICATION_ERROR");
|
|
149
|
+
this.name = "AuthenticationError";
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
var RateLimitError = class extends ApiError {
|
|
153
|
+
constructor(message, retryAfter, response) {
|
|
154
|
+
super(message, 429, response, "NEXUS_RATE_LIMIT_ERROR");
|
|
155
|
+
this.name = "RateLimitError";
|
|
156
|
+
this.retryAfter = retryAfter;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
var ValidationError = class extends ApiError {
|
|
160
|
+
constructor(message, details, response) {
|
|
161
|
+
super(message, 400, response, "NEXUS_VALIDATION_ERROR");
|
|
162
|
+
this.name = "ValidationError";
|
|
163
|
+
this.details = details;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var NotFoundError = class extends ApiError {
|
|
167
|
+
constructor(message, response) {
|
|
168
|
+
super(message, 404, response, "NEXUS_NOT_FOUND_ERROR");
|
|
169
|
+
this.name = "NotFoundError";
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// src/http/cache.ts
|
|
174
|
+
import { LRUCache } from "lru-cache";
|
|
175
|
+
var CACHEABLE_POST_PATHS = /* @__PURE__ */ new Set([
|
|
176
|
+
"/context/retrieve",
|
|
177
|
+
"/memories/search",
|
|
178
|
+
"/knowledge/query"
|
|
179
|
+
]);
|
|
180
|
+
function isCacheablePost(path) {
|
|
181
|
+
return CACHEABLE_POST_PATHS.has(path);
|
|
182
|
+
}
|
|
183
|
+
function stableHash(value) {
|
|
184
|
+
const json = JSON.stringify(value, (_key, val) => {
|
|
185
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val)) {
|
|
186
|
+
return Object.keys(val).sort().reduce((sorted, k) => {
|
|
187
|
+
sorted[k] = val[k];
|
|
188
|
+
return sorted;
|
|
189
|
+
}, {});
|
|
190
|
+
}
|
|
191
|
+
return val;
|
|
192
|
+
});
|
|
193
|
+
let hash = 5381;
|
|
194
|
+
for (let i = 0; i < json.length; i++) {
|
|
195
|
+
hash = (hash << 5) + hash + json.charCodeAt(i) | 0;
|
|
196
|
+
}
|
|
197
|
+
return (hash >>> 0).toString(36);
|
|
198
|
+
}
|
|
199
|
+
var CacheManager = class {
|
|
200
|
+
/**
|
|
201
|
+
* Create a new cache manager.
|
|
202
|
+
*
|
|
203
|
+
* @param config - Resolved cache configuration, or `false` to disable.
|
|
204
|
+
*/
|
|
205
|
+
constructor(config) {
|
|
206
|
+
/** Running hit counter. */
|
|
207
|
+
this._hits = 0;
|
|
208
|
+
/** Running miss counter. */
|
|
209
|
+
this._misses = 0;
|
|
210
|
+
if (config === false) {
|
|
211
|
+
this.enabled = false;
|
|
212
|
+
this.cache = new LRUCache({ max: 1 });
|
|
213
|
+
} else {
|
|
214
|
+
this.enabled = true;
|
|
215
|
+
this.cache = new LRUCache({
|
|
216
|
+
max: config.max,
|
|
217
|
+
ttl: config.ttl * 1e3
|
|
218
|
+
// seconds -> milliseconds
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// -----------------------------------------------------------------------
|
|
223
|
+
// Key generation
|
|
224
|
+
// -----------------------------------------------------------------------
|
|
225
|
+
/**
|
|
226
|
+
* Generate a deterministic cache key from the request signature.
|
|
227
|
+
*
|
|
228
|
+
* Format: `METHOD:path:hash(params)`
|
|
229
|
+
*
|
|
230
|
+
* @param method - HTTP method (e.g. `GET`, `POST`).
|
|
231
|
+
* @param path - Request path (e.g. `/memories/search`).
|
|
232
|
+
* @param params - Query parameters or request body (optional).
|
|
233
|
+
* @returns A string suitable for use as a cache key.
|
|
234
|
+
*/
|
|
235
|
+
generateKey(method, path, params) {
|
|
236
|
+
const base = `${method.toUpperCase()}:${path}`;
|
|
237
|
+
if (params === void 0 || params === null) {
|
|
238
|
+
return base;
|
|
239
|
+
}
|
|
240
|
+
return `${base}:${stableHash(params)}`;
|
|
241
|
+
}
|
|
242
|
+
// -----------------------------------------------------------------------
|
|
243
|
+
// Core operations
|
|
244
|
+
// -----------------------------------------------------------------------
|
|
245
|
+
/**
|
|
246
|
+
* Retrieve a cached value.
|
|
247
|
+
*
|
|
248
|
+
* @typeParam T - Expected type of the cached value.
|
|
249
|
+
* @param key - Cache key (as returned by {@link generateKey}).
|
|
250
|
+
* @returns The cached value, or `undefined` on a miss.
|
|
251
|
+
*/
|
|
252
|
+
get(key) {
|
|
253
|
+
if (!this.enabled) {
|
|
254
|
+
return void 0;
|
|
255
|
+
}
|
|
256
|
+
const value = this.cache.get(key);
|
|
257
|
+
if (value !== void 0) {
|
|
258
|
+
this._hits++;
|
|
259
|
+
return value;
|
|
260
|
+
}
|
|
261
|
+
this._misses++;
|
|
262
|
+
return void 0;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Store a value in the cache.
|
|
266
|
+
*
|
|
267
|
+
* @param key - Cache key.
|
|
268
|
+
* @param value - Value to cache.
|
|
269
|
+
*/
|
|
270
|
+
set(key, value) {
|
|
271
|
+
if (!this.enabled) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
this.cache.set(key, value);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Invalidate all cache entries whose key contains the given pattern.
|
|
278
|
+
*
|
|
279
|
+
* This is typically called after a write operation to evict stale
|
|
280
|
+
* read results. For example, after `POST /memories`, calling
|
|
281
|
+
* `invalidate('/memories')` removes all cached memory queries.
|
|
282
|
+
*
|
|
283
|
+
* @param pattern - Substring to match against cache keys.
|
|
284
|
+
*/
|
|
285
|
+
invalidate(pattern) {
|
|
286
|
+
if (!this.enabled) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
for (const key of this.cache.keys()) {
|
|
290
|
+
if (key.includes(pattern)) {
|
|
291
|
+
this.cache.delete(key);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Remove all entries from the cache and reset counters.
|
|
297
|
+
*/
|
|
298
|
+
clear() {
|
|
299
|
+
if (!this.enabled) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
this.cache.clear();
|
|
303
|
+
this._hits = 0;
|
|
304
|
+
this._misses = 0;
|
|
305
|
+
}
|
|
306
|
+
// -----------------------------------------------------------------------
|
|
307
|
+
// Observability
|
|
308
|
+
// -----------------------------------------------------------------------
|
|
309
|
+
/**
|
|
310
|
+
* Current cache statistics.
|
|
311
|
+
*
|
|
312
|
+
* Useful for logging, health checks, and dashboards.
|
|
313
|
+
*/
|
|
314
|
+
get stats() {
|
|
315
|
+
return {
|
|
316
|
+
size: this.enabled ? this.cache.size : 0,
|
|
317
|
+
hits: this._hits,
|
|
318
|
+
misses: this._misses
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// src/http/retry.ts
|
|
324
|
+
var RetryManager = class {
|
|
325
|
+
/**
|
|
326
|
+
* Create a new retry manager.
|
|
327
|
+
*
|
|
328
|
+
* @param config - Fully-resolved retry settings, or `false` to disable retries entirely.
|
|
329
|
+
*/
|
|
330
|
+
constructor(config) {
|
|
331
|
+
this.config = config;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Determine whether a given error is eligible for retry.
|
|
335
|
+
*
|
|
336
|
+
* Retryable conditions:
|
|
337
|
+
* - {@link NetworkError} -- transient connectivity issues
|
|
338
|
+
* - {@link TimeoutError} -- request exceeded its deadline
|
|
339
|
+
* - {@link RateLimitError} (HTTP 429) -- server asks us to slow down
|
|
340
|
+
* - Any {@link ApiError} with a 5xx status code -- server-side failures
|
|
341
|
+
*
|
|
342
|
+
* Non-retryable conditions:
|
|
343
|
+
* - 4xx errors other than 429 (client errors that won't resolve on retry)
|
|
344
|
+
* - Cancelled / aborted requests
|
|
345
|
+
* - Any non-Nexus error (unknown failures are not assumed to be transient)
|
|
346
|
+
*
|
|
347
|
+
* @param error - The error to evaluate.
|
|
348
|
+
* @returns `true` if the operation should be retried.
|
|
349
|
+
*/
|
|
350
|
+
isRetryable(error) {
|
|
351
|
+
if (error instanceof NetworkError) {
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
if (error instanceof TimeoutError) {
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
if (error instanceof RateLimitError) {
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
if (error instanceof ApiError) {
|
|
361
|
+
return error.statusCode >= 500 && error.statusCode < 600;
|
|
362
|
+
}
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Calculate the delay (in milliseconds) before the next retry attempt.
|
|
367
|
+
*
|
|
368
|
+
* Uses exponential back-off: `delay = initialDelay * backoffFactor ^ attempt`.
|
|
369
|
+
*
|
|
370
|
+
* Special cases:
|
|
371
|
+
* - If the error is a {@link RateLimitError} with a `retryAfter` value,
|
|
372
|
+
* that value (converted to ms) takes precedence over the computed delay.
|
|
373
|
+
* - A random jitter of ±10% is applied to prevent thundering herd.
|
|
374
|
+
* - The result is clamped to {@link ResolvedRetryConfig.maxDelay}.
|
|
375
|
+
*
|
|
376
|
+
* @param attempt - Zero-based attempt index (0 = first retry).
|
|
377
|
+
* @param error - The error that triggered the retry (optional).
|
|
378
|
+
* @returns Delay in milliseconds before the next attempt.
|
|
379
|
+
*/
|
|
380
|
+
getDelay(attempt, error) {
|
|
381
|
+
if (this.config === false) {
|
|
382
|
+
return 0;
|
|
383
|
+
}
|
|
384
|
+
const { initialDelay, backoffFactor, maxDelay } = this.config;
|
|
385
|
+
if (error instanceof RateLimitError && error.retryAfter != null) {
|
|
386
|
+
const serverDelay = error.retryAfter * 1e3;
|
|
387
|
+
return Math.min(this.applyJitter(serverDelay), maxDelay);
|
|
388
|
+
}
|
|
389
|
+
const exponentialDelay = initialDelay * Math.pow(backoffFactor, attempt);
|
|
390
|
+
return Math.min(this.applyJitter(exponentialDelay), maxDelay);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Execute an async function with automatic retries on transient failures.
|
|
394
|
+
*
|
|
395
|
+
* If retries are disabled (`config === false`), the function is invoked
|
|
396
|
+
* exactly once with no retry logic.
|
|
397
|
+
*
|
|
398
|
+
* @typeParam T - Return type of the wrapped function.
|
|
399
|
+
* @param fn - The async operation to execute (and potentially retry).
|
|
400
|
+
* @returns The resolved value of `fn`.
|
|
401
|
+
* @throws The last error encountered if all retry attempts are exhausted,
|
|
402
|
+
* or immediately if the error is not retryable.
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* const manager = new RetryManager({ maxRetries: 3, initialDelay: 500, maxDelay: 5000, backoffFactor: 2 });
|
|
407
|
+
*
|
|
408
|
+
* const data = await manager.execute(async () => {
|
|
409
|
+
* return fetch('/api/data').then(r => r.json());
|
|
410
|
+
* });
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
async execute(fn) {
|
|
414
|
+
if (this.config === false) {
|
|
415
|
+
return fn();
|
|
416
|
+
}
|
|
417
|
+
const { maxRetries } = this.config;
|
|
418
|
+
let lastError;
|
|
419
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
420
|
+
try {
|
|
421
|
+
return await fn();
|
|
422
|
+
} catch (error) {
|
|
423
|
+
lastError = error;
|
|
424
|
+
if (!this.isRetryable(error)) {
|
|
425
|
+
throw error;
|
|
426
|
+
}
|
|
427
|
+
if (attempt >= maxRetries) {
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
430
|
+
const delay = this.getDelay(attempt, error);
|
|
431
|
+
await this.sleep(delay);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
throw lastError;
|
|
435
|
+
}
|
|
436
|
+
// ---------------------------------------------------------------------------
|
|
437
|
+
// Private helpers
|
|
438
|
+
// ---------------------------------------------------------------------------
|
|
439
|
+
/**
|
|
440
|
+
* Apply ±10% random jitter to a delay value.
|
|
441
|
+
*
|
|
442
|
+
* @param delay - Base delay in milliseconds.
|
|
443
|
+
* @returns Jittered delay in milliseconds.
|
|
444
|
+
*/
|
|
445
|
+
applyJitter(delay) {
|
|
446
|
+
const jitterFactor = 0.9 + Math.random() * 0.2;
|
|
447
|
+
return Math.round(delay * jitterFactor);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Sleep for the specified duration.
|
|
451
|
+
*
|
|
452
|
+
* @param ms - Duration in milliseconds.
|
|
453
|
+
*/
|
|
454
|
+
sleep(ms) {
|
|
455
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// src/http/queue.ts
|
|
460
|
+
var OfflineQueue = class {
|
|
461
|
+
/**
|
|
462
|
+
* Create a new offline queue.
|
|
463
|
+
*
|
|
464
|
+
* @param maxSize - Maximum number of requests to buffer. When the queue
|
|
465
|
+
* is full, subsequent {@link enqueue} calls will reject
|
|
466
|
+
* immediately. Defaults to `100`.
|
|
467
|
+
*/
|
|
468
|
+
constructor(maxSize = 100) {
|
|
469
|
+
/** Internal FIFO queue of deferred requests. */
|
|
470
|
+
this.queue = [];
|
|
471
|
+
/** Guard flag to prevent concurrent flush operations. */
|
|
472
|
+
this.processing = false;
|
|
473
|
+
/** Auto-incrementing counter used to generate unique request IDs. */
|
|
474
|
+
this.idCounter = 0;
|
|
475
|
+
this.maxSize = maxSize;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Add a request to the queue.
|
|
479
|
+
*
|
|
480
|
+
* The returned `Promise` settles only when the request is eventually
|
|
481
|
+
* executed during a {@link flush} call.
|
|
482
|
+
*
|
|
483
|
+
* @param request - The request descriptor (method, path, and optional data).
|
|
484
|
+
* @returns A `Promise` that resolves with the executor's return value
|
|
485
|
+
* once the request is flushed, or rejects if the queue is full
|
|
486
|
+
* or the executor fails.
|
|
487
|
+
*
|
|
488
|
+
* @throws {NexusError} If the queue has reached its maximum capacity.
|
|
489
|
+
*/
|
|
490
|
+
enqueue(request) {
|
|
491
|
+
if (this.queue.length >= this.maxSize) {
|
|
492
|
+
return Promise.reject(
|
|
493
|
+
new NexusError(
|
|
494
|
+
`Offline queue is full (max ${this.maxSize}). Request to ${request.method} ${request.path} was rejected.`,
|
|
495
|
+
"NEXUS_QUEUE_FULL"
|
|
496
|
+
)
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
return new Promise((resolve, reject) => {
|
|
500
|
+
this.idCounter += 1;
|
|
501
|
+
const queued = {
|
|
502
|
+
id: `oq_${this.idCounter}_${Date.now()}`,
|
|
503
|
+
method: request.method,
|
|
504
|
+
path: request.path,
|
|
505
|
+
data: request.data,
|
|
506
|
+
resolve,
|
|
507
|
+
reject,
|
|
508
|
+
timestamp: Date.now()
|
|
509
|
+
};
|
|
510
|
+
this.queue.push(queued);
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Process all queued requests in FIFO order.
|
|
515
|
+
*
|
|
516
|
+
* Each request is passed to the provided `executor` function. On success
|
|
517
|
+
* the caller's deferred promise is resolved; on failure it is rejected.
|
|
518
|
+
*
|
|
519
|
+
* Requests are processed sequentially to preserve ordering guarantees.
|
|
520
|
+
* If a flush is already in progress, subsequent calls are silently ignored.
|
|
521
|
+
*
|
|
522
|
+
* @param executor - An async function that performs the actual HTTP call
|
|
523
|
+
* for a given queued request and returns the response.
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* ```typescript
|
|
527
|
+
* await queue.flush(async (req) => {
|
|
528
|
+
* return httpClient.request(req.method, req.path, req.data);
|
|
529
|
+
* });
|
|
530
|
+
* ```
|
|
531
|
+
*/
|
|
532
|
+
async flush(executor) {
|
|
533
|
+
if (this.processing) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
this.processing = true;
|
|
537
|
+
try {
|
|
538
|
+
while (this.queue.length > 0) {
|
|
539
|
+
const request = this.queue.shift();
|
|
540
|
+
try {
|
|
541
|
+
const result = await executor(request);
|
|
542
|
+
request.resolve(result);
|
|
543
|
+
} catch (error) {
|
|
544
|
+
request.reject(error);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
} finally {
|
|
548
|
+
this.processing = false;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* The number of requests currently waiting in the queue.
|
|
553
|
+
*/
|
|
554
|
+
get size() {
|
|
555
|
+
return this.queue.length;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Remove all pending requests from the queue.
|
|
559
|
+
*
|
|
560
|
+
* Every deferred promise is rejected with a cancellation error so that
|
|
561
|
+
* callers are not left hanging indefinitely.
|
|
562
|
+
*/
|
|
563
|
+
clear() {
|
|
564
|
+
while (this.queue.length > 0) {
|
|
565
|
+
const request = this.queue.shift();
|
|
566
|
+
request.reject(
|
|
567
|
+
new NexusError(
|
|
568
|
+
"Request cancelled: offline queue was cleared.",
|
|
569
|
+
"NEXUS_QUEUE_CLEARED"
|
|
570
|
+
)
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
// src/http/client.ts
|
|
577
|
+
var HttpClient = class {
|
|
578
|
+
/**
|
|
579
|
+
* Create a new HTTP client.
|
|
580
|
+
*
|
|
581
|
+
* @param config - Fully-resolved SDK configuration (see {@link resolveConfig}).
|
|
582
|
+
*/
|
|
583
|
+
constructor(config) {
|
|
584
|
+
/** Whether the client is currently considered online. */
|
|
585
|
+
this._isOnline = true;
|
|
586
|
+
this.config = config;
|
|
587
|
+
this.cache = new CacheManager(config.cache);
|
|
588
|
+
this.retry = new RetryManager(config.retry);
|
|
589
|
+
if (config.offline?.enabled) {
|
|
590
|
+
this.offlineQueue = new OfflineQueue(config.offline.maxQueueSize ?? 100);
|
|
591
|
+
}
|
|
592
|
+
this.axios = axios.create({
|
|
593
|
+
baseURL: config.baseUrl,
|
|
594
|
+
timeout: config.timeout
|
|
595
|
+
});
|
|
596
|
+
this.setupRequestInterceptor();
|
|
597
|
+
this.setupResponseInterceptor();
|
|
598
|
+
}
|
|
599
|
+
// -----------------------------------------------------------------------
|
|
600
|
+
// Offline queue support
|
|
601
|
+
// -----------------------------------------------------------------------
|
|
602
|
+
/**
|
|
603
|
+
* Set the online/offline status of the client.
|
|
604
|
+
*
|
|
605
|
+
* When transitioning from offline to online, the queued requests are
|
|
606
|
+
* automatically flushed.
|
|
607
|
+
*
|
|
608
|
+
* @param online - `true` if the client is online, `false` if offline.
|
|
609
|
+
*/
|
|
610
|
+
setOnline(online) {
|
|
611
|
+
const wasOffline = !this._isOnline;
|
|
612
|
+
this._isOnline = online;
|
|
613
|
+
if (wasOffline && online && this.offlineQueue) {
|
|
614
|
+
void this.offlineQueue.flush(async (req) => {
|
|
615
|
+
switch (req.method) {
|
|
616
|
+
case "POST":
|
|
617
|
+
return this.post(req.path, req.data);
|
|
618
|
+
case "PUT":
|
|
619
|
+
return this.put(req.path, req.data);
|
|
620
|
+
case "PATCH":
|
|
621
|
+
return this.patch(req.path, req.data);
|
|
622
|
+
case "DELETE":
|
|
623
|
+
return this.delete(req.path);
|
|
624
|
+
default:
|
|
625
|
+
return this.get(req.path);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Access the offline queue instance (if offline mode is enabled).
|
|
632
|
+
*/
|
|
633
|
+
get queue() {
|
|
634
|
+
return this.offlineQueue;
|
|
635
|
+
}
|
|
636
|
+
// -----------------------------------------------------------------------
|
|
637
|
+
// Public request methods
|
|
638
|
+
// -----------------------------------------------------------------------
|
|
639
|
+
/**
|
|
640
|
+
* Send a GET request.
|
|
641
|
+
*
|
|
642
|
+
* @typeParam T - Expected shape of the response body.
|
|
643
|
+
* @param path - URL path relative to the base URL (e.g. `/memory/search`).
|
|
644
|
+
* @param params - Optional query parameters.
|
|
645
|
+
* @param signal - Optional {@link AbortSignal} to cancel the request.
|
|
646
|
+
* @returns The parsed response body.
|
|
647
|
+
*/
|
|
648
|
+
async get(path, params, signal) {
|
|
649
|
+
const cacheKey = this.cache.generateKey("GET", path, params);
|
|
650
|
+
const cached = this.cache.get(cacheKey);
|
|
651
|
+
if (cached !== void 0) return cached;
|
|
652
|
+
const result = await this.retry.execute(async () => {
|
|
653
|
+
const response = await this.axios.get(path, { params, signal });
|
|
654
|
+
return response.data;
|
|
655
|
+
});
|
|
656
|
+
this.cache.set(cacheKey, result);
|
|
657
|
+
return result;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Send a POST request.
|
|
661
|
+
*
|
|
662
|
+
* @typeParam T - Expected shape of the response body.
|
|
663
|
+
* @param path - URL path relative to the base URL.
|
|
664
|
+
* @param data - Optional request body.
|
|
665
|
+
* @param signal - Optional {@link AbortSignal} to cancel the request.
|
|
666
|
+
* @returns The parsed response body.
|
|
667
|
+
*/
|
|
668
|
+
async post(path, data, signal) {
|
|
669
|
+
if (this.offlineQueue && !this._isOnline) {
|
|
670
|
+
return this.offlineQueue.enqueue({ method: "POST", path, data });
|
|
671
|
+
}
|
|
672
|
+
if (isCacheablePost(path)) {
|
|
673
|
+
const cacheKey = this.cache.generateKey("POST", path, data);
|
|
674
|
+
const cached = this.cache.get(cacheKey);
|
|
675
|
+
if (cached !== void 0) return cached;
|
|
676
|
+
const result2 = await this.retry.execute(async () => {
|
|
677
|
+
const response = await this.axios.post(path, data, { signal });
|
|
678
|
+
return response.data;
|
|
679
|
+
});
|
|
680
|
+
this.cache.set(cacheKey, result2);
|
|
681
|
+
return result2;
|
|
682
|
+
}
|
|
683
|
+
const result = await this.retry.execute(async () => {
|
|
684
|
+
const response = await this.axios.post(path, data, { signal });
|
|
685
|
+
return response.data;
|
|
686
|
+
});
|
|
687
|
+
this.cache.invalidate(path.split("/").filter(Boolean)[0] ?? path);
|
|
688
|
+
return result;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Send a PUT request.
|
|
692
|
+
*
|
|
693
|
+
* @typeParam T - Expected shape of the response body.
|
|
694
|
+
* @param path - URL path relative to the base URL.
|
|
695
|
+
* @param data - Optional request body.
|
|
696
|
+
* @param signal - Optional {@link AbortSignal} to cancel the request.
|
|
697
|
+
* @returns The parsed response body.
|
|
698
|
+
*/
|
|
699
|
+
async put(path, data, signal) {
|
|
700
|
+
if (this.offlineQueue && !this._isOnline) {
|
|
701
|
+
return this.offlineQueue.enqueue({ method: "PUT", path, data });
|
|
702
|
+
}
|
|
703
|
+
const result = await this.retry.execute(async () => {
|
|
704
|
+
const response = await this.axios.put(path, data, { signal });
|
|
705
|
+
return response.data;
|
|
706
|
+
});
|
|
707
|
+
this.cache.invalidate(path.split("/").filter(Boolean)[0] ?? path);
|
|
708
|
+
return result;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Send a PATCH request.
|
|
712
|
+
*
|
|
713
|
+
* @typeParam T - Expected shape of the response body.
|
|
714
|
+
* @param path - URL path relative to the base URL.
|
|
715
|
+
* @param data - Optional request body.
|
|
716
|
+
* @param signal - Optional {@link AbortSignal} to cancel the request.
|
|
717
|
+
* @returns The parsed response body.
|
|
718
|
+
*/
|
|
719
|
+
async patch(path, data, signal) {
|
|
720
|
+
if (this.offlineQueue && !this._isOnline) {
|
|
721
|
+
return this.offlineQueue.enqueue({ method: "PATCH", path, data });
|
|
722
|
+
}
|
|
723
|
+
const result = await this.retry.execute(async () => {
|
|
724
|
+
const response = await this.axios.patch(path, data, { signal });
|
|
725
|
+
return response.data;
|
|
726
|
+
});
|
|
727
|
+
this.cache.invalidate(path.split("/").filter(Boolean)[0] ?? path);
|
|
728
|
+
return result;
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Send a DELETE request.
|
|
732
|
+
*
|
|
733
|
+
* @typeParam T - Expected shape of the response body.
|
|
734
|
+
* @param path - URL path relative to the base URL.
|
|
735
|
+
* @param signal - Optional {@link AbortSignal} to cancel the request.
|
|
736
|
+
* @returns The parsed response body.
|
|
737
|
+
*/
|
|
738
|
+
async delete(path, signal) {
|
|
739
|
+
if (this.offlineQueue && !this._isOnline) {
|
|
740
|
+
return this.offlineQueue.enqueue({ method: "DELETE", path });
|
|
741
|
+
}
|
|
742
|
+
const result = await this.retry.execute(async () => {
|
|
743
|
+
const response = await this.axios.delete(path, { signal });
|
|
744
|
+
return response.data;
|
|
745
|
+
});
|
|
746
|
+
this.cache.invalidate(path.split("/").filter(Boolean)[0] ?? path);
|
|
747
|
+
return result;
|
|
748
|
+
}
|
|
749
|
+
// -----------------------------------------------------------------------
|
|
750
|
+
// Interceptors
|
|
751
|
+
// -----------------------------------------------------------------------
|
|
752
|
+
/**
|
|
753
|
+
* Attach the request interceptor.
|
|
754
|
+
*
|
|
755
|
+
* Responsibilities:
|
|
756
|
+
* - Set `X-API-Key` authentication header.
|
|
757
|
+
* - Set `X-Tenant-ID` header when a tenant identifier is configured.
|
|
758
|
+
* - Ensure `Content-Type` is `application/json`.
|
|
759
|
+
*/
|
|
760
|
+
setupRequestInterceptor() {
|
|
761
|
+
this.axios.interceptors.request.use((requestConfig) => {
|
|
762
|
+
requestConfig.headers.set("X-API-Key", this.config.apiKey);
|
|
763
|
+
if (this.config.tenantId) {
|
|
764
|
+
requestConfig.headers.set("X-Tenant-ID", this.config.tenantId);
|
|
765
|
+
}
|
|
766
|
+
requestConfig.headers.set("Content-Type", "application/json");
|
|
767
|
+
return requestConfig;
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Attach the response interceptor.
|
|
772
|
+
*
|
|
773
|
+
* Successful responses pass through unchanged. Errors are normalised
|
|
774
|
+
* into the appropriate {@link NexusError} subclass:
|
|
775
|
+
*
|
|
776
|
+
* | Condition | Error class |
|
|
777
|
+
* |------------------------|--------------------|
|
|
778
|
+
* | Request cancelled | *(re-thrown as-is)*|
|
|
779
|
+
* | Timeout (`ECONNABORTED`, `ETIMEDOUT`) | {@link TimeoutError} |
|
|
780
|
+
* | No response received | {@link NetworkError} |
|
|
781
|
+
* | HTTP 4xx / 5xx | {@link ApiError} (or subclass) |
|
|
782
|
+
*/
|
|
783
|
+
setupResponseInterceptor() {
|
|
784
|
+
this.axios.interceptors.response.use(
|
|
785
|
+
// Success handler -- pass through
|
|
786
|
+
(response) => response,
|
|
787
|
+
// Error handler -- normalise into NexusError hierarchy
|
|
788
|
+
(error) => {
|
|
789
|
+
if (axios.isCancel(error)) {
|
|
790
|
+
return Promise.reject(error);
|
|
791
|
+
}
|
|
792
|
+
if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") {
|
|
793
|
+
return Promise.reject(
|
|
794
|
+
new TimeoutError(
|
|
795
|
+
`Request to ${error.config?.url ?? "unknown"} timed out after ${this.config.timeout}ms`,
|
|
796
|
+
error
|
|
797
|
+
)
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
if (error.response) {
|
|
801
|
+
const apiError = ApiError.fromResponse(error.response);
|
|
802
|
+
const reqUrl = error.config?.url ?? "";
|
|
803
|
+
if (this.onApiError && !reqUrl.includes("/errors")) {
|
|
804
|
+
try {
|
|
805
|
+
this.onApiError(
|
|
806
|
+
error.response.status,
|
|
807
|
+
error.config?.method?.toUpperCase() ?? "UNKNOWN",
|
|
808
|
+
reqUrl,
|
|
809
|
+
apiError.message
|
|
810
|
+
);
|
|
811
|
+
} catch {
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return Promise.reject(apiError);
|
|
815
|
+
}
|
|
816
|
+
return Promise.reject(
|
|
817
|
+
new NetworkError(
|
|
818
|
+
error.message || "A network error occurred",
|
|
819
|
+
error
|
|
820
|
+
)
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
// src/services/base.ts
|
|
828
|
+
var BaseService = class {
|
|
829
|
+
/**
|
|
830
|
+
* @param http - Fully-configured {@link HttpClient} instance.
|
|
831
|
+
*/
|
|
832
|
+
constructor(http) {
|
|
833
|
+
this.http = http;
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// src/types/context.ts
|
|
838
|
+
var DEPTH_PRESETS = {
|
|
839
|
+
L0: { include_profile: true, profile_limit: 1, include_history: false, include_graph: false, layers: [] },
|
|
840
|
+
L1: { include_profile: true, profile_limit: 3, include_history: false, include_graph: false, layers: [] },
|
|
841
|
+
L2: { include_profile: true, profile_limit: 10, include_history: false, include_graph: false, layers: ["semantic"] },
|
|
842
|
+
L3: { include_profile: true, profile_limit: 20, include_history: true, include_graph: true, layers: ["semantic", "graph"] }
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// src/schemas/context.ts
|
|
846
|
+
import { z } from "zod";
|
|
847
|
+
var contextLayerSchema = z.enum(["recent", "semantic", "graph"]);
|
|
848
|
+
var contextRequestSchema = z.object({
|
|
849
|
+
user_id: z.string().min(1),
|
|
850
|
+
query: z.string().optional(),
|
|
851
|
+
layers: z.array(contextLayerSchema).optional(),
|
|
852
|
+
recent_hours: z.number().positive().optional(),
|
|
853
|
+
recent_limit: z.number().int().positive().optional(),
|
|
854
|
+
include_profile: z.boolean().optional(),
|
|
855
|
+
profile_limit: z.number().int().positive().optional(),
|
|
856
|
+
include_history: z.boolean().optional(),
|
|
857
|
+
history_limit: z.number().int().positive().optional(),
|
|
858
|
+
include_graph: z.boolean().optional(),
|
|
859
|
+
graph_limit: z.number().int().positive().optional(),
|
|
860
|
+
// RFC 3339 with required timezone offset (`offset: true`). Rejects naive
|
|
861
|
+
// datetimes like `"2026-01-01T00:00:00"` to surface ingest-boundary
|
|
862
|
+
// ambiguity early — see ContextRequest.as_of JSDoc.
|
|
863
|
+
// Added in v1.3.0 (US-037 Wave 1 TASK-005).
|
|
864
|
+
as_of: z.string().datetime({ offset: true }).optional()
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
// src/errors/validation.ts
|
|
868
|
+
var InputValidationError = class extends NexusError {
|
|
869
|
+
constructor(zodError) {
|
|
870
|
+
const message = `Validation failed: ${zodError.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`;
|
|
871
|
+
super(message, "NEXUS_INPUT_VALIDATION_ERROR");
|
|
872
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
873
|
+
this.name = "InputValidationError";
|
|
874
|
+
this.fieldErrors = zodError.flatten().fieldErrors;
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
// src/services/context.ts
|
|
879
|
+
var ContextService = class extends BaseService {
|
|
880
|
+
/**
|
|
881
|
+
* Retrieve aggregated context for a user across multiple layers.
|
|
882
|
+
*
|
|
883
|
+
* Performs v2.0 three-layer parallel retrieval:
|
|
884
|
+
* - **recent**: Time-anchored activities from the activity stream
|
|
885
|
+
* - **semantic**: Vector similarity search against Mem0 memory store
|
|
886
|
+
* - **graph**: Knowledge graph traversal via Fast GraphRAG
|
|
887
|
+
*
|
|
888
|
+
* @param request - Context retrieval parameters including user_id, query, and layer configuration.
|
|
889
|
+
* @returns Aggregated context containing profile, history, graph, and performance metadata.
|
|
890
|
+
*/
|
|
891
|
+
async retrieve(request, options) {
|
|
892
|
+
let resolved;
|
|
893
|
+
if (request.depth !== void 0 && DEPTH_PRESETS[request.depth]) {
|
|
894
|
+
const { depth, ...rest } = request;
|
|
895
|
+
resolved = { ...DEPTH_PRESETS[depth], ...rest };
|
|
896
|
+
} else {
|
|
897
|
+
const { depth: _depth, ...rest } = request;
|
|
898
|
+
resolved = rest;
|
|
899
|
+
}
|
|
900
|
+
const parsed = contextRequestSchema.safeParse(resolved);
|
|
901
|
+
if (!parsed.success) {
|
|
902
|
+
throw new InputValidationError(parsed.error);
|
|
903
|
+
}
|
|
904
|
+
return this.http.post("/context/retrieve", resolved, options?.signal);
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
// src/schemas/memory.ts
|
|
909
|
+
import { z as z2 } from "zod";
|
|
910
|
+
var memoryTypeSchema = z2.enum(["episodic", "semantic", "procedural"]);
|
|
911
|
+
var memoryCreateSchema = z2.object({
|
|
912
|
+
user_id: z2.string().min(1),
|
|
913
|
+
content: z2.string().min(1).max(1e4),
|
|
914
|
+
memory_type: memoryTypeSchema.optional(),
|
|
915
|
+
metadata: z2.record(z2.unknown()).optional()
|
|
916
|
+
});
|
|
917
|
+
var memoryUpdateSchema = z2.object({
|
|
918
|
+
content: z2.string().optional(),
|
|
919
|
+
memory_type: memoryTypeSchema.optional(),
|
|
920
|
+
metadata: z2.record(z2.unknown()).optional()
|
|
921
|
+
});
|
|
922
|
+
var memorySearchSchema = z2.object({
|
|
923
|
+
user_id: z2.string().min(1),
|
|
924
|
+
query: z2.string().min(1),
|
|
925
|
+
memory_type: memoryTypeSchema.optional(),
|
|
926
|
+
limit: z2.number().int().min(1).max(50).optional(),
|
|
927
|
+
threshold: z2.number().min(0).max(1).optional()
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
// src/services/memories.ts
|
|
931
|
+
var MemoryService = class extends BaseService {
|
|
932
|
+
/**
|
|
933
|
+
* Create a new memory record.
|
|
934
|
+
*
|
|
935
|
+
* @param data - Memory creation payload including user_id, content, and optional type/metadata.
|
|
936
|
+
* @returns The newly created memory with generated ID and timestamps.
|
|
937
|
+
*/
|
|
938
|
+
async create(data, options) {
|
|
939
|
+
const parsed = memoryCreateSchema.safeParse(data);
|
|
940
|
+
if (!parsed.success) {
|
|
941
|
+
throw new InputValidationError(parsed.error);
|
|
942
|
+
}
|
|
943
|
+
return this.http.post("/memories", data, options?.signal);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* List memories with optional filtering and pagination.
|
|
947
|
+
*
|
|
948
|
+
* @param params - Optional filters for user_id, memory_type, and pagination controls.
|
|
949
|
+
* @returns Paginated list of memory records.
|
|
950
|
+
*/
|
|
951
|
+
async list(params, options) {
|
|
952
|
+
return this.http.get("/memories", params, options?.signal);
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Retrieve a single memory by its ID.
|
|
956
|
+
*
|
|
957
|
+
* @param memoryId - UUID of the memory to retrieve.
|
|
958
|
+
* @returns The memory record.
|
|
959
|
+
* @throws {ApiError} 404 if the memory does not exist.
|
|
960
|
+
*/
|
|
961
|
+
async get(memoryId, options) {
|
|
962
|
+
return this.http.get(`/memories/${memoryId}`, void 0, options?.signal);
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Update an existing memory record.
|
|
966
|
+
*
|
|
967
|
+
* Supports partial updates -- only the provided fields are modified.
|
|
968
|
+
*
|
|
969
|
+
* @param memoryId - UUID of the memory to update.
|
|
970
|
+
* @param data - Fields to update (content, memory_type, metadata).
|
|
971
|
+
* @returns The updated memory record.
|
|
972
|
+
* @throws {ApiError} 404 if the memory does not exist.
|
|
973
|
+
*/
|
|
974
|
+
async update(memoryId, data, options) {
|
|
975
|
+
const parsed = memoryUpdateSchema.safeParse(data);
|
|
976
|
+
if (!parsed.success) {
|
|
977
|
+
throw new InputValidationError(parsed.error);
|
|
978
|
+
}
|
|
979
|
+
return this.http.patch(`/memories/${memoryId}`, data, options?.signal);
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* Delete a memory record.
|
|
983
|
+
*
|
|
984
|
+
* @param memoryId - UUID of the memory to delete.
|
|
985
|
+
* @throws {ApiError} 404 if the memory does not exist.
|
|
986
|
+
*/
|
|
987
|
+
async delete(memoryId, options) {
|
|
988
|
+
return this.http.delete(`/memories/${memoryId}`, options?.signal);
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Perform semantic similarity search across memories.
|
|
992
|
+
*
|
|
993
|
+
* Uses Mem0's vector search to find memories relevant to the query text.
|
|
994
|
+
* Results are ranked by similarity score and filtered by optional thresholds.
|
|
995
|
+
*
|
|
996
|
+
* @param request - Search parameters including user_id, query, and optional filters.
|
|
997
|
+
* @returns Search results with scored memories and timing metadata.
|
|
998
|
+
*/
|
|
999
|
+
async search(request, options) {
|
|
1000
|
+
const parsed = memorySearchSchema.safeParse(request);
|
|
1001
|
+
if (!parsed.success) {
|
|
1002
|
+
throw new InputValidationError(parsed.error);
|
|
1003
|
+
}
|
|
1004
|
+
return this.http.post("/memories/search", request, options?.signal);
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Retrieve the Memory Journal view (US-015).
|
|
1008
|
+
*
|
|
1009
|
+
* Groups memories chronologically by date for review. Supports both
|
|
1010
|
+
* markdown (human-readable) and JSON (programmatic) output formats.
|
|
1011
|
+
*
|
|
1012
|
+
* @param params - Optional filters for format, date range, and user_id.
|
|
1013
|
+
* @returns Journal response with memories grouped by date.
|
|
1014
|
+
*/
|
|
1015
|
+
async journal(params, options) {
|
|
1016
|
+
return this.http.get("/memories/journal", params, options?.signal);
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
// src/schemas/conversation.ts
|
|
1021
|
+
import { z as z3 } from "zod";
|
|
1022
|
+
var messageRoleSchema = z3.enum(["user", "assistant", "system", "tool"]);
|
|
1023
|
+
var conversationCreateSchema = z3.object({
|
|
1024
|
+
user_id: z3.string().min(1),
|
|
1025
|
+
session_id: z3.string().optional(),
|
|
1026
|
+
metadata: z3.record(z3.unknown()).optional()
|
|
1027
|
+
});
|
|
1028
|
+
var messageCreateSchema = z3.object({
|
|
1029
|
+
role: messageRoleSchema,
|
|
1030
|
+
content: z3.string().min(1).max(5e4),
|
|
1031
|
+
metadata: z3.record(z3.unknown()).optional()
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
// src/services/conversations.ts
|
|
1035
|
+
var ConversationService = class extends BaseService {
|
|
1036
|
+
/**
|
|
1037
|
+
* Create a new conversation session.
|
|
1038
|
+
*
|
|
1039
|
+
* @param data - Conversation creation payload including user_id and optional metadata.
|
|
1040
|
+
* @returns The newly created conversation with generated ID and timestamps.
|
|
1041
|
+
*/
|
|
1042
|
+
async create(data, options) {
|
|
1043
|
+
const parsed = conversationCreateSchema.safeParse(data);
|
|
1044
|
+
if (!parsed.success) {
|
|
1045
|
+
throw new InputValidationError(parsed.error);
|
|
1046
|
+
}
|
|
1047
|
+
return this.http.post("/conversations", data, options?.signal);
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* List conversations with optional filtering and pagination.
|
|
1051
|
+
*
|
|
1052
|
+
* @param params - Optional filters for user_id and pagination controls.
|
|
1053
|
+
* @returns Paginated list of conversation records.
|
|
1054
|
+
*/
|
|
1055
|
+
async list(params, options) {
|
|
1056
|
+
return this.http.get("/conversations", params, options?.signal);
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Retrieve a conversation with its messages included.
|
|
1060
|
+
*
|
|
1061
|
+
* @param conversationId - UUID of the conversation to retrieve.
|
|
1062
|
+
* @returns Conversation detail including the full message list.
|
|
1063
|
+
* @throws {ApiError} 404 if the conversation does not exist.
|
|
1064
|
+
*/
|
|
1065
|
+
async get(conversationId, options) {
|
|
1066
|
+
return this.http.get(`/conversations/${conversationId}`, void 0, options?.signal);
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Add a message to an existing conversation.
|
|
1070
|
+
*
|
|
1071
|
+
* The message is appended to the conversation's message sequence.
|
|
1072
|
+
* Zep will asynchronously update the conversation summary after
|
|
1073
|
+
* new messages are added.
|
|
1074
|
+
*
|
|
1075
|
+
* @param conversationId - UUID of the target conversation.
|
|
1076
|
+
* @param message - Message payload including role and content.
|
|
1077
|
+
* @returns The newly created message with generated ID and sequence number.
|
|
1078
|
+
* @throws {ApiError} 404 if the conversation does not exist.
|
|
1079
|
+
*/
|
|
1080
|
+
async addMessage(conversationId, message, options) {
|
|
1081
|
+
const parsed = messageCreateSchema.safeParse(message);
|
|
1082
|
+
if (!parsed.success) {
|
|
1083
|
+
throw new InputValidationError(parsed.error);
|
|
1084
|
+
}
|
|
1085
|
+
return this.http.post(`/conversations/${conversationId}/messages`, message, options?.signal);
|
|
1086
|
+
}
|
|
1087
|
+
/**
|
|
1088
|
+
* List messages within a conversation with optional pagination.
|
|
1089
|
+
*
|
|
1090
|
+
* Messages are returned in chronological order (oldest first).
|
|
1091
|
+
*
|
|
1092
|
+
* @param conversationId - UUID of the conversation.
|
|
1093
|
+
* @param params - Optional pagination controls (limit, offset).
|
|
1094
|
+
* @returns Paginated list of messages.
|
|
1095
|
+
* @throws {ApiError} 404 if the conversation does not exist.
|
|
1096
|
+
*/
|
|
1097
|
+
async getMessages(conversationId, params, options) {
|
|
1098
|
+
return this.http.get(
|
|
1099
|
+
`/conversations/${conversationId}/messages`,
|
|
1100
|
+
params,
|
|
1101
|
+
options?.signal
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Retrieve the auto-generated summary of a conversation.
|
|
1106
|
+
*
|
|
1107
|
+
* Summaries are produced by Zep OSS temporal graph analysis and
|
|
1108
|
+
* include key points extracted from the conversation history.
|
|
1109
|
+
*
|
|
1110
|
+
* @param conversationId - UUID of the conversation.
|
|
1111
|
+
* @returns The conversation summary with key points and generation timestamp.
|
|
1112
|
+
* @throws {ApiError} 404 if the conversation does not exist.
|
|
1113
|
+
*/
|
|
1114
|
+
async getSummary(conversationId, options) {
|
|
1115
|
+
return this.http.get(`/conversations/${conversationId}/summary`, void 0, options?.signal);
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Delete a conversation and all its messages.
|
|
1119
|
+
*
|
|
1120
|
+
* This operation is irreversible. The conversation, all associated
|
|
1121
|
+
* messages, and the generated summary will be permanently removed.
|
|
1122
|
+
*
|
|
1123
|
+
* @param conversationId - UUID of the conversation to delete.
|
|
1124
|
+
* @throws {ApiError} 404 if the conversation does not exist.
|
|
1125
|
+
*/
|
|
1126
|
+
async delete(conversationId, options) {
|
|
1127
|
+
return this.http.delete(`/conversations/${conversationId}`, options?.signal);
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1131
|
+
// src/schemas/knowledge.ts
|
|
1132
|
+
import { z as z4 } from "zod";
|
|
1133
|
+
var entityCreateSchema = z4.object({
|
|
1134
|
+
name: z4.string().min(1),
|
|
1135
|
+
entity_type: z4.string().min(1),
|
|
1136
|
+
description: z4.string().optional(),
|
|
1137
|
+
properties: z4.record(z4.unknown()).optional()
|
|
1138
|
+
});
|
|
1139
|
+
var graphQueryRequestSchema = z4.object({
|
|
1140
|
+
entity_name: z4.string().min(1),
|
|
1141
|
+
depth: z4.number().int().min(1).max(3).optional(),
|
|
1142
|
+
relationship_types: z4.array(z4.string()).optional()
|
|
1143
|
+
});
|
|
1144
|
+
var extractionRequestSchema = z4.object({
|
|
1145
|
+
text: z4.string().min(1).max(1e4),
|
|
1146
|
+
agent_id: z4.string().optional(),
|
|
1147
|
+
owner_user_id: z4.string().optional()
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
// src/services/knowledge.ts
|
|
1151
|
+
var KnowledgeService = class extends BaseService {
|
|
1152
|
+
/**
|
|
1153
|
+
* Create a new knowledge entity in the graph.
|
|
1154
|
+
*
|
|
1155
|
+
* @param data - Entity creation payload including name, type, and optional description/properties.
|
|
1156
|
+
* @returns The newly created entity with generated entity_id.
|
|
1157
|
+
*/
|
|
1158
|
+
async createEntity(data, options) {
|
|
1159
|
+
const parsed = entityCreateSchema.safeParse(data);
|
|
1160
|
+
if (!parsed.success) {
|
|
1161
|
+
throw new InputValidationError(parsed.error);
|
|
1162
|
+
}
|
|
1163
|
+
return this.http.post("/knowledge/entities", data, options?.signal);
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* List knowledge entities with optional filtering.
|
|
1167
|
+
*
|
|
1168
|
+
* @param params - Optional filters for user_id, entity_type, and pagination controls.
|
|
1169
|
+
* @returns Paginated list of knowledge entities.
|
|
1170
|
+
*/
|
|
1171
|
+
async listEntities(params, options) {
|
|
1172
|
+
return this.http.get("/knowledge/entities", params, options?.signal);
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Query the knowledge graph using BFS traversal.
|
|
1176
|
+
*
|
|
1177
|
+
* Starts from a named entity and traverses outward up to the specified
|
|
1178
|
+
* depth, collecting all reachable entities and relationships along
|
|
1179
|
+
* the traversal paths.
|
|
1180
|
+
*
|
|
1181
|
+
* @param request - Graph query parameters including starting entity name, depth, and optional relationship type filters.
|
|
1182
|
+
* @returns Graph query response with the start entity, traversal paths, and total path count.
|
|
1183
|
+
*/
|
|
1184
|
+
async query(request, options) {
|
|
1185
|
+
const parsed = graphQueryRequestSchema.safeParse(request);
|
|
1186
|
+
if (!parsed.success) {
|
|
1187
|
+
throw new InputValidationError(parsed.error);
|
|
1188
|
+
}
|
|
1189
|
+
return this.http.post("/knowledge/query", request, options?.signal);
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Extract entities and relationships from unstructured text.
|
|
1193
|
+
*
|
|
1194
|
+
* Uses Fast GraphRAG's NLP pipeline to identify named entities and
|
|
1195
|
+
* their relationships in Triplex format (Subject, Relation, Object).
|
|
1196
|
+
* Extracted items are automatically persisted to the knowledge graph.
|
|
1197
|
+
*
|
|
1198
|
+
* @param request - Extraction request including the source text and ownership (agent_id or owner_user_id).
|
|
1199
|
+
* @returns Extraction result with lists of created entities and relationships.
|
|
1200
|
+
*/
|
|
1201
|
+
async extract(request, options) {
|
|
1202
|
+
const parsed = extractionRequestSchema.safeParse(request);
|
|
1203
|
+
if (!parsed.success) {
|
|
1204
|
+
throw new InputValidationError(parsed.error);
|
|
1205
|
+
}
|
|
1206
|
+
return this.http.post("/knowledge/extract", request, options?.signal);
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
// src/services/activities.ts
|
|
1211
|
+
var ActivityService = class extends BaseService {
|
|
1212
|
+
/**
|
|
1213
|
+
* Batch-ingest an activity stream.
|
|
1214
|
+
*
|
|
1215
|
+
* Accepts up to 1000 activities per request. Activities are queued for
|
|
1216
|
+
* asynchronous processing by Arq workers on the Nexus backend.
|
|
1217
|
+
*
|
|
1218
|
+
* @param request - The activity stream payload containing agent ID and activities.
|
|
1219
|
+
* @returns Processing summary with accepted / processed / queued counts.
|
|
1220
|
+
*/
|
|
1221
|
+
async stream(request, options) {
|
|
1222
|
+
return this.http.post("/activities/stream", request, options?.signal);
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Convenience method to log a single activity.
|
|
1226
|
+
*
|
|
1227
|
+
* Wraps {@link stream} for the common case of reporting one event at a time.
|
|
1228
|
+
*
|
|
1229
|
+
* @param activity - The activity event to record.
|
|
1230
|
+
* @param agentId - Agent identifier (defaults to `'default'`).
|
|
1231
|
+
* @returns Processing summary with accepted / processed / queued counts.
|
|
1232
|
+
*/
|
|
1233
|
+
async log(activity, agentId, options) {
|
|
1234
|
+
return this.stream({
|
|
1235
|
+
agent_id: agentId || "default",
|
|
1236
|
+
activities: [activity]
|
|
1237
|
+
}, options);
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1241
|
+
// src/services/tenants.ts
|
|
1242
|
+
var TenantService = class extends BaseService {
|
|
1243
|
+
/**
|
|
1244
|
+
* Retrieve the current tenant's profile.
|
|
1245
|
+
*
|
|
1246
|
+
* Returns the tenant record associated with the API key,
|
|
1247
|
+
* including name, tier, quotas, and current usage snapshot.
|
|
1248
|
+
*
|
|
1249
|
+
* @returns The authenticated tenant's profile.
|
|
1250
|
+
*/
|
|
1251
|
+
async me(options) {
|
|
1252
|
+
return this.http.get("/tenants/me", void 0, options?.signal);
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Retrieve the current tenant's resource usage statistics.
|
|
1256
|
+
*
|
|
1257
|
+
* Returns counts for memories, conversations, and today's API calls.
|
|
1258
|
+
* Useful for monitoring quota consumption and building dashboards.
|
|
1259
|
+
*
|
|
1260
|
+
* @returns Current resource usage for the authenticated tenant.
|
|
1261
|
+
*/
|
|
1262
|
+
async usage(options) {
|
|
1263
|
+
return this.http.get("/tenants/me/usage", void 0, options?.signal);
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* List all API keys for the current tenant.
|
|
1267
|
+
*
|
|
1268
|
+
* @returns Array of API key records (without full key values).
|
|
1269
|
+
*/
|
|
1270
|
+
async listApiKeys(options) {
|
|
1271
|
+
return this.http.get("/tenants/me/api-keys", void 0, options?.signal);
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Create a new API key for the current tenant.
|
|
1275
|
+
*
|
|
1276
|
+
* @param data - API key creation parameters (name, scopes, expiry).
|
|
1277
|
+
* @returns The newly created API key, including the full key value (shown only once).
|
|
1278
|
+
*/
|
|
1279
|
+
async createApiKey(data, options) {
|
|
1280
|
+
return this.http.post("/tenants/me/api-keys", data, options?.signal);
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Revoke (delete) an API key.
|
|
1284
|
+
*
|
|
1285
|
+
* @param id - The UUID of the API key to revoke.
|
|
1286
|
+
*/
|
|
1287
|
+
async revokeApiKey(id, options) {
|
|
1288
|
+
return this.http.delete(`/tenants/me/api-keys/${id}`, options?.signal);
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
|
|
1292
|
+
// src/services/feedback.ts
|
|
1293
|
+
var FeedbackService = class extends BaseService {
|
|
1294
|
+
/**
|
|
1295
|
+
* Submit explicit feedback for a prior context retrieval (L2 signal).
|
|
1296
|
+
*
|
|
1297
|
+
* The backend accepts the submission immediately (HTTP 202) and processes
|
|
1298
|
+
* quality scoring asynchronously via QualityScoreWorker.
|
|
1299
|
+
*
|
|
1300
|
+
* @param retrieveId - The `retrieve_id` returned by `/context/retrieve`.
|
|
1301
|
+
* @param data - Rating and optional per-item feedback.
|
|
1302
|
+
* @param options - Optional request options (e.g. AbortSignal).
|
|
1303
|
+
* @returns The created feedback record metadata.
|
|
1304
|
+
*/
|
|
1305
|
+
async submit(retrieveId, data, options) {
|
|
1306
|
+
return this.http.put(
|
|
1307
|
+
`/feedback/${retrieveId}`,
|
|
1308
|
+
data,
|
|
1309
|
+
options?.signal
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* List feedback records with optional filtering and pagination.
|
|
1314
|
+
*
|
|
1315
|
+
* @param params - Optional filters: `user_id`, `limit`, `offset`.
|
|
1316
|
+
* @param options - Optional request options (e.g. AbortSignal).
|
|
1317
|
+
* @returns Paginated list of feedback records.
|
|
1318
|
+
*/
|
|
1319
|
+
async list(params, options) {
|
|
1320
|
+
const query = new URLSearchParams();
|
|
1321
|
+
if (params?.user_id) query.set("user_id", params.user_id);
|
|
1322
|
+
if (params?.limit !== void 0) query.set("limit", String(params.limit));
|
|
1323
|
+
if (params?.offset !== void 0) query.set("offset", String(params.offset));
|
|
1324
|
+
const qs = query.toString();
|
|
1325
|
+
return this.http.get(
|
|
1326
|
+
`/feedback${qs ? `?${qs}` : ""}`,
|
|
1327
|
+
void 0,
|
|
1328
|
+
options?.signal
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
// src/services/errors.ts
|
|
1334
|
+
var ErrorService = class extends BaseService {
|
|
1335
|
+
/**
|
|
1336
|
+
* Submit a structured error report.
|
|
1337
|
+
*
|
|
1338
|
+
* @param data - Error report payload.
|
|
1339
|
+
* @param options - Optional request options (e.g. AbortSignal).
|
|
1340
|
+
* @returns The created or updated error report metadata.
|
|
1341
|
+
*/
|
|
1342
|
+
async submit(data, options) {
|
|
1343
|
+
return this.http.post(
|
|
1344
|
+
"/errors",
|
|
1345
|
+
data,
|
|
1346
|
+
options?.signal
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
|
|
1351
|
+
// src/client.ts
|
|
1352
|
+
var NexusClient = class {
|
|
1353
|
+
/**
|
|
1354
|
+
* Create a new Nexus SDK client.
|
|
1355
|
+
*
|
|
1356
|
+
* @param config - SDK configuration. Only `apiKey` is required; all other
|
|
1357
|
+
* fields fall back to sensible defaults (see {@link resolveConfig}).
|
|
1358
|
+
*
|
|
1359
|
+
* @throws {Error} If `apiKey` is missing or empty.
|
|
1360
|
+
*/
|
|
1361
|
+
constructor(config) {
|
|
1362
|
+
const resolved = resolveConfig(config);
|
|
1363
|
+
this.http = new HttpClient(resolved);
|
|
1364
|
+
this.context = new ContextService(this.http);
|
|
1365
|
+
this.memories = new MemoryService(this.http);
|
|
1366
|
+
this.conversations = new ConversationService(this.http);
|
|
1367
|
+
this.knowledge = new KnowledgeService(this.http);
|
|
1368
|
+
this.activities = new ActivityService(this.http);
|
|
1369
|
+
this.tenants = new TenantService(this.http);
|
|
1370
|
+
this.feedback = new FeedbackService(this.http);
|
|
1371
|
+
this.errors = new ErrorService(this.http);
|
|
1372
|
+
if (resolved.autoErrorReport) {
|
|
1373
|
+
this.http.onApiError = (statusCode, method, url, detail) => {
|
|
1374
|
+
this.errors.submit({
|
|
1375
|
+
error_type: "api_error",
|
|
1376
|
+
severity: statusCode >= 500 ? "major" : "minor",
|
|
1377
|
+
description: `${method} ${url} \u2192 ${statusCode}: ${detail}`,
|
|
1378
|
+
request_context: { method, url, status_code: statusCode }
|
|
1379
|
+
}).catch(() => {
|
|
1380
|
+
});
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Access the offline queue instance (if offline mode is enabled).
|
|
1386
|
+
*/
|
|
1387
|
+
get queue() {
|
|
1388
|
+
return this.http.queue;
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* Set the online/offline status of the client.
|
|
1392
|
+
*
|
|
1393
|
+
* When transitioning from offline to online, queued requests are
|
|
1394
|
+
* automatically flushed.
|
|
1395
|
+
*/
|
|
1396
|
+
setOnline(online) {
|
|
1397
|
+
this.http.setOnline(online);
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
|
|
1401
|
+
// src/schemas/tenant.ts
|
|
1402
|
+
import { z as z5 } from "zod";
|
|
1403
|
+
var apiKeyScopeSchema = z5.enum(["read", "write", "admin"]);
|
|
1404
|
+
var apiKeyCreateSchema = z5.object({
|
|
1405
|
+
name: z5.string().min(1).max(100),
|
|
1406
|
+
scopes: z5.array(apiKeyScopeSchema).optional(),
|
|
1407
|
+
expires_days: z5.number().int().min(1).max(365).optional()
|
|
1408
|
+
});
|
|
1409
|
+
export {
|
|
1410
|
+
ActivityService,
|
|
1411
|
+
ApiError,
|
|
1412
|
+
AuthenticationError,
|
|
1413
|
+
ConfigurationError,
|
|
1414
|
+
ContextService,
|
|
1415
|
+
ConversationService,
|
|
1416
|
+
DEFAULT_CONFIG,
|
|
1417
|
+
DEPTH_PRESETS,
|
|
1418
|
+
ErrorService,
|
|
1419
|
+
FeedbackService,
|
|
1420
|
+
InputValidationError,
|
|
1421
|
+
KnowledgeService,
|
|
1422
|
+
MemoryService,
|
|
1423
|
+
NetworkError,
|
|
1424
|
+
NexusClient,
|
|
1425
|
+
NexusError,
|
|
1426
|
+
NotFoundError,
|
|
1427
|
+
OfflineQueue,
|
|
1428
|
+
RateLimitError,
|
|
1429
|
+
TenantService,
|
|
1430
|
+
TimeoutError,
|
|
1431
|
+
ValidationError,
|
|
1432
|
+
apiKeyCreateSchema,
|
|
1433
|
+
contextRequestSchema,
|
|
1434
|
+
conversationCreateSchema,
|
|
1435
|
+
entityCreateSchema,
|
|
1436
|
+
extractionRequestSchema,
|
|
1437
|
+
graphQueryRequestSchema,
|
|
1438
|
+
memoryCreateSchema,
|
|
1439
|
+
memorySearchSchema,
|
|
1440
|
+
memoryUpdateSchema,
|
|
1441
|
+
messageCreateSchema,
|
|
1442
|
+
resolveConfig
|
|
1443
|
+
};
|
|
1444
|
+
//# sourceMappingURL=index.mjs.map
|