Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py1315 linesDownload Raw Back to base
1"""Base classes and types for persistent key-value stores.2 3Stores provide long-term memory that persists across threads and conversations.4Supports hierarchical namespaces, key-value storage, and optional vector search.5 6Core types:7    - `BaseStore`: Store interface with sync/async operations8    - `Item`: Stored key-value pairs with metadata9    - `Op`: Get/Put/Search/List operations10"""11 12from __future__ import annotations13 14from abc import ABC, abstractmethod15from collections.abc import Iterable16from datetime import datetime17from typing import (18    Any,19    Literal,20    NamedTuple,21    TypedDict,22    cast,23)24 25from langchain_core.embeddings import Embeddings26from typing_extensions import override27 28from langgraph.store.base.embed import (29    AEmbeddingsFunc,30    EmbeddingsFunc,31    ensure_embeddings,32    get_text_at_path,33    tokenize_path,34)35 36 37class NotProvided:38    """Sentinel singleton."""39 40    def __bool__(self) -> Literal[False]:41        return False42 43    @override44    def __repr__(self) -> str:45        return "NOT_GIVEN"46 47 48NOT_PROVIDED = NotProvided()49 50 51class Item:52    """Represents a stored item with metadata.53 54    Args:55        value: The stored data as a dictionary. Keys are filterable.56        key: Unique identifier within the namespace.57        namespace: Hierarchical path defining the collection in which this document resides.58            Represented as a tuple of strings, allowing for nested categorization.59            For example: `("documents", 'user123')`60        created_at: Timestamp of item creation.61        updated_at: Timestamp of last update.62    """63 64    __slots__ = ("value", "key", "namespace", "created_at", "updated_at")65 66    def __init__(67        self,68        *,69        value: dict[str, Any],70        key: str,71        namespace: tuple[str, ...],72        created_at: datetime,73        updated_at: datetime,74    ):75        self.value = value76        self.key = key77        # The casting from json-like types is for if this object is78        # deserialized.79        self.namespace = tuple(namespace)80        self.created_at = (81            datetime.fromisoformat(cast(str, created_at))82            if isinstance(created_at, str)83            else created_at84        )85        self.updated_at = (86            datetime.fromisoformat(cast(str, updated_at))87            if isinstance(updated_at, str)88            else updated_at89        )90 91    def __eq__(self, other: object) -> bool:92        if not isinstance(other, Item):93            return False94        return (95            self.value == other.value96            and self.key == other.key97            and self.namespace == other.namespace98            and self.created_at == other.created_at99            and self.updated_at == other.updated_at100        )101 102    def __hash__(self) -> int:103        return hash((self.namespace, self.key))104 105    def dict(self) -> dict:106        return {107            "namespace": list(self.namespace),108            "key": self.key,109            "value": self.value,110            "created_at": self.created_at.isoformat(),111            "updated_at": self.updated_at.isoformat(),112        }113 114    def __repr__(self) -> str:115        return f"Item({', '.join(f'{k}={v!r}' for k, v in self.dict().items())})"116 117 118class SearchItem(Item):119    """Represents an item returned from a search operation with additional metadata."""120 121    __slots__ = ("score",)122 123    def __init__(124        self,125        namespace: tuple[str, ...],126        key: str,127        value: dict[str, Any],128        created_at: datetime,129        updated_at: datetime,130        score: float | None = None,131    ) -> None:132        """Initialize a result item.133 134        Args:135            namespace: Hierarchical path to the item.136            key: Unique identifier within the namespace.137            value: The stored value.138            created_at: When the item was first created.139            updated_at: When the item was last updated.140            score: Relevance/similarity score if from a ranked operation.141        """142        super().__init__(143            value=value,144            key=key,145            namespace=namespace,146            created_at=created_at,147            updated_at=updated_at,148        )149        self.score = score150 151    def dict(self) -> dict:152        result = super().dict()153        result["score"] = self.score154        return result155 156 157class GetOp(NamedTuple):158    """Operation to retrieve a specific item by its namespace and key.159 160    This operation allows precise retrieval of stored items using their full path161    (namespace) and unique identifier (key) combination.162 163    ???+ example "Examples"164 165        Basic item retrieval:166 167        ```python168        GetOp(namespace=("users", "profiles"), key="user123")169        GetOp(namespace=("cache", "embeddings"), key="doc456")170        ```171    """172 173    namespace: tuple[str, ...]174    """Hierarchical path that uniquely identifies the item's location.175 176    ???+ example "Examples"177 178        ```python179        ("users",)  # Root level users namespace180        ("users", "profiles")  # Profiles within users namespace181        ```182    """183 184    key: str185    """Unique identifier for the item within its specific namespace.186 187    ???+ example "Examples"188 189        ```python190        "user123"  # For a user profile191        "doc456"  # For a document192        ```193    """194    refresh_ttl: bool = True195    """Whether to refresh TTLs for the returned item.196 197    If no TTL was specified for the original item(s),198    or if TTL support is not enabled for your adapter,199    this argument is ignored.200    """201 202 203class SearchOp(NamedTuple):204    """Operation to search for items within a specified namespace hierarchy.205 206    This operation supports both structured filtering and natural language search207    within a given namespace prefix. It provides pagination through limit and offset208    parameters.209 210    !!! note211 212        Natural language search support depends on your store implementation.213 214    ???+ example "Examples"215 216        Search with filters and pagination:217 218        ```python219        SearchOp(220            namespace_prefix=("documents",),221            filter={"type": "report", "status": "active"},222            limit=5,223            offset=10224        )225        ```226 227        Natural language search:228 229        ```python230        SearchOp(231            namespace_prefix=("users", "content"),232            query="technical documentation about APIs",233            limit=20234        )235        ```236    """237 238    namespace_prefix: tuple[str, ...]239    """Hierarchical path prefix defining the search scope.240 241    ???+ example "Examples"242 243        ```python244        ()  # Search entire store245        ("documents",)  # Search all documents246        ("users", "content")  # Search within user content247        ```248    """249 250    filter: dict[str, Any] | None = None251    """Key-value pairs for filtering results based on exact matches or comparison operators.252 253    The filter supports both exact matches and operator-based comparisons.254 255    Supported Operators:256        - `$eq`: Equal to (same as direct value comparison)257        - `$ne`: Not equal to258        - `$gt`: Greater than259        - `$gte`: Greater than or equal to260        - `$lt`: Less than261        - `$lte`: Less than or equal to262 263    ???+ example "Examples"264 265        Simple exact match:266 267        ```python268        {"status": "active"}269        ```270 271        Comparison operators:272 273        ```python274        {"score": {"$gt": 4.99}}  # Score greater than 4.99275        ```276 277        Multiple conditions:278 279        ```python280        {281            "score": {"$gte": 3.0},282            "color": "red"283        }284        ```285    """286 287    limit: int = 10288    """Maximum number of items to return in the search results."""289 290    offset: int = 0291    """Number of matching items to skip for pagination."""292 293    query: str | None = None294    """Natural language search query for semantic search capabilities.295 296    ???+ example "Examples"297 298        - "technical documentation about REST APIs"299        - "machine learning papers from 2023"300    """301    refresh_ttl: bool = True302    """Whether to refresh TTLs for the returned item.303 304    If no TTL was specified for the original item(s),305    or if TTL support is not enabled for your adapter,306    this argument is ignored.307    """308 309 310# Type representing a namespace path that can include wildcards311NamespacePath = tuple[str | Literal["*"], ...]312"""A tuple representing a namespace path that can include wildcards.313 314???+ example "Examples"315 316    ```python317    ("users",)  # Exact users namespace318    ("documents", "*")  # Any sub-namespace under documents319    ("cache", "*", "v1")  # Any cache category with v1 version320    ```321"""322 323# Type for specifying how to match namespaces324NamespaceMatchType = Literal["prefix", "suffix"]325"""Specifies how to match namespace paths.326 327Values:328    "prefix": Match from the start of the namespace329    "suffix": Match from the end of the namespace330"""331 332 333class MatchCondition(NamedTuple):334    """Represents a pattern for matching namespaces in the store.335 336    This class combines a match type (prefix or suffix) with a namespace path337    pattern that can include wildcards to flexibly match different namespace338    hierarchies.339 340    ???+ example "Examples"341 342        Prefix matching:343 344        ```python345        MatchCondition(match_type="prefix", path=("users", "profiles"))346        ```347 348        Suffix matching with wildcard:349 350        ```python351        MatchCondition(match_type="suffix", path=("cache", "*"))352        ```353 354        Simple suffix matching:355 356        ```python357        MatchCondition(match_type="suffix", path=("v1",))358        ```359    """360 361    match_type: NamespaceMatchType362    """Type of namespace matching to perform."""363 364    path: NamespacePath365    """Namespace path pattern that can include wildcards."""366 367 368class ListNamespacesOp(NamedTuple):369    """Operation to list and filter namespaces in the store.370 371    This operation allows exploring the organization of data, finding specific372    collections, and navigating the namespace hierarchy.373 374    ???+ example "Examples"375 376        List all namespaces under the `"documents"` path:377 378        ```python379        ListNamespacesOp(380            match_conditions=(MatchCondition(match_type="prefix", path=("documents",)),),381            max_depth=2382        )383        ```384 385        List all namespaces that end with `"v1"`:386 387        ```python388        ListNamespacesOp(389            match_conditions=(MatchCondition(match_type="suffix", path=("v1",)),),390            limit=50391        )392        ```393 394    """395 396    match_conditions: tuple[MatchCondition, ...] | None = None397    """Optional conditions for filtering namespaces.398 399    ???+ example "Examples"400 401        All user namespaces:402 403        ```python404        (MatchCondition(match_type="prefix", path=("users",)),)405        ```406 407        All namespaces that start with `"docs"` and end with `"draft"`:408 409        ```python410        (411            MatchCondition(match_type="prefix", path=("docs",)),412            MatchCondition(match_type="suffix", path=("draft",))413        ) 414        ```415    """416 417    max_depth: int | None = None418    """Maximum depth of namespace hierarchy to return.419 420    Note:421        Namespaces deeper than this level will be truncated.422    """423 424    limit: int = 100425    """Maximum number of namespaces to return."""426 427    offset: int = 0428    """Number of namespaces to skip for pagination."""429 430 431class PutOp(NamedTuple):432    """Operation to store, update, or delete an item in the store.433 434    This class represents a single operation to modify the store's contents,435    whether adding new items, updating existing ones, or removing them.436    """437 438    namespace: tuple[str, ...]439    """Hierarchical path that identifies the location of the item.440 441    The namespace acts as a folder-like structure to organize items.442    Each element in the tuple represents one level in the hierarchy.443 444    ???+ example "Examples"445 446        Root level documents:447 448        ```python449        ("documents",)450        ```451        452        User-specific documents:453 454        ```python455        ("documents", "user123")456        ```457        458        Nested cache structure:459 460        ```python461        ("cache", "embeddings", "v1")462        ```463    """464 465    key: str466    """Unique identifier for the item within its namespace.467 468    The key must be unique within the specific namespace to avoid conflicts.469    Together with the namespace, it forms a complete path to the item.470 471    Example:472        If namespace is `("documents", "user123")` and key is `"report1"`,473        the full path would effectively be `"documents/user123/report1"`474    """475 476    value: dict[str, Any] | None477    """The data to store, or `None` to mark the item for deletion.478 479    The value must be a dictionary with string keys and JSON-serializable values.480    Setting this to `None` signals that the item should be deleted.481 482    Example:483        {484            "field1": "string value",485            "field2": 123,486            "nested": {"can": "contain", "any": "serializable data"}487        }488    """489 490    index: Literal[False] | list[str] | None = None  # type: ignore[assignment]491    """Controls how the item's fields are indexed for search operations.492 493    Indexing configuration determines how the item can be found through search:494        - `None` (default): Uses the store's default indexing configuration (if provided)495        - `False`: Disables indexing for this item496        - `list[str]`: Specifies which json path fields to index for search497 498    The item remains accessible through direct get() operations regardless of indexing.499    When indexed, fields can be searched using natural language queries through500    vector similarity search (if supported by the store implementation).501 502    Path Syntax:503        - Simple field access: `"field"`504        - Nested fields: `"parent.child.grandchild"`505        - Array indexing:506            - Specific index: `"array[0]"`507            - Last element: `"array[-1]"`508            - All elements (each individually): `"array[*]"`509 510    ???+ example "Examples"511 512        - `None` - Use store defaults (whole item)513        - `list[str]` - List of fields to index514        515        ```python516        [517            "metadata.title",                    # Nested field access518            "context[*].content",                # Index content from all context as separate vectors519            "authors[0].name",                   # First author's name520            "revisions[-1].changes",             # Most recent revision's changes521            "sections[*].paragraphs[*].text",    # All text from all paragraphs in all sections522            "metadata.tags[*]",                  # All tags in metadata523        ]524        ```525    """526    ttl: float | None = None527    """Controls the TTL (time-to-live) for the item in minutes.528 529    If provided, and if the store you are using supports this feature, the item530    will expire this many minutes after it was last accessed. The expiration timer531    refreshes on both read operations (get/search) and write operations (put/update).532    When the TTL expires, the item will be scheduled for deletion on a best-effort basis.533    Defaults to `None` (no expiration).534    """535 536 537Op = GetOp | SearchOp | PutOp | ListNamespacesOp538Result = Item | list[Item] | list[SearchItem] | list[tuple[str, ...]] | None539 540 541class InvalidNamespaceError(ValueError):542    """Provided namespace is invalid."""543 544 545class TTLConfig(TypedDict, total=False):546    """Configuration for TTL (time-to-live) behavior in the store."""547 548    refresh_on_read: bool549    """Default behavior for refreshing TTLs on read operations (`GET` and `SEARCH`).550    551    If `True`, TTLs will be refreshed on read operations (get/search) by default.552    This can be overridden per-operation by explicitly setting `refresh_ttl`.553    Defaults to `True` if not configured.554    """555    default_ttl: float | None556    """Default TTL (time-to-live) in minutes for new items.557    558    If provided, new items will expire after this many minutes after their last access.559    The expiration timer refreshes on both read and write operations.560    Defaults to `None` (no expiration).561    """562    sweep_interval_minutes: int | None563    """Interval in minutes between TTL sweep operations.564    565    If provided, the store will periodically delete expired items based on TTL.566    Defaults to None (no sweeping).567    """568 569 570class IndexConfig(TypedDict, total=False):571    """Configuration for indexing documents for semantic search in the store.572 573    If not provided to the store, the store will not support vector search.574    In that case, all `index` arguments to `put()` and `aput()` operations will be ignored.575    """576 577    dims: int578    """Number of dimensions in the embedding vectors.579    580    Common embedding models have the following dimensions:581        - `openai:text-embedding-3-large`: `3072`582        - `openai:text-embedding-3-small`: `1536`583        - `openai:text-embedding-ada-002`: `1536`584        - `cohere:embed-english-v3.0`: `1024`585        - `cohere:embed-english-light-v3.0`: `384`586        - `cohere:embed-multilingual-v3.0`: `1024`587        - `cohere:embed-multilingual-light-v3.0`: `384`588    """589 590    embed: Embeddings | EmbeddingsFunc | AEmbeddingsFunc | str591    """Optional function to generate embeddings from text.592    593    Can be specified in three ways:594        1. A LangChain `Embeddings` instance595        2. A synchronous embedding function (`EmbeddingsFunc`)596        3. An asynchronous embedding function (`AEmbeddingsFunc`)597        4. A provider string (e.g., `"openai:text-embedding-3-small"`)598    599    ???+ example "Examples"600 601        Using LangChain's initialization with `InMemoryStore`:602 603        ```python604        from langchain.embeddings import init_embeddings605        from langgraph.store.memory import InMemoryStore606        607        store = InMemoryStore(608            index={609                "dims": 1536,610                "embed": init_embeddings("openai:text-embedding-3-small")611            }612        )613        ```614        615        Using a custom embedding function with `InMemoryStore`:616 617        ```python618        from openai import OpenAI619        from langgraph.store.memory import InMemoryStore620        621        client = OpenAI()622        623        def embed_texts(texts: list[str]) -> list[list[float]]:624            response = client.embeddings.create(625                model="text-embedding-3-small",626                input=texts627            )628            return [e.embedding for e in response.data]629            630        store = InMemoryStore(631            index={632                "dims": 1536,633                "embed": embed_texts634            }635        )636        ```637        638        Using an asynchronous embedding function with `InMemoryStore`:639 640        ```python641        from openai import AsyncOpenAI642        from langgraph.store.memory import InMemoryStore643        644        client = AsyncOpenAI()645        646        async def aembed_texts(texts: list[str]) -> list[list[float]]:647            response = await client.embeddings.create(648                model="text-embedding-3-small",649                input=texts650            )651            return [e.embedding for e in response.data]652            653        store = InMemoryStore(654            index={655                "dims": 1536,656                "embed": aembed_texts657            }658        )659        ```660    """661 662    fields: list[str] | None663    """Fields to extract text from for embedding generation.664    665    Controls which parts of stored items are embedded for semantic search. Follows JSON path syntax:666 667    - `["$"]`: Embeds the entire JSON object as one vector  (default)668    - `["field1", "field2"]`: Embeds specific top-level fields669    - `["parent.child"]`: Embeds nested fields using dot notation670    - `["array[*].field"]`: Embeds field from each array element separately671    672    Note:673        You can always override this behavior when storing an item using the674        `index` parameter in the `put` or `aput` operations.675    676    ???+ example "Examples"677 678        ```python679        # Embed entire document (default)680        fields=["$"]681        682        # Embed specific fields683        fields=["text", "summary"]684        685        # Embed nested fields686        fields=["metadata.title", "content.body"]687        688        # Embed from arrays689        fields=["messages[*].content"]  # Each message content separately690        fields=["context[0].text"]      # First context item's text691        ```692    693    Note:694        - Fields missing from a document are skipped695        - Array notation creates separate embeddings for each element696        - Complex nested paths are supported (e.g., `"a.b[*].c.d"`)697    """698 699 700class BaseStore(ABC):701    """Abstract base class for persistent key-value stores.702 703    Stores enable persistence and memory that can be shared across threads,704    scoped to user IDs, assistant IDs, or other arbitrary namespaces.705    Some implementations may support semantic search capabilities through706    an optional `index` configuration.707 708    Note:709        Semantic search capabilities vary by implementation and are typically710        disabled by default. Stores that support this feature can be configured711        by providing an `index` configuration at creation time. Without this712        configuration, semantic search is disabled and any `index` arguments713        to storage operations will have no effect.714 715        Similarly, TTL (time-to-live) support is disabled by default.716        Subclasses must explicitly set `supports_ttl = True` to enable this feature.717    """718 719    supports_ttl: bool = False720    ttl_config: TTLConfig | None = None721 722    __slots__ = ("__weakref__",)723 724    @abstractmethod725    def batch(self, ops: Iterable[Op]) -> list[Result]:726        """Execute multiple operations synchronously in a single batch.727 728        Args:729            ops: An iterable of operations to execute.730 731        Returns:732            A list of results, where each result corresponds to an operation in the input.733            The order of results matches the order of input operations.734        """735 736    @abstractmethod737    async def abatch(self, ops: Iterable[Op]) -> list[Result]:738        """Execute multiple operations asynchronously in a single batch.739 740        Args:741            ops: An iterable of operations to execute.742 743        Returns:744            A list of results, where each result corresponds to an operation in the input.745            The order of results matches the order of input operations.746        """747 748    def get(749        self,750        namespace: tuple[str, ...],751        key: str,752        *,753        refresh_ttl: bool | None = None,754    ) -> Item | None:755        """Retrieve a single item.756 757        Args:758            namespace: Hierarchical path for the item.759            key: Unique identifier within the namespace.760            refresh_ttl: Whether to refresh TTLs for the returned item.761                If `None`, uses the store's default `refresh_ttl` setting.762                If no TTL is specified, this argument is ignored.763 764        Returns:765            The retrieved item or `None` if not found.766        """767        return self.batch(768            [GetOp(namespace, str(key), _ensure_refresh(self.ttl_config, refresh_ttl))]769        )[0]770 771    def search(772        self,773        namespace_prefix: tuple[str, ...],774        /,775        *,776        query: str | None = None,777        filter: dict[str, Any] | None = None,778        limit: int = 10,779        offset: int = 0,780        refresh_ttl: bool | None = None,781    ) -> list[SearchItem]:782        """Search for items within a namespace prefix.783 784        Args:785            namespace_prefix: Hierarchical path prefix to search within.786            query: Optional query for natural language search.787            filter: Key-value pairs to filter results.788            limit: Maximum number of items to return.789            offset: Number of items to skip before returning results.790            refresh_ttl: Whether to refresh TTLs for the returned items.791                If no TTL is specified, this argument is ignored.792 793        Returns:794            List of items matching the search criteria.795 796        ???+ example "Examples"797 798            Basic filtering:799 800            ```python801            # Search for documents with specific metadata802            results = store.search(803                ("docs",),804                filter={"type": "article", "status": "published"}805            )806            ```807 808            Natural language search (requires vector store implementation):809 810            ```python811            # Initialize store with embedding configuration812            store = YourStore( # e.g., InMemoryStore, AsyncPostgresStore813                index={814                    "dims": 1536,  # embedding dimensions815                    "embed": your_embedding_function,  # function to create embeddings816                    "fields": ["text"]  # fields to embed. Defaults to ["$"]817                }818            )819 820            # Search for semantically similar documents821 822            results = store.search(823                ("docs",),824                query="machine learning applications in healthcare",825                filter={"type": "research_paper"},826                limit=5827            )828            ```829 830            !!! note831 832                Natural language search support depends on your store implementation833                and requires proper embedding configuration.834        """835        return self.batch(836            [837                SearchOp(838                    namespace_prefix,839                    filter,840                    limit,841                    offset,842                    query,843                    _ensure_refresh(self.ttl_config, refresh_ttl),844                )845            ]846        )[0]847 848    def put(849        self,850        namespace: tuple[str, ...],851        key: str,852        value: dict[str, Any],853        index: Literal[False] | list[str] | None = None,854        *,855        ttl: float | None | NotProvided = NOT_PROVIDED,856    ) -> None:857        """Store or update an item in the store.858 859        Args:860            namespace: Hierarchical path for the item, represented as a tuple of strings.861                Example: `("documents", "user123")`862            key: Unique identifier within the namespace. Together with namespace forms863                the complete path to the item.864            value: Dictionary containing the item's data. Must contain string keys865                and JSON-serializable values.866            index: Controls how the item's fields are indexed for search:867 868                - None (default): Use `fields` you configured when creating the store (if any)869                    If you do not initialize the store with indexing capabilities,870                    the `index` parameter will be ignored871                - False: Disable indexing for this item872                - `list[str]`: List of field paths to index, supporting:873                    - Nested fields: `"metadata.title"`874                    - Array access: `"chapters[*].content"` (each indexed separately)875                    - Specific indices: `"authors[0].name"`876            ttl: Time to live in minutes. Support for this argument depends on your store adapter.877                If specified, the item will expire after this many minutes from when it was last accessed.878                None means no expiration. Expired runs will be deleted opportunistically.879                By default, the expiration timer refreshes on both read operations (get/search)880                and write operations (put/update), whenever the item is included in the operation.881 882        Note:883            Indexing support depends on your store implementation.884            If you do not initialize the store with indexing capabilities,885            the `index` parameter will be ignored.886 887            Similarly, TTL support depends on the specific store implementation.888            Some implementations may not support expiration of items.889 890        ???+ example "Examples"891 892            Store item. Indexing depends on how you configure the store:893 894            ```python895            store.put(("docs",), "report", {"memory": "Will likes ai"})896            ```897 898            Do not index item for semantic search. Still accessible through `get()`899            and `search()` operations but won't have a vector representation.900 901            ```python902            store.put(("docs",), "report", {"memory": "Will likes ai"}, index=False)903            ```904 905            Index specific fields for search:906 907            ```python908            store.put(("docs",), "report", {"memory": "Will likes ai"}, index=["memory"])909            ```910        """911        _validate_namespace(namespace)912        if ttl not in (NOT_PROVIDED, None) and not self.supports_ttl:913            raise NotImplementedError(914                f"TTL is not supported by {self.__class__.__name__}. "915                f"Use a store implementation that supports TTL or set ttl=None."916            )917        self.batch(918            [919                PutOp(920                    namespace,921                    str(key),922                    value,923                    index=index,924                    ttl=_ensure_ttl(self.ttl_config, ttl),925                )926            ]927        )928 929    def delete(self, namespace: tuple[str, ...], key: str) -> None:930        """Delete an item.931 932        Args:933            namespace: Hierarchical path for the item.934            key: Unique identifier within the namespace.935        """936        self.batch([PutOp(namespace, str(key), None, ttl=None)])937 938    def list_namespaces(939        self,940        *,941        prefix: NamespacePath | None = None,942        suffix: NamespacePath | None = None,943        max_depth: int | None = None,944        limit: int = 100,945        offset: int = 0,946    ) -> list[tuple[str, ...]]:947        """List and filter namespaces in the store.948 949        Used to explore the organization of data,950        find specific collections, or navigate the namespace hierarchy.951 952        Args:953            prefix: Filter namespaces that start with this path.954            suffix: Filter namespaces that end with this path.955            max_depth: Return namespaces up to this depth in the hierarchy.956                Namespaces deeper than this level will be truncated.957            limit: Maximum number of namespaces to return.958            offset: Number of namespaces to skip for pagination.959 960        Returns:961            A list of namespace tuples that match the criteria. Each tuple represents a962                full namespace path up to `max_depth`.963 964        ???+ example "Examples":965 966            Setting `max_depth=3`. Given the namespaces:967 968            ```python969            # Example if you have the following namespaces:970            # ("a", "b", "c")971            # ("a", "b", "d", "e")972            # ("a", "b", "d", "i")973            # ("a", "b", "f")974            # ("a", "c", "f")975            store.list_namespaces(prefix=("a", "b"), max_depth=3)976            # [("a", "b", "c"), ("a", "b", "d"), ("a", "b", "f")]977            ```978        """979        match_conditions = []980        if prefix:981            match_conditions.append(MatchCondition(match_type="prefix", path=prefix))982        if suffix:983            match_conditions.append(MatchCondition(match_type="suffix", path=suffix))984 985        op = ListNamespacesOp(986            match_conditions=tuple(match_conditions),987            max_depth=max_depth,988            limit=limit,989            offset=offset,990        )991        return self.batch([op])[0]992 993    async def aget(994        self,995        namespace: tuple[str, ...],996        key: str,997        *,998        refresh_ttl: bool | None = None,999    ) -> Item | None:1000        """Asynchronously retrieve a single item.1001 1002        Args:1003            namespace: Hierarchical path for the item.1004            key: Unique identifier within the namespace.1005 1006        Returns:1007            The retrieved item or `None` if not found.1008        """1009        return (1010            await self.abatch(1011                [1012                    GetOp(1013                        namespace,1014                        str(key),1015                        _ensure_refresh(self.ttl_config, refresh_ttl),1016                    )1017                ]1018            )1019        )[0]1020 1021    async def asearch(1022        self,1023        namespace_prefix: tuple[str, ...],1024        /,1025        *,1026        query: str | None = None,1027        filter: dict[str, Any] | None = None,1028        limit: int = 10,1029        offset: int = 0,1030        refresh_ttl: bool | None = None,1031    ) -> list[SearchItem]:1032        """Asynchronously search for items within a namespace prefix.1033 1034        Args:1035            namespace_prefix: Hierarchical path prefix to search within.1036            query: Optional query for natural language search.1037            filter: Key-value pairs to filter results.1038            limit: Maximum number of items to return.1039            offset: Number of items to skip before returning results.1040            refresh_ttl: Whether to refresh TTLs for the returned items.1041                If `None`, uses the store's `TTLConfig.refresh_default` setting.1042                If `TTLConfig` is not provided or no TTL is specified, this argument is ignored.1043 1044        Returns:1045            List of items matching the search criteria.1046 1047        ???+ example "Examples"1048 1049            Basic filtering:1050 1051            ```python1052            # Search for documents with specific metadata1053            results = await store.asearch(1054                ("docs",),1055                filter={"type": "article", "status": "published"}1056            )1057            ```1058 1059            Natural language search (requires vector store implementation):1060 1061            ```python1062            # Initialize store with embedding configuration1063            store = YourStore( # e.g., InMemoryStore, AsyncPostgresStore1064                index={1065                    "dims": 1536,  # embedding dimensions1066                    "embed": your_embedding_function,  # function to create embeddings1067                    "fields": ["text"]  # fields to embed1068                }1069            )1070 1071            # Search for semantically similar documents1072 1073            results = await store.asearch(1074                ("docs",),1075                query="machine learning applications in healthcare",1076                filter={"type": "research_paper"},1077                limit=51078            )1079            ```1080 1081            !!! note1082 1083                Natural language search support depends on your store implementation1084                and requires proper embedding configuration.1085        """1086        return (1087            await self.abatch(1088                [1089                    SearchOp(1090                        namespace_prefix,1091                        filter,1092                        limit,1093                        offset,1094                        query,1095                        _ensure_refresh(self.ttl_config, refresh_ttl),1096                    )1097                ]1098            )1099        )[0]1100 1101    async def aput(1102        self,1103        namespace: tuple[str, ...],1104        key: str,1105        value: dict[str, Any],1106        index: Literal[False] | list[str] | None = None,1107        *,1108        ttl: float | None | NotProvided = NOT_PROVIDED,1109    ) -> None:1110        """Asynchronously store or update an item in the store.1111 1112        Args:1113            namespace: Hierarchical path for the item, represented as a tuple of strings.1114                Example: `("documents", "user123")`1115            key: Unique identifier within the namespace. Together with namespace forms1116                the complete path to the item.1117            value: Dictionary containing the item's data. Must contain string keys1118                and JSON-serializable values.1119            index: Controls how the item's fields are indexed for search:1120 1121                - None (default): Use `fields` you configured when creating the store (if any)1122                    If you do not initialize the store with indexing capabilities,1123                    the `index` parameter will be ignored1124                - False: Disable indexing for this item1125                - `list[str]`: List of field paths to index, supporting:1126                    - Nested fields: `"metadata.title"`1127                    - Array access: `"chapters[*].content"` (each indexed separately)1128                    - Specific indices: `"authors[0].name"`1129            ttl: Time to live in minutes. Support for this argument depends on your store adapter.1130                If specified, the item will expire after this many minutes from when it was last accessed.1131                None means no expiration. Expired runs will be deleted opportunistically.1132                By default, the expiration timer refreshes on both read operations (get/search)1133                and write operations (put/update), whenever the item is included in the operation.1134 1135        Note:1136            Indexing support depends on your store implementation.1137            If you do not initialize the store with indexing capabilities,1138            the `index` parameter will be ignored.1139 1140            Similarly, TTL support depends on the specific store implementation.1141            Some implementations may not support expiration of items.1142 1143        ???+ example "Examples"1144 1145            Store item. Indexing depends on how you configure the store:1146 1147            ```python1148            await store.aput(("docs",), "report", {"memory": "Will likes ai"})1149            ```1150 1151            Do not index item for semantic search. Still accessible through `get()`1152            and `search()` operations but won't have a vector representation.1153 1154            ```python1155            await store.aput(("docs",), "report", {"memory": "Will likes ai"}, index=False)1156            ```1157 1158            Index specific fields for search (if store configured to index items):1159 1160            ```python1161            await store.aput(1162                ("docs",),1163                "report",1164                {1165                    "memory": "Will likes ai",1166                    "context": [{"content": "..."}, {"content": "..."}]1167                },1168                index=["memory", "context[*].content"]1169            )1170            ```1171        """1172        _validate_namespace(namespace)1173        if ttl not in (NOT_PROVIDED, None) and not self.supports_ttl:1174            raise NotImplementedError(1175                f"TTL is not supported by {self.__class__.__name__}. "1176                f"Use a store implementation that supports TTL or set ttl=None."1177            )1178        await self.abatch(1179            [1180                PutOp(1181                    namespace,1182                    str(key),1183                    value,1184                    index=index,1185                    ttl=_ensure_ttl(self.ttl_config, ttl),1186                )1187            ]1188        )1189 1190    async def adelete(self, namespace: tuple[str, ...], key: str) -> None:1191        """Asynchronously delete an item.1192 1193        Args:1194            namespace: Hierarchical path for the item.1195            key: Unique identifier within the namespace.1196        """1197        await self.abatch([PutOp(namespace, str(key), None)])1198 1199    async def alist_namespaces(1200        self,

Showing the first 1,200 of 1315 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai