1919from memos .llms .base import BaseLLM
2020from memos .log import get_logger
2121from memos .mem_reader .read_multi_modal import detect_lang
22- from memos .memories .textual .item import TextualMemoryItem , TreeNodeTextualMemoryMetadata
22+ from memos .memories .textual .item import (
23+ SourceMessage ,
24+ TextualMemoryItem ,
25+ TreeNodeTextualMemoryMetadata ,
26+ )
2327from memos .memories .textual .tree_text_memory .retrieve .searcher import Searcher
2428from memos .templates .skill_mem_prompt import (
2529 OTHERS_GENERATION_PROMPT ,
@@ -91,6 +95,7 @@ def _batch_extract_skills(
9195 try :
9296 skill_memory = future .result ()
9397 if skill_memory :
98+ skill_memory ["_task_type" ] = task_type
9499 results .append ((skill_memory , task_type , task_chunks .get (task_type , [])))
95100 except Exception as e :
96101 logger .warning (
@@ -901,6 +906,7 @@ def create_skill_memory_item(
901906 skill_memory : dict [str , Any ],
902907 info : dict [str , Any ],
903908 embedder : BaseEmbedder | None = None ,
909+ sources : list [SourceMessage ] | None = None ,
904910 ** kwargs : Any ,
905911) -> TextualMemoryItem :
906912 info_ = info .copy ()
@@ -923,7 +929,7 @@ def create_skill_memory_item(
923929 status = "activated" ,
924930 tags = skill_memory .get ("tags" ) or skill_memory .get ("trigger" , []),
925931 key = skill_memory .get ("name" , "" ),
926- sources = [],
932+ sources = sources or [],
927933 usage = [],
928934 background = "" ,
929935 confidence = 0.99 ,
@@ -1097,6 +1103,7 @@ def _simple_extract():
10971103 try :
10981104 skill_memory = future .result ()
10991105 if skill_memory :
1106+ skill_memory ["_task_type" ] = task_type
11001107 memories .append (skill_memory )
11011108 except Exception as e :
11021109 logger .warning (
@@ -1223,11 +1230,32 @@ def _full_extract():
12231230 except Exception as cleanup_error :
12241231 logger .warning (f"[PROCESS_SKILLS] Error cleaning up local files: { cleanup_error } " )
12251232
1233+ # Build source lookup: (role, content) → SourceMessage from fast_memory_items
1234+ source_lookup : dict [tuple [str , str ], SourceMessage ] = {}
1235+ for fast_item in fast_memory_items :
1236+ for source in getattr (fast_item .metadata , "sources" , []) or []:
1237+ source_lookup .setdefault ((source .role , source .content ), source )
1238+
12261239 # Create TextualMemoryItem objects
12271240 skill_memory_items = []
12281241 for skill_memory in skill_memories :
12291242 try :
1230- memory_item = create_skill_memory_item (skill_memory , info , embedder , ** kwargs )
1243+ # Match sources precisely via the task chunk messages that produced this skill
1244+ task_type = skill_memory .pop ("_task_type" , None )
1245+ chunk_messages = task_chunks .get (task_type , []) if task_type else []
1246+ skill_sources = []
1247+ seen = set ()
1248+ for msg in chunk_messages :
1249+ key = (msg .get ("role" ), msg .get ("content" ))
1250+ if key not in seen :
1251+ seen .add (key )
1252+ source = source_lookup .get (key )
1253+ if source :
1254+ skill_sources .append (source )
1255+
1256+ memory_item = create_skill_memory_item (
1257+ skill_memory , info , embedder , sources = skill_sources , ** kwargs
1258+ )
12311259 skill_memory_items .append (memory_item )
12321260 except Exception as e :
12331261 logger .warning (f"[PROCESS_SKILLS] Error creating skill memory item: { e } " )
0 commit comments