Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/memos/api/handlers/chat_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def handle_chat_complete(self, chat_req: APIChatCompleteRequest) -> dict[str, An
include_preference=chat_req.include_preference,
pref_top_k=chat_req.pref_top_k,
filter=chat_req.filter,
relativity=chat_req.relativity,
)

search_response = self.search_handler.handle_search_memories(search_req)
Expand Down Expand Up @@ -269,6 +270,7 @@ def generate_chat_response() -> Generator[str, None, None]:
include_preference=chat_req.include_preference,
pref_top_k=chat_req.pref_top_k,
filter=chat_req.filter,
relativity=chat_req.relativity,
)

search_response = self.search_handler.handle_search_memories(search_req)
Expand Down Expand Up @@ -811,6 +813,7 @@ def generate_chat_response() -> Generator[str, None, None]:
include_preference=chat_req.include_preference,
pref_top_k=chat_req.pref_top_k,
filter=chat_req.filter,
relativity=chat_req.relativity,
)

search_response = self.search_handler.handle_search_memories(search_req)
Expand Down
22 changes: 18 additions & 4 deletions src/memos/api/handlers/memory_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,12 @@ def handle_get_memories_dashboard(
get_mem_req: GetMemoryDashboardRequest, naive_mem_cube: NaiveMemCube
) -> GetMemoryResponse:
results: dict[str, Any] = {"text_mem": [], "pref_mem": [], "tool_mem": [], "skill_mem": []}
# for statistics
total_text_nodes, total_tool_nodes, total_skill_nodes, total_preference_nodes = 0, 0, 0, 0
total_tool_nodes = 0
total_skill_nodes = 0
total_preference_nodes = 0

