@origintrail-official/dkg-node-ui 10.0.12 → 10.0.14

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.
Files changed (39) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +50 -50
  3. package/dist/chain-cursor-stores.js +6 -6
  4. package/dist/chat-memory.d.ts +43 -2
  5. package/dist/chat-memory.d.ts.map +1 -1
  6. package/dist/chat-memory.js +240 -216
  7. package/dist/chat-memory.js.map +1 -1
  8. package/dist/db.d.ts +18 -10
  9. package/dist/db.d.ts.map +1 -1
  10. package/dist/db.js +1118 -988
  11. package/dist/db.js.map +1 -1
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist-ui/assets/{3d-force-graph-Bl6v-uII.js → 3d-force-graph-C9KowW4u.js} +1 -1
  17. package/dist-ui/assets/{AgentHub-D2vaQxlw.js → AgentHub-BVrcom9_.js} +1 -1
  18. package/dist-ui/assets/{AgentProfilePage-BgSTdsjD.js → AgentProfilePage-C9XaTt7j.js} +1 -1
  19. package/dist-ui/assets/{ApproveWalletsModal-D0Ub_eiD.js → ApproveWalletsModal-BdR2mshx.js} +3 -3
  20. package/dist-ui/assets/{ConvictionDetailView-CieVypna.js → ConvictionDetailView-cao48GL1.js} +1 -1
  21. package/dist-ui/assets/{Network-DKw_XEGi.js → Network-B3jCYzr5.js} +1 -1
  22. package/dist-ui/assets/{OnChainProvenanceCard-Dn_IEP7Q.js → OnChainProvenanceCard-DboMX4Aq.js} +1 -1
  23. package/dist-ui/assets/{Operations-BO2C3UWB.js → Operations-Dg1gfLXv.js} +1 -1
  24. package/dist-ui/assets/{PublishingConviction-xKRNHbzk.js → PublishingConviction-Byp6t69e.js} +1 -1
  25. package/dist-ui/assets/{Settings-DC_d9STV.js → Settings-CxI0SKeV.js} +1 -1
  26. package/dist-ui/assets/{ccip-zWfeQL8Q.js → ccip-wJ3OMRuz.js} +1 -1
  27. package/dist-ui/assets/{index-CwRQnNYh.js → index-5DS6xjw0.js} +3 -3
  28. package/dist-ui/assets/index-DOjsv0r7.css +1 -0
  29. package/dist-ui/assets/index-KoAnx9JE.js +1661 -0
  30. package/dist-ui/assets/{jsonld-B67IUHNU-C3ydusi_.js → jsonld-32FQRO67-CDirPi8u.js} +2 -2
  31. package/dist-ui/assets/{jsonld-G-CM-8JR.js → jsonld-CwHW9UDN.js} +1 -1
  32. package/dist-ui/assets/{renderer-3d-OSESAPET-ConXqyK6.js → renderer-3d-2EVDZII7-BNXV6iSu.js} +2 -2
  33. package/dist-ui/assets/{shikiHighlighter-C6lRYd1O.js → shikiHighlighter-C-LWPPSu.js} +1 -1
  34. package/dist-ui/index.html +14 -14
  35. package/package.json +4 -3
  36. package/dist-ui/assets/index-DEtfq9qv.css +0 -1
  37. package/dist-ui/assets/index-hrI-Ir4l.js +0 -1661
  38. /package/dist-ui/assets/{ntriples-SF2LFNMC-DH7OofPp.js → ntriples-ZWBY2WET-DH7OofPp.js} +0 -0
  39. /package/dist-ui/assets/{turtle-BXN4L2BY-BzTu0283.js → turtle-JJPK7LJ5-BzTu0283.js} +0 -0
@@ -20,8 +20,11 @@ const IMPORT_SOURCES = ['claude', 'chatgpt', 'gemini', 'other'];
20
20
  * extraction). v1 of the openclaw-dkg-primary-memory work intentionally
21
21
  * defers that migration; follow-up work tracks it.
22
22
  */
23
- const AGENT_CONTEXT_GRAPH = 'agent-context';
24
- const CHAT_TURNS_ASSERTION = 'chat-turns';
23
+ // Exported so the daemon's MemoryToolContext implementation can key
24
+ // chat-specific ensure behavior (the legacy-WM migration for exactly this
25
+ // assertion, #2149) off the same identifiers the manager writes with.
26
+ export const AGENT_CONTEXT_GRAPH = 'agent-context';
27
+ export const CHAT_TURNS_ASSERTION = 'chat-turns';
25
28
  const OPENCLAW_LOCAL_SESSION_ID = 'openclaw:dkg-ui';
26
29
  const CHAT_NS = 'urn:dkg:chat:';
27
30
  const MEMORY_NS = 'urn:dkg:memory:';
