77from agent_memory_server .auth import UserInfo , get_current_user
88from agent_memory_server .config import settings
99from agent_memory_server .dependencies import get_background_tasks
10+ from agent_memory_server .filters import SessionId , UserId
1011from agent_memory_server .llms import get_model_client , get_model_config
1112from agent_memory_server .logging import get_logger
1213from agent_memory_server .models import (
@@ -234,7 +235,6 @@ async def get_working_memory(
234235 """
235236 redis = await get_redis_conn ()
236237
237- # Get unified working memory
238238 working_mem = await working_memory .get_working_memory (
239239 session_id = session_id ,
240240 namespace = namespace ,
@@ -243,7 +243,7 @@ async def get_working_memory(
243243 )
244244
245245 if not working_mem :
246- # Return empty working memory if none exists
246+ # Create empty working memory if none exists
247247 working_mem = WorkingMemory (
248248 messages = [],
249249 memories = [],
@@ -267,6 +267,8 @@ async def get_working_memory(
267267 break
268268 working_mem .messages = truncated_messages
269269
270+ logger .debug (f"Working mem: { working_mem } " )
271+
270272 return working_mem
271273
272274
@@ -314,6 +316,14 @@ async def put_working_memory(
314316 detail = "All memory records in working memory must have an ID" ,
315317 )
316318
319+ # Validate that all messages have non-empty content
320+ for msg in memory .messages :
321+ if not msg .content or not msg .content .strip ():
322+ raise HTTPException (
323+ status_code = 400 ,
324+ detail = f"Message content cannot be empty (message ID: { msg .id } )" ,
325+ )
326+
317327 # Handle summarization if needed (before storing) - now token-based
318328 updated_memory = memory
319329 if memory .messages :
@@ -333,8 +343,9 @@ async def put_working_memory(
333343 # Promote structured memories from working memory to long-term storage
334344 await background_tasks .add_task (
335345 long_term_memory .promote_working_memory_to_long_term ,
336- session_id ,
337- updated_memory .namespace ,
346+ session_id = session_id ,
347+ user_id = updated_memory .user_id ,
348+ namespace = updated_memory .namespace ,
338349 )
339350
340351 return updated_memory
@@ -431,7 +442,7 @@ async def search_long_term_memory(
431442 # Extract filter objects from the payload
432443 filters = payload .get_filters ()
433444
434- print ( "Long-term search filters: " , filters )
445+ logger . debug ( f "Long-term search filters: { filters } " )
435446
436447 kwargs = {
437448 "distance_threshold" : payload .distance_threshold ,
@@ -440,10 +451,10 @@ async def search_long_term_memory(
440451 ** filters ,
441452 }
442453
443- print ("Kwargs: " , kwargs )
444-
445454 kwargs ["text" ] = payload .text or ""
446455
456+ logger .debug (f"Long-term search kwargs: { kwargs } " )
457+
447458 # Pass text and filter objects to the search function (no redis needed for vectorstore adapter)
448459 return await long_term_memory .search_long_term_memories (** kwargs )
449460
@@ -466,53 +477,6 @@ async def delete_long_term_memory(
466477 return AckResponse (status = f"ok, deleted { count } memories" )
467478
468479
469- @router .post ("/v1/memory/search" , response_model = MemoryRecordResultsResponse )
470- async def search_memory (
471- payload : SearchRequest ,
472- current_user : UserInfo = Depends (get_current_user ),
473- ):
474- """
475- Run a search across all memory types (working memory and long-term memory).
476-
477- This endpoint searches both working memory (ephemeral, session-scoped) and
478- long-term memory (persistent, indexed) to provide comprehensive results.
479-
480- For working memory:
481- - Uses simple text matching
482- - Searches across all sessions (unless session_id filter is provided)
483- - Returns memories that haven't been promoted to long-term storage
484-
485- For long-term memory:
486- - Uses semantic vector search
487- - Includes promoted memories from working memory
488- - Supports advanced filtering by topics, entities, etc.
489-
490- Args:
491- payload: Search payload with filter objects for precise queries
492-
493- Returns:
494- Search results from both memory types, sorted by relevance
495- """
496- redis = await get_redis_conn ()
497-
498- # Extract filter objects from the payload
499- filters = payload .get_filters ()
500-
501- kwargs = {
502- "redis" : redis ,
503- "distance_threshold" : payload .distance_threshold ,
504- "limit" : payload .limit ,
505- "offset" : payload .offset ,
506- ** filters ,
507- }
508-
509- if payload .text :
510- kwargs ["text" ] = payload .text
511-
512- # Use the search function
513- return await long_term_memory .search_memories (** kwargs )
514-
515-
516480@router .post ("/v1/memory/prompt" , response_model = MemoryPromptResponse )
517481async def memory_prompt (
518482 params : MemoryPromptRequest ,
@@ -546,7 +510,7 @@ async def memory_prompt(
546510 redis = await get_redis_conn ()
547511 _messages = []
548512
549- print ( "Received params: " , params )
513+ logger . debug ( f"Memory prompt params: { params } " )
550514
551515 if params .session :
552516 # Use token limit for memory prompt, fallback to message count for backward compatibility
@@ -569,6 +533,8 @@ async def memory_prompt(
569533 redis_client = redis ,
570534 )
571535
536+ logger .debug (f"Found working memory: { working_mem } " )
537+
572538 if working_mem :
573539 if working_mem .context :
574540 # TODO: Weird to use MCP types here?
@@ -580,7 +546,7 @@ async def memory_prompt(
580546 ),
581547 )
582548 )
583- # Apply token-based or message-based truncation
549+ # Apply token-based truncation if model info is provided
584550 if params .session .model_name or params .session .context_window_max :
585551 # Token-based truncation
586552 if (
@@ -598,39 +564,55 @@ async def memory_prompt(
598564 break
599565 else :
600566 recent_messages = working_mem .messages
567+
568+ for msg in recent_messages :
569+ if msg .role == "user" :
570+ msg_class = base .UserMessage
571+ else :
572+ msg_class = base .AssistantMessage
573+ _messages .append (
574+ msg_class (
575+ content = TextContent (type = "text" , text = msg .content ),
576+ )
577+ )
601578 else :
602- # Message-based truncation (backward compatibility)
603- recent_messages = (
604- working_mem .messages [- effective_window_size :]
605- if len (working_mem .messages ) > effective_window_size
606- else working_mem .messages
607- )
608- for msg in recent_messages :
609- if msg .role == "user" :
610- msg_class = base .UserMessage
611- else :
612- msg_class = base .AssistantMessage
613- _messages .append (
614- msg_class (
615- content = TextContent (type = "text" , text = msg .content ),
579+ # No token-based truncation - use all messages
580+ for msg in working_mem .messages :
581+ if msg .role == "user" :
582+ msg_class = base .UserMessage
583+ else :
584+ msg_class = base .AssistantMessage
585+ _messages .append (
586+ msg_class (
587+ content = TextContent (type = "text" , text = msg .content ),
588+ )
616589 )
617- )
618590
619591 if params .long_term_search :
620- # TODO: Exclude session messages if we already included them from session memory
621-
622- # If no text is provided in long_term_search, use the user's query
623- if not params .long_term_search .text :
624- # Create a new SearchRequest with the query as text
625- search_payload = params .long_term_search .model_copy ()
626- search_payload .text = params .query
592+ logger .debug (
593+ f"[memory_prompt] Long-term search args: { params .long_term_search } "
594+ )
595+ if isinstance (params .long_term_search , bool ):
596+ search_kwargs = {}
597+ if params .session :
598+ # Exclude memories from the current session because we already included them
599+ search_kwargs ["session_id" ] = SessionId (ne = params .session .session_id )
600+ if params .session and params .session .user_id :
601+ search_kwargs ["user_id" ] = UserId (eq = params .session .user_id )
602+ search_payload = SearchRequest (** search_kwargs , limit = 20 , offset = 0 )
627603 else :
628- search_payload = params .long_term_search
604+ search_payload = params .long_term_search .model_copy ()
605+ # Merge session user_id into the search request if not already specified
606+ if params .session and params .session .user_id and not search_payload .user_id :
607+ search_payload .user_id = UserId (eq = params .session .user_id )
629608
609+ logger .debug (f"[memory_prompt] Search payload: { search_payload } " )
630610 long_term_memories = await search_long_term_memory (
631611 search_payload ,
632612 )
633613
614+ logger .debug (f"[memory_prompt] Long-term memories: { long_term_memories } " )
615+
634616 if long_term_memories .total > 0 :
635617 long_term_memories_text = "\n " .join (
636618 [f"- { m .text } " for m in long_term_memories .memories ]
0 commit comments