Add a node if it doesn't exist. Returns node_id. Args: source_document: doc_id from documents_store (provenance pointer). source_chunks: list of chunk_ids that mention this entity.
(
name: str,
node_type: str,
source_document: str | None = None,
source_chunks: list[str] | None = None,
)
| 36 | |
| 37 | |
| 38 | def add_node( |
| 39 | name: str, |
| 40 | node_type: str, |
| 41 | source_document: str | None = None, |
| 42 | source_chunks: list[str] | None = None, |
| 43 | ) -> str: |
| 44 | """ |
| 45 | Add a node if it doesn't exist. Returns node_id. |
| 46 | |
| 47 | Args: |
| 48 | source_document: doc_id from documents_store (provenance pointer). |
| 49 | source_chunks: list of chunk_ids that mention this entity. |
| 50 | """ |
| 51 | graph = _load() |
| 52 | name_lower = name.strip().lower() |
| 53 | |
| 54 | # Deduplication: search by normalized name |
| 55 | for node_id, node in graph["nodes"].items(): |
| 56 | if node["name"] == name_lower: |
| 57 | # Merge provenance if new info provided |
| 58 | changed = False |
| 59 | if source_document and node.get("source_document") is None: |
| 60 | node["source_document"] = source_document |
| 61 | changed = True |
| 62 | if source_chunks: |
| 63 | existing = set(node.get("source_chunks") or []) |
| 64 | merged = list(existing | set(source_chunks)) |
| 65 | if merged != list(existing): |
| 66 | node["source_chunks"] = merged |
| 67 | changed = True |
| 68 | if changed: |
| 69 | _save(graph) |
| 70 | return node_id |
| 71 | |
| 72 | node_id = str(uuid.uuid4())[:8] |
| 73 | graph["nodes"][node_id] = { |
| 74 | "name": name_lower, |
| 75 | "type": node_type.strip().lower(), |
| 76 | "source_document": source_document, |
| 77 | "source_chunks": source_chunks or [], |
| 78 | } |
| 79 | _save(graph) |
| 80 | return node_id |
| 81 | |
| 82 | |
| 83 | def add_edge( |