@neo4j-labs/agent-memory 0.3.0 → 0.4.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/CHANGELOG.md +29 -0
- package/README.md +5 -5
- package/dist/{chunk-TGBKROHO.js → chunk-E752ALCR.js} +3 -3
- package/dist/{chunk-TGBKROHO.js.map → chunk-E752ALCR.js.map} +1 -1
- package/dist/{client-DSqbWQoa.d.ts → client-DV-lnohj.d.ts} +174 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +294 -17
- package/dist/index.js.map +1 -1
- package/dist/integrations/langchain.d.ts +1 -1
- package/dist/integrations/mastra.d.ts +1 -1
- package/dist/integrations/strands.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/middleware/vercel-ai.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { extractRequestId, supportsUserAgentHeader, defaultUserAgent, BridgeTransport } from './chunk-
|
|
2
|
-
export { VERSION } from './chunk-
|
|
3
|
-
import {
|
|
1
|
+
import { extractRequestId, supportsUserAgentHeader, defaultUserAgent, BridgeTransport } from './chunk-E752ALCR.js';
|
|
2
|
+
export { VERSION } from './chunk-E752ALCR.js';
|
|
3
|
+
import { ValidationError, NotSupportedError, ConnectionError, AuthenticationError, TransportError } from './chunk-ASQMU7YC.js';
|
|
4
4
|
export { AuthenticationError, ConnectionError, MemoryError, NotFoundError, NotSupportedError, TransportError, ValidationError } from './chunk-ASQMU7YC.js';
|
|
5
5
|
|
|
6
6
|
// src/auth/index.ts
|
|
@@ -165,6 +165,59 @@ var LongTermMemory = class {
|
|
|
165
165
|
});
|
|
166
166
|
return wire.map(toEntity);
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Poll entity search until async extraction has caught up, or time out.
|
|
170
|
+
*
|
|
171
|
+
* NAMS extracts entities in a background pipeline, so writes return before
|
|
172
|
+
* the entities are searchable. This helper lets application and test code
|
|
173
|
+
* await consistency explicitly instead of racing a fixed delay.
|
|
174
|
+
*
|
|
175
|
+
* Provide one of:
|
|
176
|
+
* - `predicate` — called with the current results; return true when satisfied.
|
|
177
|
+
* - `expectedNames` — succeed once every name appears (case-insensitive).
|
|
178
|
+
* **Recommended**: NAMS entity search is vector/nearest-neighbor, so a
|
|
179
|
+
* `minResults` threshold is satisfied almost immediately on a non-empty
|
|
180
|
+
* workspace; prefer `expectedNames`/`predicate` to confirm a *specific*
|
|
181
|
+
* extraction landed.
|
|
182
|
+
* - otherwise — succeed once at least `minResults` entities match.
|
|
183
|
+
*
|
|
184
|
+
* Returns `true` if satisfied within `timeoutMs`, `false` otherwise (it does
|
|
185
|
+
* not throw, so callers can branch or skip gracefully).
|
|
186
|
+
*/
|
|
187
|
+
async waitForExtraction(options) {
|
|
188
|
+
const {
|
|
189
|
+
query,
|
|
190
|
+
expectedNames,
|
|
191
|
+
minResults = 1,
|
|
192
|
+
predicate,
|
|
193
|
+
timeoutMs = 3e4,
|
|
194
|
+
intervalMs = 1e3
|
|
195
|
+
} = options;
|
|
196
|
+
const q = query ?? (expectedNames && expectedNames.length > 0 ? expectedNames[0] : void 0);
|
|
197
|
+
if (q === void 0 && predicate === void 0) {
|
|
198
|
+
throw new ValidationError(
|
|
199
|
+
"waitForExtraction requires one of: query, expectedNames, or predicate."
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
const want = (expectedNames ?? []).map((n) => n.toLowerCase());
|
|
203
|
+
const fetch2 = Math.max(minResults, want.length, options.limit ?? 10);
|
|
204
|
+
const deadline = Date.now() + timeoutMs;
|
|
205
|
+
for (; ; ) {
|
|
206
|
+
const results = await this.searchEntities(q ?? "", { limit: fetch2 });
|
|
207
|
+
let ok;
|
|
208
|
+
if (predicate !== void 0) {
|
|
209
|
+
ok = predicate(results);
|
|
210
|
+
} else if (want.length > 0) {
|
|
211
|
+
const found = new Set(results.map((e) => e.name.toLowerCase()));
|
|
212
|
+
ok = want.every((n) => found.has(n));
|
|
213
|
+
} else {
|
|
214
|
+
ok = results.length >= minResults;
|
|
215
|
+
}
|
|
216
|
+
if (ok) return true;
|
|
217
|
+
if (Date.now() >= deadline) return false;
|
|
218
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
168
221
|
async searchPreferences(query, options) {
|
|
169
222
|
const wire = await this.transport.request("search_preferences", {
|
|
170
223
|
query,
|
|
@@ -286,6 +339,172 @@ var LongTermMemory = class {
|
|
|
286
339
|
}
|
|
287
340
|
};
|
|
288
341
|
|
|
342
|
+
// src/ontology/index.ts
|
|
343
|
+
function toDocument(raw) {
|
|
344
|
+
if (!raw || typeof raw !== "object" || !raw.domain) return void 0;
|
|
345
|
+
return {
|
|
346
|
+
domain: raw.domain,
|
|
347
|
+
entityTypes: (raw.entity_types ?? []).map((e) => ({
|
|
348
|
+
label: e.label,
|
|
349
|
+
poleType: e.pole_type,
|
|
350
|
+
subtype: e.subtype,
|
|
351
|
+
color: e.color,
|
|
352
|
+
icon: e.icon,
|
|
353
|
+
properties: (e.properties ?? []).map((p) => ({
|
|
354
|
+
name: p.name,
|
|
355
|
+
type: p.type,
|
|
356
|
+
required: p.required,
|
|
357
|
+
unique: p.unique,
|
|
358
|
+
enum: p.enum ?? void 0
|
|
359
|
+
}))
|
|
360
|
+
})),
|
|
361
|
+
relationships: raw.relationships ?? []
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function toDocumentFromJson(schemaJson) {
|
|
365
|
+
if (schemaJson == null) return void 0;
|
|
366
|
+
try {
|
|
367
|
+
return toDocument(JSON.parse(schemaJson));
|
|
368
|
+
} catch {
|
|
369
|
+
return void 0;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function toVersion(raw) {
|
|
373
|
+
return {
|
|
374
|
+
id: raw.id,
|
|
375
|
+
ontologyId: raw.ontology_id,
|
|
376
|
+
revision: raw.revision,
|
|
377
|
+
validationMode: raw.validation_mode,
|
|
378
|
+
document: toDocumentFromJson(raw.schema_json),
|
|
379
|
+
schemaHash: raw.schema_hash,
|
|
380
|
+
createdAt: raw.created_at,
|
|
381
|
+
message: raw.message
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function toSummary(raw) {
|
|
385
|
+
return {
|
|
386
|
+
id: raw.id,
|
|
387
|
+
name: raw.name,
|
|
388
|
+
displayName: raw.display_name,
|
|
389
|
+
description: raw.description,
|
|
390
|
+
emoji: raw.emoji,
|
|
391
|
+
tagline: raw.tagline,
|
|
392
|
+
isSystem: raw.is_system ?? false,
|
|
393
|
+
currentRevision: raw.current_revision,
|
|
394
|
+
isActive: raw.is_active ?? false
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
function docToWire(doc) {
|
|
398
|
+
return {
|
|
399
|
+
domain: doc.domain,
|
|
400
|
+
entity_types: doc.entityTypes.map((e) => ({
|
|
401
|
+
label: e.label,
|
|
402
|
+
pole_type: e.poleType,
|
|
403
|
+
subtype: e.subtype,
|
|
404
|
+
color: e.color,
|
|
405
|
+
icon: e.icon,
|
|
406
|
+
properties: (e.properties ?? []).map((p) => ({
|
|
407
|
+
name: p.name,
|
|
408
|
+
type: p.type,
|
|
409
|
+
required: p.required,
|
|
410
|
+
unique: p.unique,
|
|
411
|
+
enum: p.enum
|
|
412
|
+
}))
|
|
413
|
+
})),
|
|
414
|
+
relationships: doc.relationships
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
var OntologyClient = class {
|
|
418
|
+
constructor(transport) {
|
|
419
|
+
this.transport = transport;
|
|
420
|
+
}
|
|
421
|
+
async list() {
|
|
422
|
+
const raw = await this.transport.request(
|
|
423
|
+
"list_ontologies",
|
|
424
|
+
{}
|
|
425
|
+
);
|
|
426
|
+
return (raw.ontologies ?? []).map(toSummary);
|
|
427
|
+
}
|
|
428
|
+
async get(id) {
|
|
429
|
+
const raw = await this.transport.request(
|
|
430
|
+
"get_ontology",
|
|
431
|
+
{ id }
|
|
432
|
+
);
|
|
433
|
+
const r = raw.record ?? {};
|
|
434
|
+
return {
|
|
435
|
+
record: {
|
|
436
|
+
id: r.id,
|
|
437
|
+
name: r.name,
|
|
438
|
+
description: r.description,
|
|
439
|
+
workspaceId: r.workspace_id,
|
|
440
|
+
isSystem: r.is_system ?? false,
|
|
441
|
+
createdAt: r.created_at
|
|
442
|
+
},
|
|
443
|
+
versions: (raw.versions ?? []).map(toVersion)
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
async getActive() {
|
|
447
|
+
const raw = await this.transport.request(
|
|
448
|
+
"get_active_ontology",
|
|
449
|
+
{}
|
|
450
|
+
);
|
|
451
|
+
const document = toDocument(raw.ontology);
|
|
452
|
+
if (!document) {
|
|
453
|
+
throw new NotSupportedError("No active ontology bound for this workspace.");
|
|
454
|
+
}
|
|
455
|
+
const active = { document };
|
|
456
|
+
const summaries = await this.list();
|
|
457
|
+
const match = summaries.find((s) => s.isActive) ?? summaries.find((s) => s.name === document.domain.id);
|
|
458
|
+
if (match) {
|
|
459
|
+
active.ontologyId = match.id;
|
|
460
|
+
const detail = await this.get(match.id);
|
|
461
|
+
const current = currentVersion(detail, match.currentRevision);
|
|
462
|
+
if (current) {
|
|
463
|
+
active.validationMode = current.validationMode;
|
|
464
|
+
active.revision = current.revision;
|
|
465
|
+
active.versionId = current.id;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return active;
|
|
469
|
+
}
|
|
470
|
+
async clone(templateName) {
|
|
471
|
+
const raw = await this.transport.request("clone_ontology", { name: templateName });
|
|
472
|
+
return toVersion(raw);
|
|
473
|
+
}
|
|
474
|
+
async create(options) {
|
|
475
|
+
const body = { ontology: docToWire(options.schema) };
|
|
476
|
+
if (options.validationMode !== void 0) body.validation_mode = options.validationMode;
|
|
477
|
+
const raw = await this.transport.request("create_ontology", { body });
|
|
478
|
+
return toVersion(raw);
|
|
479
|
+
}
|
|
480
|
+
async update(options) {
|
|
481
|
+
const body = { ontology: docToWire(options.schema) };
|
|
482
|
+
if (options.validationMode !== void 0) body.validation_mode = options.validationMode;
|
|
483
|
+
const raw = await this.transport.request("update_ontology", {
|
|
484
|
+
id: options.id,
|
|
485
|
+
body
|
|
486
|
+
});
|
|
487
|
+
return toVersion(raw);
|
|
488
|
+
}
|
|
489
|
+
async activate(versionId) {
|
|
490
|
+
const raw = await this.transport.request("activate_ontology", {
|
|
491
|
+
body: { version_id: versionId }
|
|
492
|
+
});
|
|
493
|
+
return toVersion(raw);
|
|
494
|
+
}
|
|
495
|
+
async delete(id) {
|
|
496
|
+
await this.transport.request("delete_ontology", { id });
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
function currentVersion(ontology, revision) {
|
|
500
|
+
if (ontology.versions.length === 0) return void 0;
|
|
501
|
+
if (revision !== void 0) {
|
|
502
|
+
const exact = ontology.versions.find((v) => v.revision === revision);
|
|
503
|
+
if (exact) return exact;
|
|
504
|
+
}
|
|
505
|
+
return ontology.versions.reduce((a, b) => b.revision > a.revision ? b : a);
|
|
506
|
+
}
|
|
507
|
+
|
|
289
508
|
// src/query/index.ts
|
|
290
509
|
var QueryConsole = class {
|
|
291
510
|
constructor(transport) {
|
|
@@ -509,6 +728,15 @@ var ReasoningMemory = class {
|
|
|
509
728
|
};
|
|
510
729
|
|
|
511
730
|
// src/short-term/index.ts
|
|
731
|
+
function resolveConversationId(sessionId, conversationId, method) {
|
|
732
|
+
const resolved = sessionId ?? conversationId;
|
|
733
|
+
if (resolved === void 0) {
|
|
734
|
+
throw new ValidationError(
|
|
735
|
+
`${method} requires sessionId (alias: conversationId) \u2014 the NAMS API is conversation-scoped.`
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
return resolved;
|
|
739
|
+
}
|
|
512
740
|
function toMessage(w) {
|
|
513
741
|
return {
|
|
514
742
|
id: w.id,
|
|
@@ -566,8 +794,9 @@ var ShortTermMemory = class {
|
|
|
566
794
|
}
|
|
567
795
|
// ---- Bronze tier (bridge) ----------------------------------------------
|
|
568
796
|
async addMessage(sessionId, role, content, options) {
|
|
797
|
+
const conv = resolveConversationId(sessionId, options?.conversationId, "addMessage");
|
|
569
798
|
const wire = await this.transport.request("add_message", {
|
|
570
|
-
session_id:
|
|
799
|
+
session_id: conv,
|
|
571
800
|
role,
|
|
572
801
|
content,
|
|
573
802
|
metadata: options?.metadata
|
|
@@ -575,16 +804,18 @@ var ShortTermMemory = class {
|
|
|
575
804
|
return toMessage(wire);
|
|
576
805
|
}
|
|
577
806
|
async getConversation(sessionId, options) {
|
|
807
|
+
const conv = resolveConversationId(sessionId, options?.conversationId, "getConversation");
|
|
578
808
|
const wire = await this.transport.request("get_conversation", {
|
|
579
|
-
session_id:
|
|
809
|
+
session_id: conv,
|
|
580
810
|
limit: options?.limit
|
|
581
811
|
});
|
|
582
812
|
return toConversation(wire);
|
|
583
813
|
}
|
|
584
814
|
async searchMessages(query, options) {
|
|
815
|
+
const conv = options?.sessionId ?? options?.conversationId;
|
|
585
816
|
const wire = await this.transport.request("search_messages", {
|
|
586
817
|
query,
|
|
587
|
-
session_id:
|
|
818
|
+
session_id: conv,
|
|
588
819
|
limit: options?.limit ?? 10,
|
|
589
820
|
threshold: options?.threshold ?? 0.7
|
|
590
821
|
});
|
|
@@ -602,8 +833,9 @@ var ShortTermMemory = class {
|
|
|
602
833
|
});
|
|
603
834
|
return result.deleted;
|
|
604
835
|
}
|
|
605
|
-
async clearSession(sessionId) {
|
|
606
|
-
|
|
836
|
+
async clearSession(sessionId, options) {
|
|
837
|
+
const conv = resolveConversationId(sessionId, options?.conversationId, "clearSession");
|
|
838
|
+
await this.transport.request("clear_session", { session_id: conv });
|
|
607
839
|
}
|
|
608
840
|
// ---- Volume 5 / hosted-native methods -----------------------------------
|
|
609
841
|
/** Create a new conversation (hosted service). */
|
|
@@ -969,7 +1201,32 @@ var ROUTES = {
|
|
|
969
1201
|
method: "POST",
|
|
970
1202
|
path: "/auth/refresh",
|
|
971
1203
|
hasBody: true
|
|
972
|
-
}
|
|
1204
|
+
},
|
|
1205
|
+
// Ontologies — snake_case sub-API (verified against staging; absent from the
|
|
1206
|
+
// OpenAPI spec). Bodies are sent verbatim via `snakeBody`.
|
|
1207
|
+
list_ontologies: { method: "GET", path: "/ontologies" },
|
|
1208
|
+
get_ontology: { method: "GET", path: "/ontologies/{id}", pathParams: ["id"] },
|
|
1209
|
+
get_active_ontology: { method: "GET", path: "/ontologies/active" },
|
|
1210
|
+
clone_ontology: {
|
|
1211
|
+
method: "POST",
|
|
1212
|
+
path: "/ontologies/{name}/clone",
|
|
1213
|
+
pathParams: ["name"]
|
|
1214
|
+
},
|
|
1215
|
+
create_ontology: { method: "POST", path: "/ontologies", hasBody: true, snakeBody: true },
|
|
1216
|
+
update_ontology: {
|
|
1217
|
+
method: "PUT",
|
|
1218
|
+
path: "/ontologies/{id}",
|
|
1219
|
+
pathParams: ["id"],
|
|
1220
|
+
hasBody: true,
|
|
1221
|
+
snakeBody: true
|
|
1222
|
+
},
|
|
1223
|
+
activate_ontology: {
|
|
1224
|
+
method: "POST",
|
|
1225
|
+
path: "/ontologies/active",
|
|
1226
|
+
hasBody: true,
|
|
1227
|
+
snakeBody: true
|
|
1228
|
+
},
|
|
1229
|
+
delete_ontology: { method: "DELETE", path: "/ontologies/{id}", pathParams: ["id"] }
|
|
973
1230
|
};
|
|
974
1231
|
var RestTransport = class {
|
|
975
1232
|
endpoint;
|
|
@@ -1107,13 +1364,17 @@ var RestTransport = class {
|
|
|
1107
1364
|
const query = queryEntries.length ? "?" + queryEntries.map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&") : "";
|
|
1108
1365
|
let body;
|
|
1109
1366
|
if (route.hasBody) {
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1367
|
+
if (route.snakeBody) {
|
|
1368
|
+
body = JSON.stringify(original.body ?? {});
|
|
1369
|
+
} else {
|
|
1370
|
+
const bodyObj = {};
|
|
1371
|
+
for (const [k, v] of Object.entries(camelParams)) {
|
|
1372
|
+
if (!consumed.has(k) && v !== void 0 && v !== null) {
|
|
1373
|
+
bodyObj[k] = v;
|
|
1374
|
+
}
|
|
1114
1375
|
}
|
|
1376
|
+
body = JSON.stringify(bodyObj);
|
|
1115
1377
|
}
|
|
1116
|
-
body = JSON.stringify(bodyObj);
|
|
1117
1378
|
}
|
|
1118
1379
|
const url = `${this.endpoint}${path}${query}`;
|
|
1119
1380
|
const start = nowMs();
|
|
@@ -1229,6 +1490,8 @@ var MemoryClient = class {
|
|
|
1229
1490
|
query;
|
|
1230
1491
|
/** API-key & OAuth management (hosted service only). */
|
|
1231
1492
|
auth;
|
|
1493
|
+
/** Ontology lifecycle — typed domain schemas (hosted service only). */
|
|
1494
|
+
ontology;
|
|
1232
1495
|
transport;
|
|
1233
1496
|
constructor(optionsOrTransport = {}) {
|
|
1234
1497
|
if (isTransport(optionsOrTransport)) {
|
|
@@ -1241,6 +1504,7 @@ var MemoryClient = class {
|
|
|
1241
1504
|
this.reasoning = new ReasoningMemory(this.transport);
|
|
1242
1505
|
this.query = new QueryConsole(this.transport);
|
|
1243
1506
|
this.auth = new AuthClient(this.transport);
|
|
1507
|
+
this.ontology = new OntologyClient(this.transport);
|
|
1244
1508
|
}
|
|
1245
1509
|
async connect() {
|
|
1246
1510
|
await this.transport.connect();
|
|
@@ -1261,9 +1525,22 @@ function resolveApiKey(option) {
|
|
|
1261
1525
|
if (typeof process === "undefined" || !process.env) return void 0;
|
|
1262
1526
|
return process.env.MEMORY_API_KEY;
|
|
1263
1527
|
}
|
|
1528
|
+
function resolveWorkspaceId(option) {
|
|
1529
|
+
if (option !== void 0) return option;
|
|
1530
|
+
if (typeof process === "undefined" || !process.env) return void 0;
|
|
1531
|
+
return process.env.MEMORY_WORKSPACE_ID;
|
|
1532
|
+
}
|
|
1533
|
+
function withWorkspaceHeader(headers, workspaceId) {
|
|
1534
|
+
if (!workspaceId) return headers;
|
|
1535
|
+
const hasExplicit = headers !== void 0 && Object.keys(headers).some((k) => k.toLowerCase() === "x-workspace-id");
|
|
1536
|
+
if (hasExplicit) return headers;
|
|
1537
|
+
return { ...headers ?? {}, "X-Workspace-Id": workspaceId };
|
|
1538
|
+
}
|
|
1264
1539
|
function createTransport(options) {
|
|
1265
1540
|
const endpoint = options.endpoint;
|
|
1266
1541
|
const apiKey = resolveApiKey(options.apiKey);
|
|
1542
|
+
const workspaceId = resolveWorkspaceId(options.workspaceId);
|
|
1543
|
+
const headers = withWorkspaceHeader(options.headers, workspaceId);
|
|
1267
1544
|
const choice = pickTransport(endpoint ?? DEFAULT_ENDPOINT, options.transport);
|
|
1268
1545
|
if (choice === "rest") {
|
|
1269
1546
|
return new RestTransport({
|
|
@@ -1271,7 +1548,7 @@ function createTransport(options) {
|
|
|
1271
1548
|
apiKey,
|
|
1272
1549
|
tokenProvider: options.tokenProvider,
|
|
1273
1550
|
timeout: options.timeout,
|
|
1274
|
-
headers
|
|
1551
|
+
headers,
|
|
1275
1552
|
logger: options.logger
|
|
1276
1553
|
});
|
|
1277
1554
|
}
|
|
@@ -1282,7 +1559,7 @@ function createTransport(options) {
|
|
|
1282
1559
|
endpoint,
|
|
1283
1560
|
apiKey,
|
|
1284
1561
|
timeout: options.timeout,
|
|
1285
|
-
headers
|
|
1562
|
+
headers,
|
|
1286
1563
|
logger: options.logger
|
|
1287
1564
|
});
|
|
1288
1565
|
}
|
|
@@ -1308,6 +1585,6 @@ var LazyConnectTransport = class {
|
|
|
1308
1585
|
}
|
|
1309
1586
|
};
|
|
1310
1587
|
|
|
1311
|
-
export { AuthClient, LongTermMemory, MemoryClient, QueryConsole, ReasoningMemory, RestTransport, ShortTermMemory };
|
|
1588
|
+
export { AuthClient, LongTermMemory, MemoryClient, OntologyClient, QueryConsole, ReasoningMemory, RestTransport, ShortTermMemory };
|
|
1312
1589
|
//# sourceMappingURL=index.js.map
|
|
1313
1590
|
//# sourceMappingURL=index.js.map
|