text_memory_type = ["WorkingMemory", "LongTermMemory", "UserMemory", "OuterMemory"]
text_memories_info = naive_mem_cube.text_mem.get_all(
user_name=get_mem_req.mem_cube_id,
Expand All @@ -421,7 +427,7 @@ def handle_get_memories_dashboard(
filter=get_mem_req.filter,
memory_type=text_memory_type,
)
text_memories, _ = text_memories_info["nodes"], text_memories_info["total_nodes"]
text_memories, total_text_nodes = text_memories_info["nodes"], text_memories_info["total_nodes"]

# Group text memories by cube_id from metadata.user_name
text_mem_by_cube: dict[str, list] = {}
Expand Down Expand Up @@ -453,7 +459,7 @@ def handle_get_memories_dashboard(
filter=get_mem_req.filter,
memory_type=["ToolSchemaMemory", "ToolTrajectoryMemory"],
)
tool_memories, _ = (
tool_memories, total_tool_nodes = (
tool_memories_info["nodes"],
tool_memories_info["total_nodes"],
)
Expand Down Expand Up @@ -488,7 +494,7 @@ def handle_get_memories_dashboard(
filter=get_mem_req.filter,
memory_type=["SkillMemory"],
)
skill_memories, _ = (
skill_memories, total_skill_nodes = (
skill_memories_info["nodes"],
skill_memories_info["total_nodes"],
)
Expand All @@ -515,7 +521,6 @@ def handle_get_memories_dashboard(
]

preferences: list[TextualMemoryItem] = []
total_preference_nodes = 0

format_preferences = []
if get_mem_req.include_preference and naive_mem_cube.pref_mem is not None:
Expand Down Expand Up @@ -578,4 +583,13 @@ def handle_get_memories_dashboard(
"skill_mem": results.get("skill_mem", []),
}

# statistics
statistics = {
"total_text_nodes": total_text_nodes,
"total_tool_nodes": total_tool_nodes,
"total_skill_nodes": total_skill_nodes,
"total_preference_nodes": total_preference_nodes,
}
filtered_results["statistics"] = statistics

return GetMemoryResponse(message="Memories retrieved successfully", data=filtered_results)
18 changes: 18 additions & 0 deletions src/memos/api/product_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ class ChatRequest(BaseRequest):
add_message_on_answer: bool = Field(True, description="Add dialogs to memory after chat")
manager_user_id: str | None = Field(None, description="Manager User ID")
project_id: str | None = Field(None, description="Project ID")
relativity: float = Field(
0.0,
ge=0,
description=(
"Relevance threshold for recalled memories. "
"Only memories with metadata.relativity >= relativity will be returned. "
"Use 0 to disable threshold filtering. Default: 0.3."
),
)

# ==== Filter conditions ====
filter: dict[str, Any] | None = Field(
Expand Down Expand Up @@ -775,6 +784,15 @@ class APIChatCompleteRequest(BaseRequest):
add_message_on_answer: bool = Field(True, description="Add dialogs to memory after chat")
manager_user_id: str | None = Field(None, description="Manager User ID")
project_id: str | None = Field(None, description="Project ID")
relativity: float = Field(
0.0,
ge=0,
description=(
"Relevance threshold for recalled memories. "
"Only memories with metadata.relativity >= relativity will be returned. "
"Use 0 to disable threshold filtering. Default: 0.3."
),
)

# ==== Filter conditions ====
filter: dict[str, Any] | None = Field(
Expand Down
41 changes: 23 additions & 18 deletions src/memos/mem_reader/read_skill_memory/process_skill_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def _generate_content_by_llm(llm: BaseLLM, prompt_template: str, **kwargs) -> An
try:
prompt = prompt_template.format(**kwargs)
response = llm.generate([{"role": "user", "content": prompt}])
if not response:
logger.warning("[PROCESS_SKILLS] LLM returned empty or invalid response")
return {} if "json" in prompt_template.lower() else ""
if "json" in prompt_template.lower():
response = response.replace("```json", "").replace("```", "").strip()
return json.loads(response)
Expand Down Expand Up @@ -436,6 +439,9 @@ def _extract_skill_memory_by_llm(
skills_llm = os.getenv("SKILLS_LLM", None)
llm_kwargs = {"model_name_or_path": skills_llm} if skills_llm else {}
response_text = llm.generate(prompt, **llm_kwargs)
if not response_text:
logger.warning("[PROCESS_SKILLS] LLM returned empty or invalid response")
continue
# Clean up response (remove Markdown code blocks if present)
logger.info(f"[Skill Memory]: response_text {response_text}")
response_text = response_text.strip()
Expand Down Expand Up @@ -561,6 +567,9 @@ def _extract_skill_memory_by_llm_md(
skills_llm = os.getenv("SKILLS_LLM", None)
llm_kwargs = {"model_name_or_path": skills_llm} if skills_llm else {}
response_text = llm.generate(prompt, **llm_kwargs)
if not response_text:
logger.warning("[PROCESS_SKILLS] LLM returned empty or invalid response")
continue
# Clean up response (remove Markdown code blocks if present)
logger.info(f"[Skill Memory]: response_text {response_text}")
response_text = response_text.strip()
Expand Down Expand Up @@ -641,26 +650,22 @@ def _rewrite_query(task_type: str, messages: MessageList, llm: BaseLLM, rewrite_
)
prompt = [{"role": "user", "content": prompt_content}]

# Call LLM to rewrite the query with retry logic
for attempt in range(3):
try:
response_text = llm.generate(prompt)
# Clean up response (remove any markdown formatting if present)
response_text = response_text.strip()
logger.info(f"[PROCESS_SKILLS] Rewritten query for task '{task_type}': {response_text}")
return response_text
except Exception as e:
# Call LLM to rewrite the query
try:
response_text = llm.generate(prompt)
# Clean up response (remove any markdown formatting if present)
if response_text and isinstance(response_text, str):
return response_text.strip()
else:
logger.warning(
f"[PROCESS_SKILLS] LLM query rewrite failed (attempt {attempt + 1}): {e}"
"[PROCESS_SKILLS] LLM returned empty or invalid response, returning first message content"
)
if attempt == 2:
logger.warning(
"[PROCESS_SKILLS] LLM query rewrite failed after 3 retries, returning first message content"
)
return messages[0]["content"] if messages else ""

# Fallback (should not reach here due to return in exception handling)
return messages[0]["content"] if messages else ""
return messages[0]["content"] if messages else ""
except Exception as e:
logger.warning(
f"[PROCESS_SKILLS] LLM query rewrite failed: {e}, returning first message content"
)
return messages[0]["content"] if messages else ""


@require_python_package(
Expand Down