feat: Allow agent archival tools to insert/search with tags [LET-4072] (#4300)
* Finish modifying archival memory tools * Add tags * Add disabled test
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from typing import Optional
|
||||
from typing import Literal, Optional
|
||||
|
||||
from letta.agent import Agent
|
||||
from letta.constants import CORE_MEMORY_LINE_NUMBER_WARNING
|
||||
@@ -63,70 +63,36 @@ def conversation_search(self: "Agent", query: str, page: Optional[int] = 0) -> O
|
||||
return results_str
|
||||
|
||||
|
||||
async def archival_memory_insert(self: "Agent", content: str) -> Optional[str]:
|
||||
async def archival_memory_insert(self: "Agent", content: str, tags: Optional[list[str]] = None) -> Optional[str]:
|
||||
"""
|
||||
Add to archival memory. Make sure to phrase the memory contents such that it can be easily queried later.
|
||||
|
||||
Args:
|
||||
content (str): Content to write to the memory. All unicode (including emojis) are supported.
|
||||
tags (Optional[list[str]]): Optional list of tags to associate with this memory for better organization and filtering.
|
||||
|
||||
Returns:
|
||||
Optional[str]: None is always returned as this function does not produce a response.
|
||||
"""
|
||||
await self.passage_manager.insert_passage(
|
||||
agent_state=self.agent_state,
|
||||
text=content,
|
||||
actor=self.user,
|
||||
)
|
||||
self.agent_manager.rebuild_system_prompt(agent_id=self.agent_state.id, actor=self.user, force=True)
|
||||
return None
|
||||
raise NotImplementedError("This should never be invoked directly. Contact Letta if you see this error message.")
|
||||
|
||||
|
||||
async def archival_memory_search(self: "Agent", query: str, page: Optional[int] = 0, start: Optional[int] = 0) -> Optional[str]:
|
||||
async def archival_memory_search(
|
||||
self: "Agent", query: str, tags: Optional[list[str]] = None, tag_match_mode: Literal["any", "all"] = "any", top_k: Optional[int] = None
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Search archival memory using semantic (embedding-based) search.
|
||||
|
||||
Args:
|
||||
query (str): String to search for.
|
||||
page (Optional[int]): Allows you to page through results. Only use on a follow-up query. Defaults to 0 (first page).
|
||||
start (Optional[int]): Starting index for the search results. Defaults to 0.
|
||||
query (str): String to search for using semantic similarity.
|
||||
tags (Optional[list[str]]): Optional list of tags to filter search results. Only passages with these tags will be returned.
|
||||
tag_match_mode (Literal["any", "all"]): How to match tags - "any" to match passages with any of the tags, "all" to match only passages with all tags. Defaults to "any".
|
||||
top_k (Optional[int]): Maximum number of results to return. Uses system default if not specified.
|
||||
|
||||
Returns:
|
||||
str: Query result string
|
||||
str: Query result string containing matching passages with timestamps and content.
|
||||
"""
|
||||
|
||||
from letta.constants import RETRIEVAL_QUERY_DEFAULT_PAGE_SIZE
|
||||
|
||||
if page is None or (isinstance(page, str) and page.lower().strip() == "none"):
|
||||
page = 0
|
||||
try:
|
||||
page = int(page)
|
||||
except:
|
||||
raise ValueError("'page' argument must be an integer")
|
||||
count = RETRIEVAL_QUERY_DEFAULT_PAGE_SIZE
|
||||
|
||||
try:
|
||||
# Get results using passage manager
|
||||
all_results = await self.agent_manager.query_agent_passages_async(
|
||||
actor=self.user,
|
||||
agent_id=self.agent_state.id,
|
||||
query_text=query,
|
||||
limit=count + start, # Request enough results to handle offset
|
||||
embedding_config=self.agent_state.embedding_config,
|
||||
embed_query=True,
|
||||
)
|
||||
|
||||
# Apply pagination
|
||||
end = min(count + start, len(all_results))
|
||||
paged_results = all_results[start:end]
|
||||
|
||||
# Format results to match previous implementation
|
||||
formatted_results = [{"timestamp": str(result.created_at), "content": result.text} for result in paged_results]
|
||||
|
||||
return formatted_results, len(formatted_results)
|
||||
|
||||
except Exception as e:
|
||||
raise e
|
||||
raise NotImplementedError("This should never be invoked directly. Contact Letta if you see this error message.")
|
||||
|
||||
|
||||
def core_memory_append(agent_state: "AgentState", label: str, content: str) -> Optional[str]: # type: ignore
|
||||
|
||||
Reference in New Issue
Block a user