@@ -183,102 +186,102 @@ function buildSessionRootPattern(sessionUri) {
183
186
  const clauses = [
184
187
  `{ <${sessionUri}> ?sessionP ?sessionO . BIND(<${sessionUri}> AS ?s) }`,
185
188
  `{ ?s <${SCHEMA}isPartOf> <${sessionUri}> }`,
186
- `{
187
- ?msg <${SCHEMA}isPartOf> <${sessionUri}> .
188
- ?msg <${DKG_ONT}usedTool> ?s .
189
+ `{
190
+ ?msg <${SCHEMA}isPartOf> <${sessionUri}> .
191
+ ?msg <${DKG_ONT}usedTool> ?s .
189
192
  }`,
190
- `{
191
- ?msg <${SCHEMA}isPartOf> <${sessionUri}> .
192
- ?s <${DKG_ONT}mentionedIn> ?msg .
193
+ `{
194
+ ?msg <${SCHEMA}isPartOf> <${sessionUri}> .
195
+ ?s <${DKG_ONT}mentionedIn> ?msg .
193
196
  }`,
194
197
  `{ ?s <${DKG_ONT}extractedFrom> <${sessionUri}> }`,
195
198
  ];
196
- return `{
197
- ${clauses.join('\n UNION ')}
199
+ return `{
200
+ ${clauses.join('\n UNION ')}
198
201
  }`;
199
202
  }
200
- const MENTION_EXTRACTION_PROMPT = `Extract named entities mentioned in the following text. Output ONLY a JSON array of objects with "name" and "type" fields.
201
-
202
- Rules:
203
- - "name" is the canonical label (proper casing, e.g. "Porsche", "Bitcoin", "Berlin")
204
- - "type" is one of: Person, Organization, Place, Product, Event, Technology, Concept
205
- - Only extract concrete, specific entities — skip vague words like "car", "company", "city"
206
- - If no entities found, output: []
207
- - Do NOT wrap in markdown code fences
208
-
209
- Example output:
210
- [{"name":"Porsche","type":"Organization"},{"name":"Berlin","type":"Place"}]
211
-
203
+ const MENTION_EXTRACTION_PROMPT = `Extract named entities mentioned in the following text. Output ONLY a JSON array of objects with "name" and "type" fields.
204
+
205
+ Rules:
206
+ - "name" is the canonical label (proper casing, e.g. "Porsche", "Bitcoin", "Berlin")
207
+ - "type" is one of: Person, Organization, Place, Product, Event, Technology, Concept
208
+ - Only extract concrete, specific entities — skip vague words like "car", "company", "city"
209
+ - If no entities found, output: []
210
+ - Do NOT wrap in markdown code fences
211
+
212
+ Example output:
213
+ [{"name":"Porsche","type":"Organization"},{"name":"Berlin","type":"Place"}]
214
+
212
215
  Text:`;
213
- const KG_EXTRACTION_PROMPT = `Extract structured knowledge from the following conversation exchange. Output ONLY valid N-Triples (one per line, no blank lines). Use URIs for subjects/predicates and proper RDF syntax.
214
-
215
- Rules:
216
- - Subject URIs: use urn:dkg:entity:{slug} where slug is a lowercase-kebab-case identifier for the entity
217
- - Use schema.org predicates where possible (e.g. <http://schema.org/name>, <http://schema.org/description>, <http://schema.org/knows>, <http://schema.org/about>)
218
- - Use <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> for types
219
- - String literals use "value" syntax; typed literals use "value"^^<datatype>
220
- - Each triple must end with " ."
221
- - Only extract factual, meaningful entities and relationships — skip conversational filler
222
- - If no meaningful knowledge can be extracted, output exactly: NONE
223
-
224
- Example output:
225
- <urn:dkg:entity:alice> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
226
- <urn:dkg:entity:alice> <http://schema.org/name> "Alice Johnson" .
227
- <urn:dkg:entity:alice> <http://schema.org/worksFor> <urn:dkg:entity:acme-corp> .
228
-
216
+ const KG_EXTRACTION_PROMPT = `Extract structured knowledge from the following conversation exchange. Output ONLY valid N-Triples (one per line, no blank lines). Use URIs for subjects/predicates and proper RDF syntax.
217
+
218
+ Rules:
219
+ - Subject URIs: use urn:dkg:entity:{slug} where slug is a lowercase-kebab-case identifier for the entity
220
+ - Use schema.org predicates where possible (e.g. <http://schema.org/name>, <http://schema.org/description>, <http://schema.org/knows>, <http://schema.org/about>)
221
+ - Use <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> for types
222
+ - String literals use "value" syntax; typed literals use "value"^^<datatype>
223
+ - Each triple must end with " ."
224
+ - Only extract factual, meaningful entities and relationships — skip conversational filler
225
+ - If no meaningful knowledge can be extracted, output exactly: NONE
226
+
227
+ Example output:
228
+ <urn:dkg:entity:alice> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
229
+ <urn:dkg:entity:alice> <http://schema.org/name> "Alice Johnson" .
230
+ <urn:dkg:entity:alice> <http://schema.org/worksFor> <urn:dkg:entity:acme-corp> .
231
+
229
232
  Conversation:`;
230
- const MEMORY_PARSE_PROMPT = `Parse the following exported AI memories into individual structured items. Each memory is a discrete fact, preference, or piece of context the user previously shared with an AI assistant.
231
-
232
- Output ONLY a valid JSON array. Each item should have:
233
- - "text": the memory content as a clear sentence
234
- - "category": one of "preference", "fact", "context", "instruction", "relationship"
235
-
236
- Rules:
237
- - Split compound memories into separate items when they contain distinct facts
238
- - Normalize formatting: remove bullet markers, numbering, markdown artifacts
239
- - Preserve the original meaning faithfully
240
- - Skip metadata lines like "Here are your memories:" or "Last updated:"
241
- - If no valid memories can be extracted, output: []
242
- - Do NOT wrap in markdown code fences
243
-
244
- Example input:
245
- "- Prefers dark mode in all apps
246
- - Works at Acme Corp as a senior engineer
247
- - Has a dog named Max"
248
-
249
- Example output:
250
- [{"text":"Prefers dark mode in all apps","category":"preference"},{"text":"Works at Acme Corp as a senior engineer","category":"fact"},{"text":"Has a dog named Max","category":"fact"}]
251
-
233
+ const MEMORY_PARSE_PROMPT = `Parse the following exported AI memories into individual structured items. Each memory is a discrete fact, preference, or piece of context the user previously shared with an AI assistant.
234
+
235
+ Output ONLY a valid JSON array. Each item should have:
236
+ - "text": the memory content as a clear sentence
237
+ - "category": one of "preference", "fact", "context", "instruction", "relationship"
238
+
239
+ Rules:
240
+ - Split compound memories into separate items when they contain distinct facts
241
+ - Normalize formatting: remove bullet markers, numbering, markdown artifacts
242
+ - Preserve the original meaning faithfully
243
+ - Skip metadata lines like "Here are your memories:" or "Last updated:"
244
+ - If no valid memories can be extracted, output: []
245
+ - Do NOT wrap in markdown code fences
246
+
247
+ Example input:
248
+ "- Prefers dark mode in all apps
249
+ - Works at Acme Corp as a senior engineer
250
+ - Has a dog named Max"
251
+
252
+ Example output:
253
+ [{"text":"Prefers dark mode in all apps","category":"preference"},{"text":"Works at Acme Corp as a senior engineer","category":"fact"},{"text":"Has a dog named Max","category":"fact"}]
254
+
252
255
  Memories to parse:`;
253
- const MEMORY_KG_PROMPT = `Extract structured knowledge from the following personal memory items. These are facts/preferences a user previously stored with an AI assistant. Output ONLY valid N-Triples (one per line).
254
-
255
- Rules:
256
- - Subject URIs: use urn:dkg:entity:{slug} where slug is a lowercase-kebab-case identifier
257
- - Use schema.org predicates where possible (e.g. <http://schema.org/name>, <http://schema.org/description>, <http://schema.org/knows>)
258
- - Use <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> for types
259
- - String literals use "value" syntax
260
- - Each triple must end with " ."
261
- - Focus on extracting entities (people, organizations, tools, places) and their relationships
262
- - If no meaningful knowledge can be extracted, output exactly: NONE
263
-
256
+ const MEMORY_KG_PROMPT = `Extract structured knowledge from the following personal memory items. These are facts/preferences a user previously stored with an AI assistant. Output ONLY valid N-Triples (one per line).
257
+
258
+ Rules:
259
+ - Subject URIs: use urn:dkg:entity:{slug} where slug is a lowercase-kebab-case identifier
260
+ - Use schema.org predicates where possible (e.g. <http://schema.org/name>, <http://schema.org/description>, <http://schema.org/knows>)
261
+ - Use <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> for types
262
+ - String literals use "value" syntax
263
+ - Each triple must end with " ."
264
+ - Focus on extracting entities (people, organizations, tools, places) and their relationships
265
+ - If no meaningful knowledge can be extracted, output exactly: NONE
266
+
264
267
  Memory items:`;
265
- const SEMANTIC_RECALL_SYSTEM = `You are a SPARQL query generator. Output ONLY a valid SPARQL SELECT query.
266
-
267
- IMPORTANT: Always use full URI syntax with angle brackets — NEVER use prefix shortcuts.
268
-
269
- Available patterns:
270
- - Sessions: ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Conversation>
271
- - Messages: ?m <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Message>
272
- - ?m <http://schema.org/text> ?text
273
- - ?m <http://schema.org/author> <urn:dkg:chat:actor:user> or <urn:dkg:chat:actor:agent>
274
- - ?m <http://schema.org/isPartOf> ?session
275
- - ?m <http://schema.org/dateCreated> ?ts
276
- - Entities: ?e <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?type . FILTER(STRSTARTS(STR(?e), "urn:dkg:entity:"))
277
- - ?e <http://schema.org/name> ?name
278
- - ?e <http://schema.org/worksFor> ?org
279
- - Memory links: ?m <http://dkg.io/ontology/contains> ?entity
280
- - Entity mentions: ?entity <http://dkg.io/ontology/mentionedIn> ?message
281
-
268
+ const SEMANTIC_RECALL_SYSTEM = `You are a SPARQL query generator. Output ONLY a valid SPARQL SELECT query.
269
+
270
+ IMPORTANT: Always use full URI syntax with angle brackets — NEVER use prefix shortcuts.
271
+
272
+ Available patterns:
273
+ - Sessions: ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Conversation>
274
+ - Messages: ?m <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Message>
275
+ - ?m <http://schema.org/text> ?text
276
+ - ?m <http://schema.org/author> <urn:dkg:chat:actor:user> or <urn:dkg:chat:actor:agent>
277
+ - ?m <http://schema.org/isPartOf> ?session
278
+ - ?m <http://schema.org/dateCreated> ?ts
279
+ - Entities: ?e <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?type . FILTER(STRSTARTS(STR(?e), "urn:dkg:entity:"))
280
+ - ?e <http://schema.org/name> ?name
281
+ - ?e <http://schema.org/worksFor> ?org
282
+ - Memory links: ?m <http://dkg.io/ontology/contains> ?entity
283
+ - Entity mentions: ?entity <http://dkg.io/ontology/mentionedIn> ?message
284
+
282
285
  Always include LIMIT (default 50). Use FILTER with regex or CONTAINS for text search.`;
283
286
  export class ChatMemoryManager {
284
287
  tools;
@@ -300,6 +303,15 @@ export class ChatMemoryManager {
300
303
  get contextGraphId() {
301
304
  return this.agentContextGraph;
302
305
  }
306
+ /**
307
+ * The chat-turns assertion this manager writes to. Exposed so a caller
308
+ * wiring a storage-upgrade policy can assert it covers the assertion the
309
+ * manager ACTUALLY uses, rather than comparing its own configuration to
310
+ * itself (#2149).
311
+ */
312
+ get assertionName() {
313
+ return this.chatTurnsAssertion;
314
+ }
303
315
  updateConfig(llmConfig) {
304
316
  this.llmConfig = llmConfig;
305
317
  }
@@ -316,6 +328,18 @@ export class ChatMemoryManager {
316
328
  assertionName: overrides?.assertionName ?? this.chatTurnsAssertion,
317
329
  };
318
330
  }
331
+ wmMutationOpts() {
332
+ return { agentAddress: this.agentAddress };
333
+ }
334
+ /**
335
+ * The ONE route every chat-turn mutation takes. Target graph, assertion
336
+ * name, and the resolved-agent mutation options are owned here, so a new
337
+ * write path cannot silently land in a different graph or skip the
338
+ * agentAddress that reads resolve under (#277, #2149).
339
+ */
340
+ async writeChatTurns(quads) {
341
+ await this.tools.writeAssertion(this.agentContextGraph, this.chatTurnsAssertion, quads, this.wmMutationOpts());
342
+ }
319
343
  /**
320
344
  * Lazy creation of the chat-turn context graph + assertion. Runs on the
321
345
  * first `storeChatExchange` / `ensureInitialized` call and is idempotent
@@ -348,7 +372,7 @@ export class ChatMemoryManager {
348
372
  const assertionKey = `${this.agentContextGraph}::${this.chatTurnsAssertion}`;
349
373
  if (!this.assertionEnsured.has(assertionKey)) {
350
374
  try {
351
- await this.tools.createAssertion(this.agentContextGraph, this.chatTurnsAssertion);
375
+ await this.tools.createAssertion(this.agentContextGraph, this.chatTurnsAssertion, this.wmMutationOpts());
352
376
  this.assertionEnsured.add(assertionKey);
353
377
  }
354
378
  catch (err) {
@@ -417,7 +441,7 @@ export class ChatMemoryManager {
417
441
  quads.push({ subject: tcUri, predicate: RDF_TYPE, object: `${DKG_ONT}ToolInvocation`, graph: '' }, { subject: tcUri, predicate: `${DKG_ONT}toolName`, object: `"${tc.name}"`, graph: '' }, { subject: tcUri, predicate: `${DKG_ONT}toolArgs`, object: JSON.stringify(JSON.stringify(tc.args)), graph: '' }, { subject: assistantMsgUri, predicate: `${DKG_ONT}usedTool`, object: tcUri, graph: '' });
418
442
  }
419
443
  }
420
- await this.tools.writeAssertion(this.agentContextGraph, this.chatTurnsAssertion, quads);
444
+ await this.writeChatTurns(quads);
421
445
  this.knownSessions.add(sessionId);
422
446
  // Fire-and-forget: extract entity mentions and write them as separate triples
423
447
  if (this.llmConfig?.apiKey) {
@@ -431,10 +455,10 @@ export class ChatMemoryManager {
431
455
  if (!trimmedTurnId)
432
456
  return false;
433
457
  const sessionUri = `${CHAT_NS}session:${sessionId}`;
434
- const result = await this.tools.query(`SELECT ?turn WHERE {
435
- ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
436
- ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
437
- ?turn <${DKG_ONT}turnId> ${JSON.stringify(trimmedTurnId)} .
458
+ const result = await this.tools.query(`SELECT ?turn WHERE {
459
+ ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
460
+ ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
461
+ ?turn <${DKG_ONT}turnId> ${JSON.stringify(trimmedTurnId)} .
438
462
  } LIMIT 1`, this.wmReadOpts());
439
463
  return (result.bindings ?? []).length > 0;
440
464
  }
@@ -444,16 +468,16 @@ export class ChatMemoryManager {
444
468
  if (!trimmedTurnId)
445
469
  return null;
446
470
  const sessionUri = `${CHAT_NS}session:${sessionId}`;
447
- const result = await this.tools.query(`SELECT ?persistenceState ?transitionState WHERE {
448
- ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
449
- ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
450
- ?turn <${DKG_ONT}turnId> ${JSON.stringify(trimmedTurnId)} .
451
- OPTIONAL { ?turn <${DKG_ONT}persistenceState> ?persistenceState }
452
- OPTIONAL {
453
- ?transition <${RDF_TYPE}> <${CHAT_TURN_PERSISTENCE_TRANSITION_TYPE}> .
454
- ?transition <${CHAT_TURN_PERSISTENCE_TRANSITION_PREDICATE}> ?turn .
455
- ?transition <${DKG_ONT}persistenceState> ?transitionState .
456
- }
471
+ const result = await this.tools.query(`SELECT ?persistenceState ?transitionState WHERE {
472
+ ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
473
+ ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
474
+ ?turn <${DKG_ONT}turnId> ${JSON.stringify(trimmedTurnId)} .
475
+ OPTIONAL { ?turn <${DKG_ONT}persistenceState> ?persistenceState }
476
+ OPTIONAL {
477
+ ?transition <${RDF_TYPE}> <${CHAT_TURN_PERSISTENCE_TRANSITION_TYPE}> .
478
+ ?transition <${CHAT_TURN_PERSISTENCE_TRANSITION_PREDICATE}> ?turn .
479
+ ?transition <${DKG_ONT}persistenceState> ?transitionState .
480
+ }
457
481
  }`, this.wmReadOpts());
458
482
  const states = (result.bindings ?? [])
459
483
  .flatMap((binding) => [
@@ -520,7 +544,7 @@ export class ChatMemoryManager {
520
544
  graph: '',
521
545
  });
522
546
  }
523
- await this.tools.writeAssertion(this.agentContextGraph, this.chatTurnsAssertion, quads);
547
+ await this.writeChatTurns(quads);
524
548
  }
525
549
  async extractAndWriteMentions(userMsgUri, userMessage, assistantMsgUri, assistantReply) {
526
550
  const allText = `User: ${userMessage}\nAssistant: ${assistantReply}`;
@@ -554,7 +578,7 @@ export class ChatMemoryManager {
554
578
  }
555
579
  }
556
580
  if (quads.length > 0) {
557
- await this.tools.writeAssertion(this.agentContextGraph, this.chatTurnsAssertion, quads);
581
+ await this.writeChatTurns(quads);
558
582
  }
559
583
  }
560
584
  async callMentionExtraction(text) {
@@ -623,7 +647,7 @@ export class ChatMemoryManager {
623
647
  const memUri = `${MEMORY_NS}${crypto.randomUUID().slice(0, 8)}`;
624
648
  quads.push({ subject: memUri, predicate: RDF_TYPE, object: `${DKG_ONT}Memory`, graph: '' }, { subject: memUri, predicate: `${DKG_ONT}extractedFrom`, object: sessionUri, graph: '' }, { subject: memUri, predicate: `${DKG_ONT}contains`, object: entity, graph: '' }, { subject: memUri, predicate: `${SCHEMA}dateCreated`, object: `"${new Date().toISOString()}"^^<${XSD_DATETIME}>`, graph: '' });
625
649
  }
626
- await this.tools.writeAssertion(this.agentContextGraph, this.chatTurnsAssertion, quads);
650
+ await this.writeChatTurns(quads);
627
651
  return triples.length;
628
652
  }
629
653
  async recall(sparql) {
@@ -668,12 +692,12 @@ export class ChatMemoryManager {
668
692
  base.sessionCount = sumBindingValues(sessions.bindings, 'c');
669
693
  const msgs = await this.tools.query(`SELECT (COUNT(*) AS ?c) WHERE { ?s <${RDF_TYPE}> <${SCHEMA}Message> }`, this.wmReadOpts());
670
694
  base.messageCount = sumBindingValues(msgs.bindings, 'c');
671
- const chatRelatedTriples = await this.tools.query(`SELECT (COUNT(*) AS ?c) WHERE {
672
- { ?s <${RDF_TYPE}> <${SCHEMA}Message> . ?s ?p ?o }
673
- UNION
674
- { ?s <${RDF_TYPE}> <${SCHEMA}Conversation> . ?s ?p ?o }
675
- UNION
676
- { ?s <${RDF_TYPE}> <${DKG_ONT}ToolInvocation> . ?s ?p ?o }
695
+ const chatRelatedTriples = await this.tools.query(`SELECT (COUNT(*) AS ?c) WHERE {
696
+ { ?s <${RDF_TYPE}> <${SCHEMA}Message> . ?s ?p ?o }
697
+ UNION
698
+ { ?s <${RDF_TYPE}> <${SCHEMA}Conversation> . ?s ?p ?o }
699
+ UNION
700
+ { ?s <${RDF_TYPE}> <${DKG_ONT}ToolInvocation> . ?s ?p ?o }
677
701
  }`, this.wmReadOpts());
678
702
  const chatTripleCount = sumBindingValues(chatRelatedTriples.bindings, 'c');
679
703
  const entities = await this.tools.query(`SELECT (COUNT(DISTINCT ?e) AS ?c) WHERE { ?e <${RDF_TYPE}> ?t . FILTER(STRSTARTS(STR(?e), "urn:dkg:entity:")) }`, this.wmReadOpts());
@@ -686,10 +710,10 @@ export class ChatMemoryManager {
686
710
  async getEntities(limit = 50) {
687
711
  await this.ensureInitialized();
688
712
  try {
689
- const result = await this.tools.query(`SELECT DISTINCT ?e ?type ?label WHERE {
690
- ?e <${RDF_TYPE}> ?type .
691
- OPTIONAL { ?e <${SCHEMA}name> ?label }
692
- FILTER(STRSTARTS(STR(?e), "urn:dkg:entity:"))
713
+ const result = await this.tools.query(`SELECT DISTINCT ?e ?type ?label WHERE {
714
+ ?e <${RDF_TYPE}> ?type .
715
+ OPTIONAL { ?e <${SCHEMA}name> ?label }
716
+ FILTER(STRSTARTS(STR(?e), "urn:dkg:entity:"))
693
717
  } LIMIT ${limit}`, this.wmReadOpts());
694
718
  const entities = [];
695
719
  for (const b of result.bindings ?? []) {
@@ -722,35 +746,35 @@ export class ChatMemoryManager {
722
746
  : 500;
723
747
  const order = opts.order === 'desc' ? 'DESC' : 'ASC';
724
748
  const sessionUri = `${CHAT_NS}session:${sessionId}`;
725
- const msgsResult = await this.tools.query(`SELECT ?m ?author ?text ?ts ?turnId ?persistenceState ?transitionState ?attachmentRefs ?failureReason ?transitionFailureReason ?transitionAssistantReply ?transitionAttachmentRefs ?transitionToolCalls WHERE {
726
- {
727
- SELECT ?m ?ts WHERE {
728
- ?m <${SCHEMA}isPartOf> <${sessionUri}> .
729
- ?m <${SCHEMA}dateCreated> ?ts
730
- } ORDER BY ${order}(?ts) LIMIT ${limit}
731
- }
732
- ?m <${SCHEMA}isPartOf> <${sessionUri}> .
733
- ?m <${SCHEMA}author> ?author .
734
- ?m <${SCHEMA}text> ?text .
735
- ?m <${SCHEMA}dateCreated> ?ts
736
- OPTIONAL { ?m <${DKG_ONT}turnId> ?turnId }
737
- OPTIONAL { ?m <${CHAT_ATTACHMENT_REFS_PREDICATE}> ?attachmentRefs }
738
- OPTIONAL {
739
- ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
740
- ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
741
- ?turn <${DKG_ONT}turnId> ?turnId .
742
- OPTIONAL { ?turn <${DKG_ONT}persistenceState> ?persistenceState }
743
- OPTIONAL { ?turn <${DKG_ONT}failureReason> ?failureReason }
744
- OPTIONAL {
745
- ?transition <${RDF_TYPE}> <${CHAT_TURN_PERSISTENCE_TRANSITION_TYPE}> .
746
- ?transition <${CHAT_TURN_PERSISTENCE_TRANSITION_PREDICATE}> ?turn .
747
- ?transition <${DKG_ONT}persistenceState> ?transitionState .
748
- OPTIONAL { ?transition <${DKG_ONT}failureReason> ?transitionFailureReason }
749
- OPTIONAL { ?transition <${DKG_ONT}assistantReply> ?transitionAssistantReply }
750
- OPTIONAL { ?transition <${CHAT_ATTACHMENT_REFS_PREDICATE}> ?transitionAttachmentRefs }
751
- OPTIONAL { ?transition <${DKG_ONT}toolCalls> ?transitionToolCalls }
752
- }
753
- }
749
+ const msgsResult = await this.tools.query(`SELECT ?m ?author ?text ?ts ?turnId ?persistenceState ?transitionState ?attachmentRefs ?failureReason ?transitionFailureReason ?transitionAssistantReply ?transitionAttachmentRefs ?transitionToolCalls WHERE {
750
+ {
751
+ SELECT ?m ?ts WHERE {
752
+ ?m <${SCHEMA}isPartOf> <${sessionUri}> .
753
+ ?m <${SCHEMA}dateCreated> ?ts
754
+ } ORDER BY ${order}(?ts) LIMIT ${limit}
755
+ }
756
+ ?m <${SCHEMA}isPartOf> <${sessionUri}> .
757
+ ?m <${SCHEMA}author> ?author .
758
+ ?m <${SCHEMA}text> ?text .
759
+ ?m <${SCHEMA}dateCreated> ?ts
760
+ OPTIONAL { ?m <${DKG_ONT}turnId> ?turnId }
761
+ OPTIONAL { ?m <${CHAT_ATTACHMENT_REFS_PREDICATE}> ?attachmentRefs }
762
+ OPTIONAL {
763
+ ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
764
+ ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
765
+ ?turn <${DKG_ONT}turnId> ?turnId .
766
+ OPTIONAL { ?turn <${DKG_ONT}persistenceState> ?persistenceState }
767
+ OPTIONAL { ?turn <${DKG_ONT}failureReason> ?failureReason }
768
+ OPTIONAL {
769
+ ?transition <${RDF_TYPE}> <${CHAT_TURN_PERSISTENCE_TRANSITION_TYPE}> .
770
+ ?transition <${CHAT_TURN_PERSISTENCE_TRANSITION_PREDICATE}> ?turn .
771
+ ?transition <${DKG_ONT}persistenceState> ?transitionState .
772
+ OPTIONAL { ?transition <${DKG_ONT}failureReason> ?transitionFailureReason }
773
+ OPTIONAL { ?transition <${DKG_ONT}assistantReply> ?transitionAssistantReply }
774
+ OPTIONAL { ?transition <${CHAT_ATTACHMENT_REFS_PREDICATE}> ?transitionAttachmentRefs }
775
+ OPTIONAL { ?transition <${DKG_ONT}toolCalls> ?transitionToolCalls }
776
+ }
777
+ }
754
778
  } ORDER BY ${order}(?ts)`, this.wmReadOpts());
755
779
  const bindings = msgsResult.bindings ?? [];
756
780
  if (bindings.length === 0)
@@ -812,10 +836,10 @@ export class ChatMemoryManager {
812
836
  await this.ensureInitialized();
813
837
  try {
814
838
  const expandedLimit = Math.max(limit, Math.min(limit * 4, 400));
815
- const sessionsResult = await this.tools.query(`SELECT ?s ?sid (MAX(?mts) AS ?latest) WHERE {
816
- ?s <${RDF_TYPE}> <${SCHEMA}Conversation> .
817
- ?s <${DKG_ONT}sessionId> ?sid .
818
- OPTIONAL { ?m <${SCHEMA}isPartOf> ?s . ?m <${SCHEMA}dateCreated> ?mts }
839
+ const sessionsResult = await this.tools.query(`SELECT ?s ?sid (MAX(?mts) AS ?latest) WHERE {
840
+ ?s <${RDF_TYPE}> <${SCHEMA}Conversation> .
841
+ ?s <${DKG_ONT}sessionId> ?sid .
842
+ OPTIONAL { ?m <${SCHEMA}isPartOf> ?s . ?m <${SCHEMA}dateCreated> ?mts }
819
843
  } GROUP BY ?s ?sid ORDER BY DESC(?latest) LIMIT ${expandedLimit}`, this.wmReadOpts());
820
844
  const sessionBindings = sessionsResult.bindings ?? [];
821
845
  if (sessionBindings.length === 0)
@@ -842,12 +866,12 @@ export class ChatMemoryManager {
842
866
  const values = sessionEntries
843
867
  .map((entry) => `<${entry.sessionUri}>`)
844
868
  .join(' ');
845
- const allMsgs = await this.tools.query(`SELECT ?session ?author ?text ?ts WHERE {
846
- VALUES ?session { ${values} }
847
- ?m <${SCHEMA}isPartOf> ?session .
848
- ?m <${SCHEMA}author> ?author .
849
- ?m <${SCHEMA}text> ?text .
850
- ?m <${SCHEMA}dateCreated> ?ts
869
+ const allMsgs = await this.tools.query(`SELECT ?session ?author ?text ?ts WHERE {
870
+ VALUES ?session { ${values} }
871
+ ?m <${SCHEMA}isPartOf> ?session .
872
+ ?m <${SCHEMA}author> ?author .
873
+ ?m <${SCHEMA}text> ?text .
874
+ ?m <${SCHEMA}dateCreated> ?ts
851
875
  } ORDER BY ?session ?ts`, this.wmReadOpts());
852
876
  const bySession = new Map();
853
877
  for (const row of allMsgs.bindings ?? []) {
@@ -878,9 +902,9 @@ export class ChatMemoryManager {
878
902
  await this.ensureInitialized();
879
903
  const sessionUri = `${CHAT_NS}session:${sessionId}`;
880
904
  const baseTurnId = opts?.baseTurnId?.trim() || null;
881
- const countResult = await this.tools.query(`SELECT (COUNT(*) AS ?c) WHERE {
882
- ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
883
- ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
905
+ const countResult = await this.tools.query(`SELECT (COUNT(*) AS ?c) WHERE {
906
+ ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
907
+ ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
884
908
  }`, this.wmReadOpts());
885
909
  const turnCount = sumBindingValues(countResult.bindings, 'c');
886
910
  if (turnCount === 0) {
@@ -901,20 +925,20 @@ export class ChatMemoryManager {
901
925
  };
902
926
  }
903
927
  const turnUri = `${CHAT_NS}turn:${turnId}`;
904
- const currentTurnResult = await this.tools.query(`SELECT ?tid ?ts WHERE {
905
- <${turnUri}> <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
906
- <${turnUri}> <${SCHEMA}isPartOf> <${sessionUri}> .
907
- <${turnUri}> <${DKG_ONT}turnId> ?tid .
908
- OPTIONAL { <${turnUri}> <${SCHEMA}dateCreated> ?ts }
928
+ const currentTurnResult = await this.tools.query(`SELECT ?tid ?ts WHERE {
929
+ <${turnUri}> <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
930
+ <${turnUri}> <${SCHEMA}isPartOf> <${sessionUri}> .
931
+ <${turnUri}> <${DKG_ONT}turnId> ?tid .
932
+ OPTIONAL { <${turnUri}> <${SCHEMA}dateCreated> ?ts }
909
933
  } LIMIT 1`, this.wmReadOpts());
910
934
  const currentTurn = (currentTurnResult.bindings ?? [])[0];
911
935
  const currentTurnId = stripRdfLiteral(currentTurn?.tid ?? '').trim();
912
936
  const currentTurnTs = stripRdfLiteral(currentTurn?.ts ?? '').trim();
913
- const latestTurnResult = await this.tools.query(`SELECT ?latestTurnId ?latestTs WHERE {
914
- ?latestTurn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
915
- ?latestTurn <${SCHEMA}isPartOf> <${sessionUri}> .
916
- ?latestTurn <${DKG_ONT}turnId> ?latestTurnId .
917
- OPTIONAL { ?latestTurn <${SCHEMA}dateCreated> ?latestTs }
937
+ const latestTurnResult = await this.tools.query(`SELECT ?latestTurnId ?latestTs WHERE {
938
+ ?latestTurn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
939
+ ?latestTurn <${SCHEMA}isPartOf> <${sessionUri}> .
940
+ ?latestTurn <${DKG_ONT}turnId> ?latestTurnId .
941
+ OPTIONAL { ?latestTurn <${SCHEMA}dateCreated> ?latestTs }
918
942
  } ORDER BY DESC(?latestTs) DESC(?latestTurnId) LIMIT 1`, this.wmReadOpts());
919
943
  const latestTurnId = stripRdfLiteral((latestTurnResult.bindings ?? [])[0]?.latestTurnId ?? '').trim() || null;
920
944
  if (!currentTurnId || currentTurnId !== turnId) {
@@ -939,34 +963,34 @@ export class ChatMemoryManager {
939
963
  ? `"${currentTurnTs}"^^<${XSD_DATETIME}>`
940
964
  : null;
941
965
  const previousTurnQuery = currentTsLiteral
942
- ? `SELECT ?previousTurnId WHERE {
943
- ?previousTurn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
944
- ?previousTurn <${SCHEMA}isPartOf> <${sessionUri}> .
945
- ?previousTurn <${DKG_ONT}turnId> ?previousTurnId .
946
- ?previousTurn <${SCHEMA}dateCreated> ?previousTs .
947
- FILTER(
948
- ?previousTs < ${currentTsLiteral}
949
- || (?previousTs = ${currentTsLiteral} && ?previousTurnId < ${currentTurnIdLiteral})
950
- )
966
+ ? `SELECT ?previousTurnId WHERE {
967
+ ?previousTurn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
968
+ ?previousTurn <${SCHEMA}isPartOf> <${sessionUri}> .
969
+ ?previousTurn <${DKG_ONT}turnId> ?previousTurnId .
970
+ ?previousTurn <${SCHEMA}dateCreated> ?previousTs .
971
+ FILTER(
972
+ ?previousTs < ${currentTsLiteral}
973
+ || (?previousTs = ${currentTsLiteral} && ?previousTurnId < ${currentTurnIdLiteral})
974
+ )
951
975
  } ORDER BY DESC(?previousTs) DESC(?previousTurnId) LIMIT 1`
952
- : `SELECT ?previousTurnId WHERE {
953
- ?previousTurn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
954
- ?previousTurn <${SCHEMA}isPartOf> <${sessionUri}> .
955
- ?previousTurn <${DKG_ONT}turnId> ?previousTurnId .
956
- FILTER(?previousTurnId < ${currentTurnIdLiteral})
976
+ : `SELECT ?previousTurnId WHERE {
977
+ ?previousTurn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
978
+ ?previousTurn <${SCHEMA}isPartOf> <${sessionUri}> .
979
+ ?previousTurn <${DKG_ONT}turnId> ?previousTurnId .
980
+ FILTER(?previousTurnId < ${currentTurnIdLiteral})
957
981
  } ORDER BY DESC(?previousTurnId) LIMIT 1`;
958
982
  const previousTurnResult = await this.tools.query(previousTurnQuery, this.wmReadOpts());
959
983
  const previousTurnId = stripRdfLiteral((previousTurnResult.bindings ?? [])[0]?.previousTurnId ?? '').trim() || null;
960
984
  const turnIndexResult = currentTsLiteral
961
- ? await this.tools.query(`SELECT (COUNT(*) AS ?c) WHERE {
962
- ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
963
- ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
964
- ?turn <${DKG_ONT}turnId> ?tid .
965
- ?turn <${SCHEMA}dateCreated> ?ts .
966
- FILTER(
967
- ?ts < ${currentTsLiteral}
968
- || (?ts = ${currentTsLiteral} && ?tid <= ${currentTurnIdLiteral})
969
- )
985
+ ? await this.tools.query(`SELECT (COUNT(*) AS ?c) WHERE {
986
+ ?turn <${RDF_TYPE}> <${DKG_ONT}ChatTurn> .
987
+ ?turn <${SCHEMA}isPartOf> <${sessionUri}> .
988
+ ?turn <${DKG_ONT}turnId> ?tid .
989
+ ?turn <${SCHEMA}dateCreated> ?ts .
990
+ FILTER(
991
+ ?ts < ${currentTsLiteral}
992
+ || (?ts = ${currentTsLiteral} && ?tid <= ${currentTurnIdLiteral})
993
+ )
970
994
  }`, this.wmReadOpts())
971
995
  : { bindings: [{ c: String(previousTurnId ? 2 : 1) }] };
972
996
  const turnIndex = Math.max(0, sumBindingValues(turnIndexResult.bindings, 'c'));
@@ -1005,10 +1029,10 @@ export class ChatMemoryManager {
1005
1029
  triples: [],
1006
1030
  };
1007
1031
  }
1008
- const turnMessagesResult = await this.tools.query(`SELECT ?user ?assistant WHERE {
1009
- <${turnUri}> <${SCHEMA}isPartOf> <${sessionUri}> .
1010
- <${turnUri}> <${DKG_ONT}hasUserMessage> ?user .
1011
- <${turnUri}> <${DKG_ONT}hasAssistantMessage> ?assistant .
1032
+ const turnMessagesResult = await this.tools.query(`SELECT ?user ?assistant WHERE {
1033
+ <${turnUri}> <${SCHEMA}isPartOf> <${sessionUri}> .
1034
+ <${turnUri}> <${DKG_ONT}hasUserMessage> ?user .
1035
+ <${turnUri}> <${DKG_ONT}hasAssistantMessage> ?assistant .
1012
1036
  } LIMIT 1`, this.wmReadOpts());
1013
1037
  const turnMessages = (turnMessagesResult.bindings ?? [])[0];
1014
1038
  const userMsgUri = String(turnMessages?.user ?? '').replace(/[<>]/g, '');
@@ -1030,18 +1054,18 @@ export class ChatMemoryManager {
1030
1054
  triples: [],
1031
1055
  };
1032
1056
  }
1033
- const relatedSubjectsResult = await this.tools.query(`SELECT DISTINCT ?s WHERE {
1034
- VALUES ?msg { <${userMsgUri}> <${assistantMsgUri}> }
1035
- { BIND(<${sessionUri}> AS ?s) }
1036
- UNION { BIND(<${turnUri}> AS ?s) }
1037
- UNION { BIND(?msg AS ?s) }
1038
- UNION { <${assistantMsgUri}> <${DKG_ONT}usedTool> ?s }
1039
- UNION { ?s <${DKG_ONT}mentionedIn> ?msg }
1040
- UNION {
1041
- ?entity <${DKG_ONT}mentionedIn> ?msg .
1042
- ?s <${DKG_ONT}contains> ?entity .
1043
- ?s <${DKG_ONT}extractedFrom> <${sessionUri}> .
1044
- }
1057
+ const relatedSubjectsResult = await this.tools.query(`SELECT DISTINCT ?s WHERE {
1058
+ VALUES ?msg { <${userMsgUri}> <${assistantMsgUri}> }
1059
+ { BIND(<${sessionUri}> AS ?s) }
1060
+ UNION { BIND(<${turnUri}> AS ?s) }
1061
+ UNION { BIND(?msg AS ?s) }
1062
+ UNION { <${assistantMsgUri}> <${DKG_ONT}usedTool> ?s }
1063
+ UNION { ?s <${DKG_ONT}mentionedIn> ?msg }
1064
+ UNION {
1065
+ ?entity <${DKG_ONT}mentionedIn> ?msg .
1066
+ ?s <${DKG_ONT}contains> ?entity .
1067
+ ?s <${DKG_ONT}extractedFrom> <${sessionUri}> .
1068
+ }
1045
1069
  } LIMIT 5000`, this.wmReadOpts());
1046
1070
  const subjectSet = new Set([sessionUri, turnUri, userMsgUri, assistantMsgUri]);
1047
1071
  for (const b of relatedSubjectsResult.bindings ?? []) {
@@ -1053,9 +1077,9 @@ export class ChatMemoryManager {
1053
1077
  const values = [...subjectSet]
1054
1078
  .map((iri) => `<${iri}>`)
1055
1079
  .join(' ');
1056
- const deltaResult = await this.tools.query(`CONSTRUCT { ?s ?p ?o } WHERE {
1057
- VALUES ?s { ${values} }
1058
- ?s ?p ?o .
1080
+ const deltaResult = await this.tools.query(`CONSTRUCT { ?s ?p ?o } WHERE {
1081
+ VALUES ?s { ${values} }
1082
+ ?s ?p ?o .
1059
1083
  }`, this.wmReadOpts());
1060
1084
  const quads = Array.isArray(deltaResult?.quads) ? deltaResult.quads : [];
1061
1085
  const triples = quads.map((q) => ({
@@ -1089,11 +1113,11 @@ export class ChatMemoryManager {
1089
1113
  await this.ensureInitialized();
1090
1114
  const sessionUri = `${CHAT_NS}session:${sessionId}`;
1091
1115
  const rootPattern = buildSessionRootPattern(sessionUri);
1092
- const countQuery = `SELECT (COUNT(*) AS ?c) WHERE {
1093
- {
1094
- SELECT DISTINCT ?s WHERE ${rootPattern} LIMIT 5000
1095
- }
1096
- ?s ?p ?o
1116
+ const countQuery = `SELECT (COUNT(*) AS ?c) WHERE {
1117
+ {
1118
+ SELECT DISTINCT ?s WHERE ${rootPattern} LIMIT 5000
1119
+ }
1120
+ ?s ?p ?o
1097
1121
  }`;
1098
1122
  const swmCountResult = await this.tools.query(countQuery, {
1099
1123
  contextGraphId: this.agentContextGraph,