Skip to content

Commit 8ae07e6

Browse files
authored
Feat: deepsearch agent dock search pipeline (#524)
* feat: update memos headers * feat: headers add * feat: update search agent * feat: upadte mem story * feat: update mem scehduler * feat: update deepsearch mem code * feat: update deepsearch agent * feat: update test code * fix: remove dup config * feat: dock search pipeline * fix: code test * feat: add test scripts * feat: add test
1 parent d3b7d52 commit 8ae07e6

File tree

8 files changed

+267
-12
lines changed

8 files changed

+267
-12
lines changed

src/memos/api/handlers/base_handler.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ def mos_server(self):
161161
"""Get MOS server instance."""
162162
return self.deps.mos_server
163163

164+
@property
165+
def deepsearch_agent(self):
166+
"""Get deepsearch agent instance."""
167+
return self.deps.deepsearch_agent
168+
164169
def _validate_dependencies(self, *required_deps: str) -> None:
165170
"""
166171
Validate that required dependencies are available.

src/memos/api/handlers/component_init.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
if TYPE_CHECKING:
4747
from memos.memories.textual.tree import TreeTextMemory
48+
from memos.mem_agent.deepsearch_agent import DeepSearchMemAgent
4849
from memos.memories.textual.tree_text_memory.retrieve.internet_retriever_factory import (
4950
InternetRetrieverFactory,
5051
)
@@ -307,6 +308,10 @@ def init_server() -> dict[str, Any]:
307308
online_bot = get_online_bot_function() if dingding_enabled else None
308309
logger.info("DingDing bot is enabled")
309310

311+
deepsearch_agent = DeepSearchMemAgent(
312+
llm=llm,
313+
memory_retriever=tree_mem,
314+
)
310315
# Return all components as a dictionary for easy access and extension
311316
return {
312317
"graph_db": graph_db,
@@ -330,4 +335,5 @@ def init_server() -> dict[str, Any]:
330335
"text_mem": text_mem,
331336
"pref_mem": pref_mem,
332337
"online_bot": online_bot,
338+
"deepsearch_agent": deepsearch_agent,
333339
}

src/memos/api/handlers/search_handler.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ def __init__(self, dependencies: HandlerDependencies):
3131
dependencies: HandlerDependencies instance
3232
"""
3333
super().__init__(dependencies)
34-
self._validate_dependencies("naive_mem_cube", "mem_scheduler", "searcher")
34+
self._validate_dependencies(
35+
"naive_mem_cube", "mem_scheduler", "searcher", "deepsearch_agent"
36+
)
3537

3638
def handle_search_memories(self, search_req: APISearchRequest) -> SearchResponse:
3739
"""
@@ -52,10 +54,10 @@ def handle_search_memories(self, search_req: APISearchRequest) -> SearchResponse
5254

5355
results = cube_view.search_memories(search_req)
5456

55-
self.logger.info(f"[AddHandler] Final add results count={len(results)}")
57+
self.logger.info(f"[SearchHandler] Final search results count={len(results)}")
5658

5759
return SearchResponse(
58-
message="Memory searched successfully",
60+
message="Search completed successfully",
5961
data=results,
6062
)
6163

@@ -83,6 +85,7 @@ def _build_cube_view(self, search_req: APISearchRequest) -> MemCubeView:
8385
mem_scheduler=self.mem_scheduler,
8486
logger=self.logger,
8587
searcher=self.searcher,
88+
deepsearch_agent=self.deepsearch_agent,
8689
)
8790
else:
8891
single_views = [
@@ -93,6 +96,7 @@ def _build_cube_view(self, search_req: APISearchRequest) -> MemCubeView:
9396
mem_scheduler=self.mem_scheduler,
9497
logger=self.logger,
9598
searcher=self.searcher,
99+
deepsearch_agent=self.deepsearch_agent,
96100
)
97101
for cube_id in cube_ids
98102
]

src/memos/mem_agent/deepsearch_agent.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
if TYPE_CHECKING:
2727
from memos.types import MessageList
2828

29+
logger = get_logger(__name__)
30+
2931

3032
class JSONResponseParser:
3133
"""Elegant JSON response parser for LLM outputs"""
@@ -48,9 +50,6 @@ def parse(response: str) -> dict[str, Any]:
4850
raise ValueError(f"Cannot parse JSON response: {response[:100]}...")
4951

5052

51-
logger = get_logger(__name__)
52-
53-
5453
class QueryRewriter(BaseMemAgent):
5554
"""Specialized agent for rewriting queries based on conversation history"""
5655

@@ -141,7 +140,7 @@ def __init__(
141140
memory_retriever: Memory retrieval interface (e.g., naive_mem_cube.text_mem)
142141
config: Configuration for deep search behavior
143142
"""
144-
self.config = config or DeepSearchAgentConfig()
143+
self.config = config or DeepSearchAgentConfig(agent_name="DeepSearchMemAgent")
145144
self.max_iterations = self.config.max_iterations
146145
self.timeout = self.config.timeout
147146
self.llm: BaseLLM = llm
@@ -219,7 +218,7 @@ def run(self, query: str, **kwargs) -> str | list[TextualMemoryItem]:
219218
return self._remove_duplicate_memories(accumulated_memories)
220219
else:
221220
return self._generate_final_answer(
222-
query, accumulated_memories, accumulated_context, "", history
221+
query, accumulated_memories, accumulated_context, history
223222
)
224223

225224
def _remove_duplicate_memories(
@@ -248,9 +247,9 @@ def _generate_final_answer(
248247
original_query: str,
249248
search_results: list[TextualMemoryItem],
250249
context: list[str],
251-
missing_info: str = "",
252250
history: list[str] | None = None,
253251
sources: list[str] | None = None,
252+
missing_info: str | None = None,
254253
) -> str:
255254
"""
256255
Generate the final answer.

src/memos/multi_mem_cube/single_cube.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class SingleCubeView(MemCubeView):
4242
mem_scheduler: Any
4343
logger: Any
4444
searcher: Any
45+
deepsearch_agent: Any
4546

4647
def add_memories(self, add_req: APIADDRequest) -> list[dict[str, Any]]:
4748
"""
@@ -247,8 +248,11 @@ def _fast_search(
247248
def _deep_search(
248249
self, search_req: APISearchRequest, user_context: UserContext, max_thinking_depth: int
249250
) -> list:
250-
logger.error("waiting to be implemented")
251-
return []
251+
deepsearch_results = self.deepsearch_agent.run(
252+
search_req.query, user_id=user_context.mem_cube_id
253+
)
254+
formatted_memories = [format_memory_item(data) for data in deepsearch_results]
255+
return formatted_memories
252256

253257
def _fine_search(
254258
self,

src/memos/templates/mem_agent_prompts.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
{context}
2323
2424
Analyze the context and determine the next step. Return your response in JSON format with the following structure:
25-
{{
25+
```json
26+
{{
2627
"status": "sufficient|missing_info|needs_raw",
2728
"reasoning": "Brief explanation of your decision",
2829
"missing_entities": ["entity1", "entity2"],
2930
"new_search_query": "new search query",
3031
}}
32+
```
3133
3234
Status definitions:
3335
- "sufficient": Context fully answers the query

tests/api/test_server_router.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def mock_init_server():
4848
"pref_mem": None,
4949
"online_bot": None,
5050
"chat_llms": Mock(),
51+
"deepsearch_agent": Mock(),
5152
}
5253

5354
with patch("memos.api.handlers.init_server", return_value=mock_components):

0 commit comments

Comments
 (0)