|
34 | 34 | HealthCheckResponse, |
35 | 35 | MemoryRecord, |
36 | 36 | MemoryRecordResults, |
| 37 | + MemoryTypeEnum, |
37 | 38 | ModelNameLiteral, |
38 | 39 | SessionListResponse, |
39 | 40 | WorkingMemory, |
@@ -442,7 +443,7 @@ async def add_memories_to_working_memory( |
442 | 443 | # Auto-generate IDs for memories that don't have them |
443 | 444 | for memory in final_memories: |
444 | 445 | if not memory.id: |
445 | | - memory.id = str(ulid.new()) |
| 446 | + memory.id = str(ulid.ULID()) |
446 | 447 |
|
447 | 448 | # Create new working memory with the memories |
448 | 449 | working_memory = WorkingMemory( |
@@ -617,136 +618,10 @@ async def search_long_term_memory( |
617 | 618 | exclude_none=True, mode="json" |
618 | 619 | ) |
619 | 620 | if user_id: |
620 | | - payload["user_id"] = user_id.model_dump(exclude_none=True) |
621 | | - if memory_type: |
622 | | - payload["memory_type"] = memory_type.model_dump(exclude_none=True) |
623 | | - if distance_threshold is not None: |
624 | | - payload["distance_threshold"] = distance_threshold |
625 | | - |
626 | | - try: |
627 | | - response = await self._client.post( |
628 | | - "/v1/long-term-memory/search", |
629 | | - json=payload, |
630 | | - ) |
631 | | - response.raise_for_status() |
632 | | - return MemoryRecordResults(**response.json()) |
633 | | - except httpx.HTTPStatusError as e: |
634 | | - self._handle_http_error(e.response) |
635 | | - raise |
636 | | - |
637 | | - async def search_memories( |
638 | | - self, |
639 | | - text: str, |
640 | | - session_id: SessionId | dict[str, Any] | None = None, |
641 | | - namespace: Namespace | dict[str, Any] | None = None, |
642 | | - topics: Topics | dict[str, Any] | None = None, |
643 | | - entities: Entities | dict[str, Any] | None = None, |
644 | | - created_at: CreatedAt | dict[str, Any] | None = None, |
645 | | - last_accessed: LastAccessed | dict[str, Any] | None = None, |
646 | | - user_id: UserId | dict[str, Any] | None = None, |
647 | | - distance_threshold: float | None = None, |
648 | | - memory_type: MemoryType | dict[str, Any] | None = None, |
649 | | - limit: int = 10, |
650 | | - offset: int = 0, |
651 | | - ) -> MemoryRecordResults: |
652 | | - """ |
653 | | - Search across all memory types (working memory and long-term memory). |
654 | | -
|
655 | | - This method searches both working memory (ephemeral, session-scoped) and |
656 | | - long-term memory (persistent, indexed) to provide comprehensive results. |
657 | | -
|
658 | | - For working memory: |
659 | | - - Uses simple text matching |
660 | | - - Searches across all sessions (unless session_id filter is provided) |
661 | | - - Returns memories that haven't been promoted to long-term storage |
662 | | -
|
663 | | - For long-term memory: |
664 | | - - Uses semantic vector search |
665 | | - - Includes promoted memories from working memory |
666 | | - - Supports advanced filtering by topics, entities, etc. |
667 | | -
|
668 | | - Args: |
669 | | - text: Search query text for semantic similarity |
670 | | - session_id: Optional session ID filter |
671 | | - namespace: Optional namespace filter |
672 | | - topics: Optional topics filter |
673 | | - entities: Optional entities filter |
674 | | - created_at: Optional creation date filter |
675 | | - last_accessed: Optional last accessed date filter |
676 | | - user_id: Optional user ID filter |
677 | | - distance_threshold: Optional distance threshold for search results |
678 | | - memory_type: Optional memory type filter |
679 | | - limit: Maximum number of results to return (default: 10) |
680 | | - offset: Offset for pagination (default: 0) |
681 | | -
|
682 | | - Returns: |
683 | | - MemoryRecordResults with matching memories from both memory types |
684 | | -
|
685 | | - Raises: |
686 | | - MemoryServerError: If the request fails |
687 | | -
|
688 | | - Example: |
689 | | - ```python |
690 | | - # Search for user preferences with topic filtering |
691 | | - from .filters import Topics |
692 | | -
|
693 | | - results = await client.search_memories( |
694 | | - text="user prefers dark mode", |
695 | | - topics=Topics(any=["preferences", "ui"]), |
696 | | - limit=5 |
697 | | - ) |
698 | | -
|
699 | | - for memory in results.memories: |
700 | | - print(f"Found: {memory.text}") |
701 | | - ``` |
702 | | - """ |
703 | | - # Convert dictionary filters to their proper filter objects if needed |
704 | | - if isinstance(session_id, dict): |
705 | | - session_id = SessionId(**session_id) |
706 | | - if isinstance(namespace, dict): |
707 | | - namespace = Namespace(**namespace) |
708 | | - if isinstance(topics, dict): |
709 | | - topics = Topics(**topics) |
710 | | - if isinstance(entities, dict): |
711 | | - entities = Entities(**entities) |
712 | | - if isinstance(created_at, dict): |
713 | | - created_at = CreatedAt(**created_at) |
714 | | - if isinstance(last_accessed, dict): |
715 | | - last_accessed = LastAccessed(**last_accessed) |
716 | | - if isinstance(user_id, dict): |
717 | | - user_id = UserId(**user_id) |
718 | | - if isinstance(memory_type, dict): |
719 | | - memory_type = MemoryType(**memory_type) |
720 | | - |
721 | | - # Apply default namespace if needed and no namespace filter specified |
722 | | - if namespace is None and self.config.default_namespace is not None: |
723 | | - namespace = Namespace(eq=self.config.default_namespace) |
724 | | - |
725 | | - payload = { |
726 | | - "text": text, |
727 | | - "limit": limit, |
728 | | - "offset": offset, |
729 | | - } |
730 | | - |
731 | | - # Add filters if provided |
732 | | - if session_id: |
733 | | - payload["session_id"] = session_id.model_dump(exclude_none=True) |
734 | | - if namespace: |
735 | | - payload["namespace"] = namespace.model_dump(exclude_none=True) |
736 | | - if topics: |
737 | | - payload["topics"] = topics.model_dump(exclude_none=True) |
738 | | - if entities: |
739 | | - payload["entities"] = entities.model_dump(exclude_none=True) |
740 | | - if created_at: |
741 | | - payload["created_at"] = created_at.model_dump( |
742 | | - exclude_none=True, mode="json" |
743 | | - ) |
744 | | - if last_accessed: |
745 | | - payload["last_accessed"] = last_accessed.model_dump( |
746 | | - exclude_none=True, mode="json" |
747 | | - ) |
748 | | - if user_id: |
749 | | - payload["user_id"] = user_id.model_dump(exclude_none=True) |
| 621 | + if isinstance(user_id, dict): |
| 622 | + payload["user_id"] = user_id |
| 623 | + else: |
| 624 | + payload["user_id"] = user_id.model_dump(exclude_none=True) |
750 | 625 | if memory_type: |
751 | 626 | payload["memory_type"] = memory_type.model_dump(exclude_none=True) |
752 | 627 | if distance_threshold is not None: |
@@ -1076,7 +951,7 @@ async def add_memory_tool( |
1076 | 951 | # Create memory record |
1077 | 952 | memory = ClientMemoryRecord( |
1078 | 953 | text=text, |
1079 | | - memory_type=memory_type, |
| 954 | + memory_type=MemoryTypeEnum(memory_type), |
1080 | 955 | topics=topics, |
1081 | 956 | entities=entities, |
1082 | 957 | namespace=namespace or self.config.default_namespace, |
@@ -1111,7 +986,7 @@ async def update_memory_data_tool( |
1111 | 986 | self, |
1112 | 987 | session_id: str, |
1113 | 988 | data: dict[str, Any], |
1114 | | - merge_strategy: str = "merge", |
| 989 | + merge_strategy: Literal["replace", "merge", "deep_merge"] = "merge", |
1115 | 990 | namespace: str | None = None, |
1116 | 991 | user_id: str | None = None, |
1117 | 992 | ) -> dict[str, Any]: |
@@ -1997,70 +1872,6 @@ async def search_all_long_term_memories( |
1997 | 1872 |
|
1998 | 1873 | offset += batch_size |
1999 | 1874 |
|
2000 | | - async def search_all_memories( |
2001 | | - self, |
2002 | | - text: str, |
2003 | | - session_id: SessionId | dict[str, Any] | None = None, |
2004 | | - namespace: Namespace | dict[str, Any] | None = None, |
2005 | | - topics: Topics | dict[str, Any] | None = None, |
2006 | | - entities: Entities | dict[str, Any] | None = None, |
2007 | | - created_at: CreatedAt | dict[str, Any] | None = None, |
2008 | | - last_accessed: LastAccessed | dict[str, Any] | None = None, |
2009 | | - user_id: UserId | dict[str, Any] | None = None, |
2010 | | - distance_threshold: float | None = None, |
2011 | | - memory_type: MemoryType | dict[str, Any] | None = None, |
2012 | | - batch_size: int = 50, |
2013 | | - ) -> AsyncIterator[MemoryRecord]: |
2014 | | - """ |
2015 | | - Auto-paginating version of unified memory search. |
2016 | | -
|
2017 | | - Searches both working memory and long-term memory with automatic pagination. |
2018 | | -
|
2019 | | - Args: |
2020 | | - text: Search query text |
2021 | | - session_id: Optional session ID filter |
2022 | | - namespace: Optional namespace filter |
2023 | | - topics: Optional topics filter |
2024 | | - entities: Optional entities filter |
2025 | | - created_at: Optional creation date filter |
2026 | | - last_accessed: Optional last accessed date filter |
2027 | | - user_id: Optional user ID filter |
2028 | | - distance_threshold: Optional distance threshold |
2029 | | - memory_type: Optional memory type filter |
2030 | | - batch_size: Number of results to fetch per API call |
2031 | | -
|
2032 | | - Yields: |
2033 | | - Individual memory records from all result pages |
2034 | | - """ |
2035 | | - offset = 0 |
2036 | | - while True: |
2037 | | - results = await self.search_memories( |
2038 | | - text=text, |
2039 | | - session_id=session_id, |
2040 | | - namespace=namespace, |
2041 | | - topics=topics, |
2042 | | - entities=entities, |
2043 | | - created_at=created_at, |
2044 | | - last_accessed=last_accessed, |
2045 | | - user_id=user_id, |
2046 | | - distance_threshold=distance_threshold, |
2047 | | - memory_type=memory_type, |
2048 | | - limit=batch_size, |
2049 | | - offset=offset, |
2050 | | - ) |
2051 | | - |
2052 | | - if not results.memories: |
2053 | | - break |
2054 | | - |
2055 | | - for memory in results.memories: |
2056 | | - yield memory |
2057 | | - |
2058 | | - # If we got fewer results than batch_size, we've reached the end |
2059 | | - if len(results.memories) < batch_size: |
2060 | | - break |
2061 | | - |
2062 | | - offset += batch_size |
2063 | | - |
2064 | 1875 | def validate_memory_record(self, memory: ClientMemoryRecord | MemoryRecord) -> None: |
2065 | 1876 | """ |
2066 | 1877 | Validate memory record before sending to server. |
@@ -2237,7 +2048,7 @@ async def append_messages_to_working_memory( |
2237 | 2048 | converted_existing_messages.append(msg) |
2238 | 2049 | else: |
2239 | 2050 | # Fallback for any other message type - convert to string content |
2240 | | - converted_existing_messages.append( |
| 2051 | + converted_existing_messages.append( # type: ignore |
2241 | 2052 | {"role": "user", "content": str(msg)} |
2242 | 2053 | ) |
2243 | 2054 |
|
|
0 commit comments