2121from memos .api .product_models import (
2222 APIADDRequest ,
2323 APIChatCompleteRequest ,
24+ APISearchPlaygroundRequest ,
2425 APISearchRequest ,
26+ ChatPlaygroundRequest ,
2527 ChatRequest ,
2628)
2729from memos .context .context import ContextThread
@@ -91,6 +93,7 @@ def __init__(
9193 self .enable_mem_scheduler = (
9294 hasattr (dependencies , "enable_mem_scheduler" ) and dependencies .enable_mem_scheduler
9395 )
96+ self .dependencies = dependencies
9497
9598 def handle_chat_complete (self , chat_req : APIChatCompleteRequest ) -> dict [str , Any ]:
9699 """
@@ -356,7 +359,7 @@ def generate_chat_response() -> Generator[str, None, None]:
356359 self .logger .error (f"Failed to start chat stream: { traceback .format_exc ()} " )
357360 raise HTTPException (status_code = 500 , detail = str (traceback .format_exc ())) from err
358361
359- def handle_chat_stream_playground (self , chat_req : ChatRequest ) -> StreamingResponse :
362+ def handle_chat_stream_playground (self , chat_req : ChatPlaygroundRequest ) -> StreamingResponse :
360363 """
361364 Chat with MemOS via Server-Sent Events (SSE) stream using search/add handlers.
362365
@@ -413,8 +416,8 @@ def generate_chat_response() -> Generator[str, None, None]:
413416 label = QUERY_TASK_LABEL ,
414417 )
415418
416- # ====== first search without parse goal ======
417- search_req = APISearchRequest (
419+ # ====== first search text mem with parse goal ======
420+ search_req = APISearchPlaygroundRequest (
418421 query = chat_req .query ,
419422 user_id = chat_req .user_id ,
420423 readable_cube_ids = readable_cube_ids ,
@@ -426,6 +429,7 @@ def generate_chat_response() -> Generator[str, None, None]:
426429 include_preference = chat_req .include_preference ,
427430 pref_top_k = chat_req .pref_top_k ,
428431 filter = chat_req .filter ,
432+ playground_search_goal_parser = True ,
429433 )
430434 search_response = self .search_handler .handle_search_memories (search_req )
431435
@@ -439,10 +443,10 @@ def generate_chat_response() -> Generator[str, None, None]:
439443 memories_list = text_mem_results [0 ]["memories" ]
440444
441445 # Filter memories by threshold
442- first_filtered_memories = self ._filter_memories_by_threshold (memories_list )
446+ filtered_memories = self ._filter_memories_by_threshold (memories_list )
443447
444448 # Prepare reference data (first search)
445- reference = prepare_reference_data (first_filtered_memories )
449+ reference = prepare_reference_data (filtered_memories )
446450 # get preference string
447451 pref_string = search_response .data .get ("pref_string" , "" )
448452
@@ -455,48 +459,68 @@ def generate_chat_response() -> Generator[str, None, None]:
455459 pref_md_string = self ._build_pref_md_string_for_playground (pref_memories )
456460 yield f"data: { json .dumps ({'type' : 'pref_md_string' , 'data' : pref_md_string })} \n \n "
457461
458- # internet status
459- yield f"data: { json .dumps ({'type' : 'status' , 'data' : 'start_internet_search' })} \n \n "
460-
461- # ====== second search with parse goal ======
462- search_req = APISearchRequest (
463- query = chat_req .query ,
464- user_id = chat_req .user_id ,
465- readable_cube_ids = readable_cube_ids ,
466- mode = chat_req .mode ,
467- internet_search = chat_req .internet_search ,
468- top_k = chat_req .top_k ,
469- chat_history = chat_req .history ,
470- session_id = chat_req .session_id ,
471- include_preference = False ,
472- filter = chat_req .filter ,
473- playground_search_goal_parser = True ,
462+ # parse goal for internet search
463+ searcher = self .dependencies .searcher
464+ parsed_goal = searcher .task_goal_parser .parse (
465+ task_description = chat_req .query ,
466+ context = "\n " .join (
467+ [memory .get ("memory" , "" ) for memory in filtered_memories ]
468+ ),
469+ conversation = chat_req .history ,
470+ mode = "fine" ,
474471 )
475- search_response = self .search_handler .handle_search_memories (search_req )
476472
477- # Extract memories from search results (second search)
478- memories_list = []
479- if search_response .data and search_response .data .get ("text_mem" ):
480- text_mem_results = search_response .data ["text_mem" ]
481- if text_mem_results and text_mem_results [0 ].get ("memories" ):
482- memories_list = text_mem_results [0 ]["memories" ]
473+ if chat_req .beginner_guide_step == "first" :
474+ chat_req .internet_search = False
475+ parsed_goal .internet_search = False
476+ elif chat_req .beginner_guide_step == "second" :
477+ chat_req .internet_search = True
478+ parsed_goal .internet_search = True
479+
480+ if chat_req .internet_search or parsed_goal .internet_search :
481+ # internet status
482+ yield f"data: { json .dumps ({'type' : 'status' , 'data' : 'start_internet_search' })} \n \n "
483+
484+ # ====== internet search with parse goal ======
485+ search_req = APISearchPlaygroundRequest (
486+ query = chat_req .query
487+ + (f"{ parsed_goal .tags } " if parsed_goal .tags else "" ),
488+ user_id = chat_req .user_id ,
489+ readable_cube_ids = readable_cube_ids ,
490+ mode = chat_req .mode ,
491+ internet_search = True ,
492+ top_k = chat_req .top_k ,
493+ chat_history = chat_req .history ,
494+ session_id = chat_req .session_id ,
495+ include_preference = False ,
496+ filter = chat_req .filter ,
497+ search_memory_type = "OuterMemory" ,
498+ )
499+ search_response = self .search_handler .handle_search_memories (search_req )
483500
484- # Filter memories by threshold
485- second_filtered_memories = self ._filter_memories_by_threshold (memories_list )
501+ # Extract memories from search results (second search)
502+ memories_list = []
503+ if search_response .data and search_response .data .get ("text_mem" ):
504+ text_mem_results = search_response .data ["text_mem" ]
505+ if text_mem_results and text_mem_results [0 ].get ("memories" ):
506+ memories_list = text_mem_results [0 ]["memories" ]
486507
487- # dedup and supplement memories
488- filtered_memories = self ._dedup_and_supplement_memories (
489- first_filtered_memories , second_filtered_memories
490- )
508+ # Filter memories by threshold
509+ second_filtered_memories = self ._filter_memories_by_threshold (memories_list )
491510
492- # Prepare remain reference data (second search)
493- reference = prepare_reference_data (filtered_memories )
494- # get internet reference
495- internet_reference = self ._get_internet_reference (
496- search_response .data .get ("text_mem" )[0 ]["memories" ]
497- )
511+ # dedup and supplement memories
512+ filtered_memories = self ._dedup_and_supplement_memories (
513+ filtered_memories , second_filtered_memories
514+ )
498515
499- yield f"data: { json .dumps ({'type' : 'reference' , 'data' : reference })} \n \n "
516+ # Prepare remain reference data (second search)
517+ reference = prepare_reference_data (filtered_memories )
518+ # get internet reference
519+ internet_reference = self ._get_internet_reference (
520+ search_response .data .get ("text_mem" )[0 ]["memories" ]
521+ )
522+
523+ yield f"data: { json .dumps ({'type' : 'reference' , 'data' : reference })} \n \n "
500524
501525 # Step 2: Build system prompt with memories
502526 system_prompt = self ._build_enhance_system_prompt (
@@ -571,8 +595,9 @@ def generate_chat_response() -> Generator[str, None, None]:
571595 chunk_data = f"data: { json .dumps ({'type' : 'text' , 'data' : processed_chunk }, ensure_ascii = False )} \n \n "
572596 yield chunk_data
573597
574- # Yield internet reference after text response
575- yield f"data: { json .dumps ({'type' : 'internet_reference' , 'data' : internet_reference })} \n \n "
598+ if chat_req .internet_search or parsed_goal .internet_search :
599+ # Yield internet reference after text response
600+ yield f"data: { json .dumps ({'type' : 'internet_reference' , 'data' : internet_reference })} \n \n "
576601
577602 # Calculate timing
578603 time_end = time .time ()
0 commit comments