MCPcopy
hub / github.com/rohitg00/agentmemory / parseGraphXml

Function parseGraphXml

src/functions/graph.ts:378–451  ·  view source on GitHub ↗
(
  xml: string,
  observationIds: string[],
)

Source from the content-addressed store, hash-verified

376}
377
378function parseGraphXml(
379 xml: string,
380 observationIds: string[],
381): {
382 nodes: GraphNode[];
383 edges: GraphEdge[];
384} {
385 const nodes: GraphNode[] = [];
386 const edges: GraphEdge[] = [];
387 const now = new Date().toISOString();
388
389 // Two passes because <entity> can be self-closing or have a body
390 // (<property> children). The self-closing form needs `[^>]*[^/]` on
391 // the attr group so the trailing `/` isn't swallowed into the match
392 // (root cause of #494). The explicit-close form picks up the
393 // property block.
394 const entitySelfClose = /<entity\b([^>]*?)\/>/g;
395 const entityWithBody = /<entity\b([^>]*[^/])>([\s\S]*?)<\/entity>/g;
396
397 const addEntity = (rawAttrs: string, propsBlock = ""): void => {
398 const attrs = parseAttrs(rawAttrs);
399 const type = attrs["type"] as GraphNode["type"] | undefined;
400 const name = attrs["name"];
401 if (!type || !name) return;
402 const properties: Record<string, string> = {};
403 const propRegex = /<property\s+key="([^"]+)">([^<]*)<\/property>/g;
404 let propMatch;
405 while ((propMatch = propRegex.exec(propsBlock)) !== null) {
406 properties[propMatch[1]] = propMatch[2];
407 }
408 nodes.push({
409 id: generateId("gn"),
410 type,
411 name,
412 properties,
413 sourceObservationIds: observationIds,
414 createdAt: now,
415 });
416 };
417
418 let match;
419 while ((match = entitySelfClose.exec(xml)) !== null) {
420 addEntity(match[1]);
421 }
422 while ((match = entityWithBody.exec(xml)) !== null) {
423 addEntity(match[1], match[2]);
424 }
425
426 const relRegex = /<relationship\b([^>]*?)\/>/g;
427 while ((match = relRegex.exec(xml)) !== null) {
428 const attrs = parseAttrs(match[1]);
429 const type = attrs["type"] as GraphEdge["type"] | undefined;
430 const sourceName = attrs["source"];
431 const targetName = attrs["target"];
432 if (!type || !sourceName || !targetName) continue;
433 const parsedWeight = parseFloat(attrs["weight"] ?? "");
434 const weight = Number.isFinite(parsedWeight) ? parsedWeight : 0.5;
435

Callers 1

registerGraphFunctionFunction · 0.85

Calls 4

addEntityFunction · 0.85
parseAttrsFunction · 0.85
generateIdFunction · 0.85
pushMethod · 0.80

Tested by

no test coverage detected