@@ -30,7 +30,7 @@ def detect(
3030 self , memory : TextualMemoryItem , top_k : int = 5 , scope : str | None = None
3131 ) -> list [tuple [TextualMemoryItem , TextualMemoryItem ]]:
3232 """
33- Detect redundancy by finding the most similar items in the graph database based on embedding, then use LLM to judge conflict .
33+ Detect redundancy by finding the most similar items in the graph database based on embedding, then use LLM to judge redundancy .
3434 Args:
3535 memory: The memory item (should have an embedding attribute or field).
3636 top_k: Number of top similar nodes to retrieve.
@@ -49,15 +49,15 @@ def detect(
4949 for info in embedding_candidates_info
5050 if info ["score" ] >= self .EMBEDDING_THRESHOLD and info ["id" ] != memory .id
5151 ]
52- # 3. Judge conflicts using LLM
52+ # 3. Judge redundancys using LLM
5353 embedding_candidates = self .graph_store .get_nodes (embedding_candidates_ids )
5454 redundant_pairs = []
5555 for embedding_candidate in embedding_candidates :
5656 embedding_candidate = TextualMemoryItem .from_dict (embedding_candidate )
5757 prompt = [
5858 {
5959 "role" : "system" ,
60- "content" : "You are a conflict detector for memory items." ,
60+ "content" : "You are a redundancy detector for memory items." ,
6161 },
6262 {
6363 "role" : "user" ,
@@ -71,25 +71,25 @@ def detect(
7171 if "yes" in result .lower ():
7272 redundant_pairs .append ([memory , embedding_candidate ])
7373 if len (redundant_pairs ):
74- conflict_text = "\n " .join (
74+ redundant_text = "\n " .join (
7575 f'"{ pair [0 ].memory !s} " <==REDUNDANCY==> "{ pair [1 ].memory !s} "'
7676 for pair in redundant_pairs
7777 )
7878 logger .warning (
79- f"Detected { len (redundant_pairs )} redundancies for memory { memory .id } \n { conflict_text } "
79+ f"Detected { len (redundant_pairs )} redundancies for memory { memory .id } \n { redundant_text } "
8080 )
8181 return redundant_pairs
8282
8383 def resolve_two_nodes (self , memory_a : TextualMemoryItem , memory_b : TextualMemoryItem ) -> None :
8484 """
8585 Resolve detected redundancies between two memory items using LLM fusion.
8686 Args:
87- memory_a: The first conflicting memory item.
88- memory_b: The second conflicting memory item.
87+ memory_a: The first redundant memory item.
88+ memory_b: The second redundant memory item.
8989 Returns:
9090 A fused TextualMemoryItem representing the resolved memory.
9191 """
92-
92+ return # waiting for implementation
9393 # ———————————— 1. LLM generate fused memory ————————————
9494 metadata_for_resolve = ["key" , "background" , "confidence" , "updated_at" ]
9595 metadata_1 = memory_a .metadata .model_dump_json (include = metadata_for_resolve )
@@ -115,18 +115,10 @@ def resolve_two_nodes(self, memory_a: TextualMemoryItem, memory_b: TextualMemory
115115 try :
116116 answer = re .search (r"<answer>(.*?)</answer>" , response , re .DOTALL )
117117 answer = answer .group (1 ).strip ()
118- # —————— 2.1 Can't resolve conflict, hard update by comparing timestamp ————
119- if len (answer ) <= 10 and "no" in answer .lower ():
120- logger .warning (
121- f"Conflict between { memory_a .id } and { memory_b .id } could not be resolved. "
122- )
123- self ._hard_update (memory_a , memory_b )
124- # —————— 2.2 Conflict resolved, update metadata and memory ————
125- else :
126- fixed_metadata = self ._merge_metadata (answer , memory_a .metadata , memory_b .metadata )
127- merged_memory = TextualMemoryItem (memory = answer , metadata = fixed_metadata )
128- logger .info (f"Resolved result: { merged_memory } " )
129- self ._resolve_in_graph (memory_a , memory_b , merged_memory )
118+ fixed_metadata = self ._merge_metadata (answer , memory_a .metadata , memory_b .metadata )
119+ merged_memory = TextualMemoryItem (memory = answer , metadata = fixed_metadata )
120+ logger .info (f"Resolved result: { merged_memory } " )
121+ self ._resolve_in_graph (memory_a , memory_b , merged_memory )
130122 except json .decoder .JSONDecodeError :
131123 logger .error (f"Failed to parse LLM response: { response } " )
132124
@@ -145,48 +137,37 @@ def resolve_one_node(self, memory: TextualMemoryItem) -> None:
145137 )
146138 logger .debug (f"Merged memory: { memory .memory } " )
147139
148- def _hard_update (self , memory_a : TextualMemoryItem , memory_b : TextualMemoryItem ):
149- """
150- Hard update: compare updated_at, keep the newer one, overwrite the older one's metadata.
151- """
152- time_a = datetime .fromisoformat (memory_a .metadata .updated_at )
153- time_b = datetime .fromisoformat (memory_b .metadata .updated_at )
154-
155- newer_mem = memory_a if time_a >= time_b else memory_b
156- older_mem = memory_b if time_a >= time_b else memory_a
157-
158- self .graph_store .delete_node (older_mem .id )
159- logger .warning (
160- f"Delete older memory { older_mem .id } : <{ older_mem .memory } > due to conflict with { newer_mem .id } : <{ newer_mem .memory } >"
161- )
162-
163140 def _resolve_in_graph (
164141 self ,
165- conflict_a : TextualMemoryItem ,
166- conflict_b : TextualMemoryItem ,
142+ redundant_a : TextualMemoryItem ,
143+ redundant_b : TextualMemoryItem ,
167144 merged : TextualMemoryItem ,
168145 ):
169- edges_a = self .graph_store .get_edges (conflict_a .id , type = "ANY" , direction = "ANY" )
170- edges_b = self .graph_store .get_edges (conflict_b .id , type = "ANY" , direction = "ANY" )
146+ edges_a = self .graph_store .get_edges (redundant_a .id , type = "ANY" , direction = "ANY" )
147+ edges_b = self .graph_store .get_edges (redundant_b .id , type = "ANY" , direction = "ANY" )
171148 all_edges = edges_a + edges_b
172149
173150 self .graph_store .add_node (
174151 merged .id , merged .memory , merged .metadata .model_dump (exclude_none = True )
175152 )
176153
177154 for edge in all_edges :
178- new_from = merged .id if edge ["from" ] in (conflict_a .id , conflict_b .id ) else edge ["from" ]
179- new_to = merged .id if edge ["to" ] in (conflict_a .id , conflict_b .id ) else edge ["to" ]
155+ new_from = (
156+ merged .id if edge ["from" ] in (redundant_a .id , redundant_b .id ) else edge ["from" ]
157+ )
158+ new_to = merged .id if edge ["to" ] in (redundant_a .id , redundant_b .id ) else edge ["to" ]
180159 if new_from == new_to :
181160 continue
182161 # Check if the edge already exists before adding
183162 if not self .graph_store .edge_exists (new_from , new_to , edge ["type" ], direction = "ANY" ):
184163 self .graph_store .add_edge (new_from , new_to , edge ["type" ])
185164
186- self .graph_store .delete_node (conflict_a .id )
187- self .graph_store .delete_node (conflict_b .id )
165+ self .graph_store .update_node (redundant_a .id , {"status" : "archived" })
166+ self .graph_store .update_node (redundant_b .id , {"status" : "archived" })
167+ self .graph_store .add_edge (redundant_a .id , merged .id , type = "MERGED_TO" )
168+ self .graph_store .add_edge (redundant_b .id , merged .id , type = "MERGED_TO" )
188169 logger .debug (
189- f"Remove { conflict_a .id } and { conflict_b .id } , and inherit their edges to { merged .id } ."
170+ f"Archive { redundant_a .id } and { redundant_b .id } , and inherit their edges to { merged .id } ."
190171 )
191172
192173 def _merge_metadata (
0 commit comments