From 465a4deb5cff0418200492fe49ad4b36ab669ae1 Mon Sep 17 00:00:00 2001 From: liji <532311301@qq.com> Date: Tue, 28 Oct 2025 17:45:12 +0800 Subject: [PATCH 1/5] feat: fix sources --- src/memos/memories/textual/item.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/memos/memories/textual/item.py b/src/memos/memories/textual/item.py index f6254efbb..eae6b5ce8 100644 --- a/src/memos/memories/textual/item.py +++ b/src/memos/memories/textual/item.py @@ -1,6 +1,7 @@ """Defines memory item types for textual memory.""" import json +import logging import uuid from datetime import datetime @@ -123,6 +124,25 @@ class TreeNodeTextualMemoryMetadata(TextualMemoryMetadata): def coerce_sources(cls, v): if v is None: return v + # Handle string representation of sources (e.g., from PostgreSQL array or malformed data) + if isinstance(v, str): + logging.info(f"[coerce_sources] v: {v} type: {type(v)}") + # If it's a string that looks like a list representation, try to parse it + # This handles cases like: "[uuid1, uuid2, uuid3]" or "[item1, item2]" + v_stripped = v.strip() + if v_stripped.startswith("[") and v_stripped.endswith("]"): + # Remove brackets and split by comma + content = v_stripped[1:-1].strip() + if content: + # Split by comma and clean up each item + items = [item.strip() for item in content.split(",")] + # Convert to list of strings + v = items + else: + v = [] + else: + # Single string, wrap in list + v = [v] if not isinstance(v, list): raise TypeError("sources must be a list") out = [] From 3f29bcaa10fc1c72e198414e20e66107dfd51c18 Mon Sep 17 00:00:00 2001 From: liji <532311301@qq.com> Date: Tue, 28 Oct 2025 18:46:33 +0800 Subject: [PATCH 2/5] feat: fix sources --- src/memos/memories/textual/item.py | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/memos/memories/textual/item.py b/src/memos/memories/textual/item.py index eae6b5ce8..48f42fa4c 100644 --- a/src/memos/memories/textual/item.py +++ b/src/memos/memories/textual/item.py @@ -125,24 +125,24 @@ def coerce_sources(cls, v): if v is None: return v # Handle string representation of sources (e.g., from PostgreSQL array or malformed data) - if isinstance(v, str): - logging.info(f"[coerce_sources] v: {v} type: {type(v)}") - # If it's a string that looks like a list representation, try to parse it - # This handles cases like: "[uuid1, uuid2, uuid3]" or "[item1, item2]" - v_stripped = v.strip() - if v_stripped.startswith("[") and v_stripped.endswith("]"): - # Remove brackets and split by comma - content = v_stripped[1:-1].strip() - if content: - # Split by comma and clean up each item - items = [item.strip() for item in content.split(",")] - # Convert to list of strings - v = items - else: - v = [] + if isinstance(v, str): + logging.info(f"[coerce_sources] v: {v} type: {type(v)}") + # If it's a string that looks like a list representation, try to parse it + # This handles cases like: "[uuid1, uuid2, uuid3]" or "[item1, item2]" + v_stripped = v.strip() + if v_stripped.startswith("[") and v_stripped.endswith("]"): + # Remove brackets and split by comma + content = v_stripped[1:-1].strip() + if content: + # Split by comma and clean up each item + items = [item.strip() for item in content.split(",")] + # Convert to list of strings + v = items else: - # Single string, wrap in list - v = [v] + v = [] + else: + # Single string, wrap in list + v = [v] if not isinstance(v, list): raise TypeError("sources must be a list") out = [] From db8294b7b44e9c28d59ea156fc1882cc60f80687 Mon Sep 17 00:00:00 2001 From: liji <532311301@qq.com> Date: Wed, 29 Oct 2025 02:00:43 +0800 Subject: [PATCH 3/5] feat: fix nebular --- src/memos/graph_dbs/nebular.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/memos/graph_dbs/nebular.py b/src/memos/graph_dbs/nebular.py index 12b493e58..00bd04e6d 100644 --- a/src/memos/graph_dbs/nebular.py +++ b/src/memos/graph_dbs/nebular.py @@ -1551,7 +1551,7 @@ def _ensure_database_exists(self): """ self.execute_query(create_tag, auto_set_db=False) else: - describe_query = f"DESCRIBE NODE TYPE Memory OF {graph_type_name};" + describe_query = f"DESCRIBE NODE TYPE Memory OF {graph_type_name}" desc_result = self.execute_query(describe_query, auto_set_db=False) memory_fields = [] From 426a307eccd72ebd7c07383bcc65e189f5b447de Mon Sep 17 00:00:00 2001 From: liji <532311301@qq.com> Date: Wed, 29 Oct 2025 11:19:39 +0800 Subject: [PATCH 4/5] feat: fix polardb edges --- src/memos/graph_dbs/polardb.py | 58 ++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/memos/graph_dbs/polardb.py b/src/memos/graph_dbs/polardb.py index 38e71298f..292d143be 100644 --- a/src/memos/graph_dbs/polardb.py +++ b/src/memos/graph_dbs/polardb.py @@ -1776,24 +1776,39 @@ def export_graph( for row in edge_results: source_agtype, target_agtype, edge_agtype = row + + # Extract and clean source + source_raw = source_agtype.value if hasattr(source_agtype, "value") else str(source_agtype) + if isinstance(source_raw, str) and source_raw.startswith('"') and source_raw.endswith('"'): + source = source_raw[1:-1] + else: + source = str(source_raw) + + # Extract and clean target + target_raw = target_agtype.value if hasattr(target_agtype, "value") else str(target_agtype) + if isinstance(target_raw, str) and target_raw.startswith('"') and target_raw.endswith('"'): + target = target_raw[1:-1] + else: + target = str(target_raw) + + # Extract and clean edge type + type_raw = edge_agtype.value if hasattr(edge_agtype, "value") else str(edge_agtype) + if isinstance(type_raw, str) and type_raw.startswith('"') and type_raw.endswith('"'): + edge_type = type_raw[1:-1] + else: + edge_type = str(type_raw) + edges.append( { - "source": source_agtype.value - if hasattr(source_agtype, "value") - else str(source_agtype), - "target": target_agtype.value - if hasattr(target_agtype, "value") - else str(target_agtype), - "type": edge_agtype.value - if hasattr(edge_agtype, "value") - else str(edge_agtype), + "source": source, + "target": target, + "type": edge_type, } ) except Exception as e: logger.error(f"[EXPORT GRAPH - EDGES] Exception: {e}", exc_info=True) raise RuntimeError(f"[EXPORT GRAPH - EDGES] Exception: {e}") from e - return {"nodes": nodes, "edges": edges} @timed @@ -2765,9 +2780,26 @@ def get_edges( edges = [] for row in results: - from_id = row[0].value if hasattr(row[0], "value") else row[0] - to_id = row[1].value if hasattr(row[1], "value") else row[1] - edge_type = row[2].value if hasattr(row[2], "value") else row[2] + # Extract and clean from_id + from_id_raw = row[0].value if hasattr(row[0], "value") else row[0] + if isinstance(from_id_raw, str) and from_id_raw.startswith('"') and from_id_raw.endswith('"'): + from_id = from_id_raw[1:-1] + else: + from_id = str(from_id_raw) + + # Extract and clean to_id + to_id_raw = row[1].value if hasattr(row[1], "value") else row[1] + if isinstance(to_id_raw, str) and to_id_raw.startswith('"') and to_id_raw.endswith('"'): + to_id = to_id_raw[1:-1] + else: + to_id = str(to_id_raw) + + # Extract and clean edge_type + edge_type_raw = row[2].value if hasattr(row[2], "value") else row[2] + if isinstance(edge_type_raw, str) and edge_type_raw.startswith('"') and edge_type_raw.endswith('"'): + edge_type = edge_type_raw[1:-1] + else: + edge_type = str(edge_type_raw) edges.append({"from": from_id, "to": to_id, "type": edge_type}) return edges From 04522d2918af379a8974d48cffb50318f24dc8d6 Mon Sep 17 00:00:00 2001 From: liji <532311301@qq.com> Date: Wed, 29 Oct 2025 11:50:58 +0800 Subject: [PATCH 5/5] feat: format polardb --- src/memos/graph_dbs/polardb.py | 64 ++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/src/memos/graph_dbs/polardb.py b/src/memos/graph_dbs/polardb.py index 292d143be..b9bc2c8e5 100644 --- a/src/memos/graph_dbs/polardb.py +++ b/src/memos/graph_dbs/polardb.py @@ -1776,28 +1776,50 @@ def export_graph( for row in edge_results: source_agtype, target_agtype, edge_agtype = row - + # Extract and clean source - source_raw = source_agtype.value if hasattr(source_agtype, "value") else str(source_agtype) - if isinstance(source_raw, str) and source_raw.startswith('"') and source_raw.endswith('"'): + source_raw = ( + source_agtype.value + if hasattr(source_agtype, "value") + else str(source_agtype) + ) + if ( + isinstance(source_raw, str) + and source_raw.startswith('"') + and source_raw.endswith('"') + ): source = source_raw[1:-1] else: source = str(source_raw) - + # Extract and clean target - target_raw = target_agtype.value if hasattr(target_agtype, "value") else str(target_agtype) - if isinstance(target_raw, str) and target_raw.startswith('"') and target_raw.endswith('"'): + target_raw = ( + target_agtype.value + if hasattr(target_agtype, "value") + else str(target_agtype) + ) + if ( + isinstance(target_raw, str) + and target_raw.startswith('"') + and target_raw.endswith('"') + ): target = target_raw[1:-1] else: target = str(target_raw) - + # Extract and clean edge type - type_raw = edge_agtype.value if hasattr(edge_agtype, "value") else str(edge_agtype) - if isinstance(type_raw, str) and type_raw.startswith('"') and type_raw.endswith('"'): + type_raw = ( + edge_agtype.value if hasattr(edge_agtype, "value") else str(edge_agtype) + ) + if ( + isinstance(type_raw, str) + and type_raw.startswith('"') + and type_raw.endswith('"') + ): edge_type = type_raw[1:-1] else: edge_type = str(type_raw) - + edges.append( { "source": source, @@ -2782,21 +2804,33 @@ def get_edges( for row in results: # Extract and clean from_id from_id_raw = row[0].value if hasattr(row[0], "value") else row[0] - if isinstance(from_id_raw, str) and from_id_raw.startswith('"') and from_id_raw.endswith('"'): + if ( + isinstance(from_id_raw, str) + and from_id_raw.startswith('"') + and from_id_raw.endswith('"') + ): from_id = from_id_raw[1:-1] else: from_id = str(from_id_raw) - + # Extract and clean to_id to_id_raw = row[1].value if hasattr(row[1], "value") else row[1] - if isinstance(to_id_raw, str) and to_id_raw.startswith('"') and to_id_raw.endswith('"'): + if ( + isinstance(to_id_raw, str) + and to_id_raw.startswith('"') + and to_id_raw.endswith('"') + ): to_id = to_id_raw[1:-1] else: to_id = str(to_id_raw) - + # Extract and clean edge_type edge_type_raw = row[2].value if hasattr(row[2], "value") else row[2] - if isinstance(edge_type_raw, str) and edge_type_raw.startswith('"') and edge_type_raw.endswith('"'): + if ( + isinstance(edge_type_raw, str) + and edge_type_raw.startswith('"') + and edge_type_raw.endswith('"') + ): edge_type = edge_type_raw[1:-1] else: edge_type = str(edge_type_raw)