diff --git a/.fern/replay.lock b/.fern/replay.lock index 9c4b29f..2516491 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -18,5 +18,11 @@ generations: cli_version: unknown generator_versions: fernapi/fern-python-sdk: 4.25.5 -current_generation: 06329e0a67f5396af716b0f9065bf54ff9b4e613 + - commit_sha: 655b8543b6b351fc28eb78c0fcc39aa93d90b410 + tree_hash: a5aa6b923d390b275f7e12ca55ba9b44d0689ffd + timestamp: 2026-08-11T18:33:25.432Z + cli_version: unknown + generator_versions: + fernapi/fern-python-sdk: 4.25.5 +current_generation: 655b8543b6b351fc28eb78c0fcc39aa93d90b410 patches: [] diff --git a/pyproject.toml b/pyproject.toml index 2dae47b..6eba05c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [project] name = "zep-cloud" -version = "3.27.0" +version = "3.28.0" [tool.poetry] name = "zep-cloud" -version = "3.27.0" +version = "3.28.0" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index 9158587..d9dba04 100644 --- a/reference.md +++ b/reference.md @@ -3536,6 +3536,9 @@ client.graph.search( Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; auto search always uses RRF retrieval and applies its own internal rerank after retrieval. +episode_mentions ranks edge candidates by how many of the episodes listed +in search_filters.episode_uuids mention them; without episode_uuids it has +no effect and results are ranked as if no reranker were specified. @@ -3587,6 +3590,153 @@ edges, nodes, observations, and thread_summaries. + + + + +
client.graph.get_subgraph(...) +
+
+ +#### ๐Ÿ“ Description + +
+
+ +
+
+ +Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. +
+
+
+
+ +#### ๐Ÿ”Œ Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep + +client = Zep( + api_key="YOUR_API_KEY", +) +client.graph.get_subgraph( + seed_node_uuids=["seed_node_uuids"], +) + +``` +
+
+
+
+ +#### โš™๏ธ Parameters + +
+
+ +
+
+ +**seed_node_uuids:** `typing.Sequence[str]` + +Seed node UUIDs to expand from, in traversal-priority order: seeds are +admitted before any expansion, in this order, and count toward +max_nodes first. 1-20 entries, required. Seeds that do not exist in +the target graph are ignored, not an error. + +
+
+ +
+
+ +**depth:** `typing.Optional[int]` โ€” Maximum traversal depth from the seeds. 1-3. Defaults to 1. + +
+
+ +
+
+ +**direction:** `typing.Optional[str]` + +Edge orientation followed during expansion, relative to each frontier +node: "in" | "out" | "both". Defaults to "both". + +
+
+ +
+
+ +**graph_id:** `typing.Optional[str]` + +graph_id identifies the target named graph. Exactly one of user_id or +graph_id is required. + +
+
+ +
+
+ +**max_edges:** `typing.Optional[int]` โ€” Maximum number of edges in the response. 1-1000. Defaults to 200. + +
+
+ +
+
+ +**max_nodes:** `typing.Optional[int]` + +Maximum number of nodes in the response, including admitted seeds. +1-500. Defaults to 100. + +
+
+ +
+
+ +**search_filters:** `typing.Optional[SearchFilters]` + +Filters constraining traversed edges and included nodes. Reuses the +graph.search filter type. search_filters.episode_metadata_filters is +rejected: it cannot be enforced during graph traversal (spec-2 ยง9.4). + +
+
+ +
+
+ +**user_id:** `typing.Optional[str]` + +user_id identifies the target user graph. Exactly one of user_id or +graph_id is required. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` โ€” Request-specific configuration. + +
+
+
+
+ +
@@ -6495,6 +6645,125 @@ client.graph.episode.get_by_graph_id( + + + + +
client.graph.episode.list_by_graph_id(...) +
+
+ +#### ๐Ÿ“ Description + +
+
+ +
+
+ +Returns a paginated, filterable list of episodes for a graph. +
+
+
+
+ +#### ๐Ÿ”Œ Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep + +client = Zep( + api_key="YOUR_API_KEY", +) +client.graph.episode.list_by_graph_id( + graph_id="graph_id", +) + +``` +
+
+
+
+ +#### โš™๏ธ Parameters + +
+
+ +
+
+ +**graph_id:** `str` โ€” Graph ID + +
+
+ +
+
+ +**cursor:** `typing.Optional[str]` + +Opaque cursor for pagination, obtained from the Zep-Next-Cursor +response header of the previous page. + +
+
+ +
+
+ +**direction:** `typing.Optional[str]` โ€” Sort direction. One of "asc" or "desc". Defaults to "desc". + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` + +Maximum number of episodes to return. An explicit value is clamped to +50; when omitted, the default page size (100) applies. + +
+
+ +
+
+ +**mentioned_node_uuids:** `typing.Optional[typing.Sequence[str]]` + +Restricts results to episodes that mention any of the listed node +UUIDs. At most 256 entries; each must be a syntactically valid UUID. + +
+
+ +
+
+ +**order_by:** `typing.Optional[str]` โ€” Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` โ€” Request-specific configuration. + +
+
+
+
+ +
@@ -6574,6 +6843,125 @@ client.graph.episode.get_by_user_id( + + + + +
client.graph.episode.list_by_user_id(...) +
+
+ +#### ๐Ÿ“ Description + +
+
+ +
+
+ +Returns a paginated, filterable list of episodes for a user's graph. +
+
+
+
+ +#### ๐Ÿ”Œ Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep + +client = Zep( + api_key="YOUR_API_KEY", +) +client.graph.episode.list_by_user_id( + user_id="user_id", +) + +``` +
+
+
+
+ +#### โš™๏ธ Parameters + +
+
+ +
+
+ +**user_id:** `str` โ€” User ID + +
+
+ +
+
+ +**cursor:** `typing.Optional[str]` + +Opaque cursor for pagination, obtained from the Zep-Next-Cursor +response header of the previous page. + +
+
+ +
+
+ +**direction:** `typing.Optional[str]` โ€” Sort direction. One of "asc" or "desc". Defaults to "desc". + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` + +Maximum number of episodes to return. An explicit value is clamped to +50; when omitted, the default page size (100) applies. + +
+
+ +
+
+ +**mentioned_node_uuids:** `typing.Optional[typing.Sequence[str]]` + +Restricts results to episodes that mention any of the listed node +UUIDs. At most 256 entries; each must be a syntactically valid UUID. + +
+
+ +
+
+ +**order_by:** `typing.Optional[str]` โ€” Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` โ€” Request-specific configuration. + +
+
+
+
+ +
@@ -6809,7 +7197,7 @@ client.graph.episode.update(
-Returns nodes and edges mentioned in an episode +Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
@@ -7130,7 +7518,7 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-Returns all edges for a node +Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
@@ -7200,7 +7588,7 @@ client.graph.node.get_edges(
-Returns all episodes that mentioned a given node +Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
@@ -7254,6 +7642,146 @@ client.graph.node.get_episodes( + + + + +
client.graph.node.get_neighbors(...) +
+
+ +#### ๐Ÿ“ Description + +
+
+ +
+
+ +Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. +
+
+
+
+ +#### ๐Ÿ”Œ Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep + +client = Zep( + api_key="YOUR_API_KEY", +) +client.graph.node.get_neighbors( + node_uuid="node_uuid", +) + +``` +
+
+
+
+ +#### โš™๏ธ Parameters + +
+
+ +
+
+ +**node_uuid:** `str` โ€” Node UUID + +
+
+ +
+
+ +**cursor:** `typing.Optional[str]` + +Opaque cursor for pagination, obtained from the Zep-Next-Cursor +response header of the previous page. + +
+
+ +
+
+ +**direction:** `typing.Optional[str]` + +Orientation of the connecting edge relative to the anchor node: "out" +(anchor is the edge's source), "in" (anchor is the edge's target), or +"both" (either). Defaults to "both". + +
+
+ +
+
+ +**direction_sort:** `typing.Optional[str]` + +Sort direction for order_by. One of "asc" or "desc". Defaults to +"desc". Named direction_sort to avoid clashing with the traversal +Direction field above. + +
+
+ +
+
+ +**filters:** `typing.Optional[SearchFilters]` + +Filters constraining the connecting edges (edge types, dates, and the +section-3 node-/episode-anchored fields) and the neighbor nodes +(node_labels/exclude_node_labels). Reuses the graph.search filter +type. + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` + +Maximum number of neighbor nodes to return. An explicit value is +clamped to 50; when omitted, the default page size (100) applies. + +
+
+ +
+
+ +**order_by:** `typing.Optional[str]` + +Field to sort neighbor nodes by. One of "uuid" or "created_at". +Defaults to "uuid". + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` โ€” Request-specific configuration. + +
+
+
+
+ +
diff --git a/src/zep_cloud/__init__.py b/src/zep_cloud/__init__.py index 9c9f3fb..9b7b03c 100644 --- a/src/zep_cloud/__init__.py +++ b/src/zep_cloud/__init__.py @@ -49,12 +49,15 @@ Graph, GraphDataType, GraphEdgesRequest, + GraphEpisodeListRequest, GraphListResponse, + GraphNodeNeighbor, GraphNodesRequest, GraphObservationsRequest, GraphSearchResponseMetadata, GraphSearchResults, GraphSearchScope, + GraphSubgraphResponse, GraphThreadSummariesRequest, GraphitiMetadataFilterGroupType, GraphitiSagaNode, @@ -158,12 +161,15 @@ "Graph", "GraphDataType", "GraphEdgesRequest", + "GraphEpisodeListRequest", "GraphListResponse", + "GraphNodeNeighbor", "GraphNodesRequest", "GraphObservationsRequest", "GraphSearchResponseMetadata", "GraphSearchResults", "GraphSearchScope", + "GraphSubgraphResponse", "GraphThreadSummariesRequest", "GraphitiMetadataFilterGroupType", "GraphitiSagaNode", diff --git a/src/zep_cloud/core/client_wrapper.py b/src/zep_cloud/core/client_wrapper.py index 9706024..dde7c3a 100644 --- a/src/zep_cloud/core/client_wrapper.py +++ b/src/zep_cloud/core/client_wrapper.py @@ -22,10 +22,10 @@ def __init__( def get_headers(self) -> typing.Dict[str, str]: headers: typing.Dict[str, str] = { - "User-Agent": "zep-cloud/3.27.0", + "User-Agent": "zep-cloud/3.28.0", "X-Fern-Language": "Python", "X-Fern-SDK-Name": "zep-cloud", - "X-Fern-SDK-Version": "3.27.0", + "X-Fern-SDK-Version": "3.28.0", **(self.get_custom_headers() or {}), } headers["Authorization"] = f"Api-Key {self.api_key}" diff --git a/src/zep_cloud/graph/client.py b/src/zep_cloud/graph/client.py index 93fe499..0e12d30 100644 --- a/src/zep_cloud/graph/client.py +++ b/src/zep_cloud/graph/client.py @@ -21,6 +21,7 @@ from ..types.graph_list_response import GraphListResponse from ..types.graph_search_results import GraphSearchResults from ..types.graph_search_scope import GraphSearchScope +from ..types.graph_subgraph_response import GraphSubgraphResponse from ..types.list_custom_instructions_response import ListCustomInstructionsResponse from ..types.pattern_seeds import PatternSeeds from ..types.recency_weight import RecencyWeight @@ -918,6 +919,9 @@ def search( reranker : typing.Optional[Reranker] Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; auto search always uses RRF retrieval and applies its own internal rerank after retrieval. + episode_mentions ranks edge candidates by how many of the episodes listed + in search_filters.episode_uuids mention them; without episode_uuids it has + no effect and results are ranked as if no reranker were specified. return_raw_results : typing.Optional[bool] When scope=auto, include the selected raw graph results alongside the materialized context block. @@ -969,6 +973,89 @@ def search( ) return _response.data + def get_subgraph( + self, + *, + seed_node_uuids: typing.Sequence[str], + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + search_filters: typing.Optional[SearchFilters] = OMIT, + user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> GraphSubgraphResponse: + """ + Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. + + Parameters + ---------- + seed_node_uuids : typing.Sequence[str] + Seed node UUIDs to expand from, in traversal-priority order: seeds are + admitted before any expansion, in this order, and count toward + max_nodes first. 1-20 entries, required. Seeds that do not exist in + the target graph are ignored, not an error. + + depth : typing.Optional[int] + Maximum traversal depth from the seeds. 1-3. Defaults to 1. + + direction : typing.Optional[str] + Edge orientation followed during expansion, relative to each frontier + node: "in" | "out" | "both". Defaults to "both". + + graph_id : typing.Optional[str] + graph_id identifies the target named graph. Exactly one of user_id or + graph_id is required. + + max_edges : typing.Optional[int] + Maximum number of edges in the response. 1-1000. Defaults to 200. + + max_nodes : typing.Optional[int] + Maximum number of nodes in the response, including admitted seeds. + 1-500. Defaults to 100. + + search_filters : typing.Optional[SearchFilters] + Filters constraining traversed edges and included nodes. Reuses the + graph.search filter type. search_filters.episode_metadata_filters is + rejected: it cannot be enforced during graph traversal (spec-2 ยง9.4). + + user_id : typing.Optional[str] + user_id identifies the target user graph. Exactly one of user_id or + graph_id is required. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GraphSubgraphResponse + Subgraph + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.graph.get_subgraph( + seed_node_uuids=["seed_node_uuids"], + ) + """ + _response = self._raw_client.get_subgraph( + seed_node_uuids=seed_node_uuids, + depth=depth, + direction=direction, + graph_id=graph_id, + max_edges=max_edges, + max_nodes=max_nodes, + search_filters=search_filters, + user_id=user_id, + request_options=request_options, + ) + return _response.data + def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Graph: """ Returns a graph. @@ -2095,6 +2182,9 @@ async def search( reranker : typing.Optional[Reranker] Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; auto search always uses RRF retrieval and applies its own internal rerank after retrieval. + episode_mentions ranks edge candidates by how many of the episodes listed + in search_filters.episode_uuids mention them; without episode_uuids it has + no effect and results are ranked as if no reranker were specified. return_raw_results : typing.Optional[bool] When scope=auto, include the selected raw graph results alongside the materialized context block. @@ -2154,6 +2244,97 @@ async def main() -> None: ) return _response.data + async def get_subgraph( + self, + *, + seed_node_uuids: typing.Sequence[str], + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + search_filters: typing.Optional[SearchFilters] = OMIT, + user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> GraphSubgraphResponse: + """ + Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. + + Parameters + ---------- + seed_node_uuids : typing.Sequence[str] + Seed node UUIDs to expand from, in traversal-priority order: seeds are + admitted before any expansion, in this order, and count toward + max_nodes first. 1-20 entries, required. Seeds that do not exist in + the target graph are ignored, not an error. + + depth : typing.Optional[int] + Maximum traversal depth from the seeds. 1-3. Defaults to 1. + + direction : typing.Optional[str] + Edge orientation followed during expansion, relative to each frontier + node: "in" | "out" | "both". Defaults to "both". + + graph_id : typing.Optional[str] + graph_id identifies the target named graph. Exactly one of user_id or + graph_id is required. + + max_edges : typing.Optional[int] + Maximum number of edges in the response. 1-1000. Defaults to 200. + + max_nodes : typing.Optional[int] + Maximum number of nodes in the response, including admitted seeds. + 1-500. Defaults to 100. + + search_filters : typing.Optional[SearchFilters] + Filters constraining traversed edges and included nodes. Reuses the + graph.search filter type. search_filters.episode_metadata_filters is + rejected: it cannot be enforced during graph traversal (spec-2 ยง9.4). + + user_id : typing.Optional[str] + user_id identifies the target user graph. Exactly one of user_id or + graph_id is required. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GraphSubgraphResponse + Subgraph + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.graph.get_subgraph( + seed_node_uuids=["seed_node_uuids"], + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_subgraph( + seed_node_uuids=seed_node_uuids, + depth=depth, + direction=direction, + graph_id=graph_id, + max_edges=max_edges, + max_nodes=max_nodes, + search_filters=search_filters, + user_id=user_id, + request_options=request_options, + ) + return _response.data + async def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Graph: """ Returns a graph. diff --git a/src/zep_cloud/graph/episode/client.py b/src/zep_cloud/graph/episode/client.py index f6261ff..0641988 100644 --- a/src/zep_cloud/graph/episode/client.py +++ b/src/zep_cloud/graph/episode/client.py @@ -70,6 +70,73 @@ def get_by_graph_id( _response = self._raw_client.get_by_graph_id(graph_id, lastn=lastn, request_options=request_options) return _response.data + def list_by_graph_id( + self, + graph_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[Episode]: + """ + Returns a paginated, filterable list of episodes for a graph. + + Parameters + ---------- + graph_id : str + Graph ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[Episode] + Episodes + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.graph.episode.list_by_graph_id( + graph_id="graph_id", + ) + """ + _response = self._raw_client.list_by_graph_id( + graph_id, + cursor=cursor, + direction=direction, + limit=limit, + mentioned_node_uuids=mentioned_node_uuids, + order_by=order_by, + request_options=request_options, + ) + return _response.data + def get_by_user_id( self, user_id: str, @@ -111,6 +178,73 @@ def get_by_user_id( _response = self._raw_client.get_by_user_id(user_id, lastn=lastn, request_options=request_options) return _response.data + def list_by_user_id( + self, + user_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[Episode]: + """ + Returns a paginated, filterable list of episodes for a user's graph. + + Parameters + ---------- + user_id : str + User ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[Episode] + Episodes + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.graph.episode.list_by_user_id( + user_id="user_id", + ) + """ + _response = self._raw_client.list_by_user_id( + user_id, + cursor=cursor, + direction=direction, + limit=limit, + mentioned_node_uuids=mentioned_node_uuids, + order_by=order_by, + request_options=request_options, + ) + return _response.data + def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> Episode: """ Returns episodes by UUID @@ -218,7 +352,7 @@ def get_nodes_and_edges( self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None ) -> EpisodeMentions: """ - Returns nodes and edges mentioned in an episode + Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -312,6 +446,81 @@ async def main() -> None: _response = await self._raw_client.get_by_graph_id(graph_id, lastn=lastn, request_options=request_options) return _response.data + async def list_by_graph_id( + self, + graph_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[Episode]: + """ + Returns a paginated, filterable list of episodes for a graph. + + Parameters + ---------- + graph_id : str + Graph ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[Episode] + Episodes + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.graph.episode.list_by_graph_id( + graph_id="graph_id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_by_graph_id( + graph_id, + cursor=cursor, + direction=direction, + limit=limit, + mentioned_node_uuids=mentioned_node_uuids, + order_by=order_by, + request_options=request_options, + ) + return _response.data + async def get_by_user_id( self, user_id: str, @@ -361,6 +570,81 @@ async def main() -> None: _response = await self._raw_client.get_by_user_id(user_id, lastn=lastn, request_options=request_options) return _response.data + async def list_by_user_id( + self, + user_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[Episode]: + """ + Returns a paginated, filterable list of episodes for a user's graph. + + Parameters + ---------- + user_id : str + User ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[Episode] + Episodes + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.graph.episode.list_by_user_id( + user_id="user_id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_by_user_id( + user_id, + cursor=cursor, + direction=direction, + limit=limit, + mentioned_node_uuids=mentioned_node_uuids, + order_by=order_by, + request_options=request_options, + ) + return _response.data + async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> Episode: """ Returns episodes by UUID @@ -492,7 +776,7 @@ async def get_nodes_and_edges( self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None ) -> EpisodeMentions: """ - Returns nodes and edges mentioned in an episode + Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- diff --git a/src/zep_cloud/graph/episode/raw_client.py b/src/zep_cloud/graph/episode/raw_client.py index eba044f..0c44952 100644 --- a/src/zep_cloud/graph/episode/raw_client.py +++ b/src/zep_cloud/graph/episode/raw_client.py @@ -102,6 +102,105 @@ def get_by_graph_id( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + def list_by_graph_id( + self, + graph_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[typing.List[Episode]]: + """ + Returns a paginated, filterable list of episodes for a graph. + + Parameters + ---------- + graph_id : str + Graph ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[typing.List[Episode]] + Episodes + """ + _response = self._client_wrapper.httpx_client.request( + f"graph/episodes/graph/{jsonable_encoder(graph_id)}", + method="POST", + json={ + "cursor": cursor, + "direction": direction, + "limit": limit, + "mentioned_node_uuids": mentioned_node_uuids, + "order_by": order_by, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[Episode], + parse_obj_as( + type_=typing.List[Episode], # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def get_by_user_id( self, user_id: str, @@ -177,6 +276,105 @@ def get_by_user_id( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + def list_by_user_id( + self, + user_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[typing.List[Episode]]: + """ + Returns a paginated, filterable list of episodes for a user's graph. + + Parameters + ---------- + user_id : str + User ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[typing.List[Episode]] + Episodes + """ + _response = self._client_wrapper.httpx_client.request( + f"graph/episodes/user/{jsonable_encoder(user_id)}", + method="POST", + json={ + "cursor": cursor, + "direction": direction, + "limit": limit, + "mentioned_node_uuids": mentioned_node_uuids, + "order_by": order_by, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[Episode], + parse_obj_as( + type_=typing.List[Episode], # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Episode]: """ Returns episodes by UUID @@ -421,7 +619,7 @@ def get_nodes_and_edges( self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[EpisodeMentions]: """ - Returns nodes and edges mentioned in an episode + Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -562,6 +760,105 @@ async def get_by_graph_id( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + async def list_by_graph_id( + self, + graph_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[typing.List[Episode]]: + """ + Returns a paginated, filterable list of episodes for a graph. + + Parameters + ---------- + graph_id : str + Graph ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[typing.List[Episode]] + Episodes + """ + _response = await self._client_wrapper.httpx_client.request( + f"graph/episodes/graph/{jsonable_encoder(graph_id)}", + method="POST", + json={ + "cursor": cursor, + "direction": direction, + "limit": limit, + "mentioned_node_uuids": mentioned_node_uuids, + "order_by": order_by, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[Episode], + parse_obj_as( + type_=typing.List[Episode], # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def get_by_user_id( self, user_id: str, @@ -637,6 +934,105 @@ async def get_by_user_id( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + async def list_by_user_id( + self, + user_id: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = OMIT, + mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[typing.List[Episode]]: + """ + Returns a paginated, filterable list of episodes for a user's graph. + + Parameters + ---------- + user_id : str + User ID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Sort direction. One of "asc" or "desc". Defaults to "desc". + + limit : typing.Optional[int] + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + + mentioned_node_uuids : typing.Optional[typing.Sequence[str]] + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + + order_by : typing.Optional[str] + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[typing.List[Episode]] + Episodes + """ + _response = await self._client_wrapper.httpx_client.request( + f"graph/episodes/user/{jsonable_encoder(user_id)}", + method="POST", + json={ + "cursor": cursor, + "direction": direction, + "limit": limit, + "mentioned_node_uuids": mentioned_node_uuids, + "order_by": order_by, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[Episode], + parse_obj_as( + type_=typing.List[Episode], # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def get( self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[Episode]: @@ -883,7 +1279,7 @@ async def get_nodes_and_edges( self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[EpisodeMentions]: """ - Returns nodes and edges mentioned in an episode + Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- diff --git a/src/zep_cloud/graph/node/client.py b/src/zep_cloud/graph/node/client.py index 71d531c..8fafd39 100644 --- a/src/zep_cloud/graph/node/client.py +++ b/src/zep_cloud/graph/node/client.py @@ -7,6 +7,7 @@ from ...types.entity_edge import EntityEdge from ...types.entity_node import EntityNode from ...types.episode_response import EpisodeResponse +from ...types.graph_node_neighbor import GraphNodeNeighbor from ...types.search_filters import SearchFilters from ...types.success_response import SuccessResponse from .raw_client import AsyncRawNodeClient, RawNodeClient @@ -178,7 +179,7 @@ def get_edges( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> typing.List[EntityEdge]: """ - Returns all edges for a node + Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -211,7 +212,7 @@ def get_episodes( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> EpisodeResponse: """ - Returns all episodes that mentioned a given node + Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -240,6 +241,85 @@ def get_episodes( _response = self._raw_client.get_episodes(node_uuid, request_options=request_options) return _response.data + def get_neighbors( + self, + node_uuid: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + direction_sort: typing.Optional[str] = OMIT, + filters: typing.Optional[SearchFilters] = OMIT, + limit: typing.Optional[int] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[GraphNodeNeighbor]: + """ + Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. + + Parameters + ---------- + node_uuid : str + Node UUID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Orientation of the connecting edge relative to the anchor node: "out" + (anchor is the edge's source), "in" (anchor is the edge's target), or + "both" (either). Defaults to "both". + + direction_sort : typing.Optional[str] + Sort direction for order_by. One of "asc" or "desc". Defaults to + "desc". Named direction_sort to avoid clashing with the traversal + Direction field above. + + filters : typing.Optional[SearchFilters] + Filters constraining the connecting edges (edge types, dates, and the + section-3 node-/episode-anchored fields) and the neighbor nodes + (node_labels/exclude_node_labels). Reuses the graph.search filter + type. + + limit : typing.Optional[int] + Maximum number of neighbor nodes to return. An explicit value is + clamped to 50; when omitted, the default page size (100) applies. + + order_by : typing.Optional[str] + Field to sort neighbor nodes by. One of "uuid" or "created_at". + Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[GraphNodeNeighbor] + Neighbors + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.graph.node.get_neighbors( + node_uuid="node_uuid", + ) + """ + _response = self._raw_client.get_neighbors( + node_uuid, + cursor=cursor, + direction=direction, + direction_sort=direction_sort, + filters=filters, + limit=limit, + order_by=order_by, + request_options=request_options, + ) + return _response.data + def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> EntityNode: """ Returns a specific node by its UUID. @@ -536,7 +616,7 @@ async def get_edges( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> typing.List[EntityEdge]: """ - Returns all edges for a node + Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -577,7 +657,7 @@ async def get_episodes( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> EpisodeResponse: """ - Returns all episodes that mentioned a given node + Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -614,6 +694,93 @@ async def main() -> None: _response = await self._raw_client.get_episodes(node_uuid, request_options=request_options) return _response.data + async def get_neighbors( + self, + node_uuid: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + direction_sort: typing.Optional[str] = OMIT, + filters: typing.Optional[SearchFilters] = OMIT, + limit: typing.Optional[int] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[GraphNodeNeighbor]: + """ + Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. + + Parameters + ---------- + node_uuid : str + Node UUID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Orientation of the connecting edge relative to the anchor node: "out" + (anchor is the edge's source), "in" (anchor is the edge's target), or + "both" (either). Defaults to "both". + + direction_sort : typing.Optional[str] + Sort direction for order_by. One of "asc" or "desc". Defaults to + "desc". Named direction_sort to avoid clashing with the traversal + Direction field above. + + filters : typing.Optional[SearchFilters] + Filters constraining the connecting edges (edge types, dates, and the + section-3 node-/episode-anchored fields) and the neighbor nodes + (node_labels/exclude_node_labels). Reuses the graph.search filter + type. + + limit : typing.Optional[int] + Maximum number of neighbor nodes to return. An explicit value is + clamped to 50; when omitted, the default page size (100) applies. + + order_by : typing.Optional[str] + Field to sort neighbor nodes by. One of "uuid" or "created_at". + Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[GraphNodeNeighbor] + Neighbors + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.graph.node.get_neighbors( + node_uuid="node_uuid", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_neighbors( + node_uuid, + cursor=cursor, + direction=direction, + direction_sort=direction_sort, + filters=filters, + limit=limit, + order_by=order_by, + request_options=request_options, + ) + return _response.data + async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> EntityNode: """ Returns a specific node by its UUID. diff --git a/src/zep_cloud/graph/node/raw_client.py b/src/zep_cloud/graph/node/raw_client.py index a86270d..879bf2f 100644 --- a/src/zep_cloud/graph/node/raw_client.py +++ b/src/zep_cloud/graph/node/raw_client.py @@ -17,6 +17,7 @@ from ...types.entity_edge import EntityEdge from ...types.entity_node import EntityNode from ...types.episode_response import EpisodeResponse +from ...types.graph_node_neighbor import GraphNodeNeighbor from ...types.search_filters import SearchFilters from ...types.success_response import SuccessResponse @@ -244,7 +245,7 @@ def get_edges( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[typing.List[EntityEdge]]: """ - Returns all edges for a node + Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -309,7 +310,7 @@ def get_episodes( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[EpisodeResponse]: """ - Returns all episodes that mentioned a given node + Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -370,6 +371,133 @@ def get_episodes( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + def get_neighbors( + self, + node_uuid: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + direction_sort: typing.Optional[str] = OMIT, + filters: typing.Optional[SearchFilters] = OMIT, + limit: typing.Optional[int] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[typing.List[GraphNodeNeighbor]]: + """ + Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. + + Parameters + ---------- + node_uuid : str + Node UUID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Orientation of the connecting edge relative to the anchor node: "out" + (anchor is the edge's source), "in" (anchor is the edge's target), or + "both" (either). Defaults to "both". + + direction_sort : typing.Optional[str] + Sort direction for order_by. One of "asc" or "desc". Defaults to + "desc". Named direction_sort to avoid clashing with the traversal + Direction field above. + + filters : typing.Optional[SearchFilters] + Filters constraining the connecting edges (edge types, dates, and the + section-3 node-/episode-anchored fields) and the neighbor nodes + (node_labels/exclude_node_labels). Reuses the graph.search filter + type. + + limit : typing.Optional[int] + Maximum number of neighbor nodes to return. An explicit value is + clamped to 50; when omitted, the default page size (100) applies. + + order_by : typing.Optional[str] + Field to sort neighbor nodes by. One of "uuid" or "created_at". + Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[typing.List[GraphNodeNeighbor]] + Neighbors + """ + _response = self._client_wrapper.httpx_client.request( + f"graph/node/{jsonable_encoder(node_uuid)}/neighbors", + method="POST", + json={ + "cursor": cursor, + "direction": direction, + "direction_sort": direction_sort, + "filters": convert_and_respect_annotation_metadata( + object_=filters, annotation=SearchFilters, direction="write" + ), + "limit": limit, + "order_by": order_by, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[GraphNodeNeighbor], + parse_obj_as( + type_=typing.List[GraphNodeNeighbor], # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[EntityNode]: """ Returns a specific node by its UUID. @@ -846,7 +974,7 @@ async def get_edges( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[typing.List[EntityEdge]]: """ - Returns all edges for a node + Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -911,7 +1039,7 @@ async def get_episodes( self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[EpisodeResponse]: """ - Returns all episodes that mentioned a given node + Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. Parameters ---------- @@ -972,6 +1100,133 @@ async def get_episodes( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + async def get_neighbors( + self, + node_uuid: str, + *, + cursor: typing.Optional[str] = OMIT, + direction: typing.Optional[str] = OMIT, + direction_sort: typing.Optional[str] = OMIT, + filters: typing.Optional[SearchFilters] = OMIT, + limit: typing.Optional[int] = OMIT, + order_by: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[typing.List[GraphNodeNeighbor]]: + """ + Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. + + Parameters + ---------- + node_uuid : str + Node UUID + + cursor : typing.Optional[str] + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + + direction : typing.Optional[str] + Orientation of the connecting edge relative to the anchor node: "out" + (anchor is the edge's source), "in" (anchor is the edge's target), or + "both" (either). Defaults to "both". + + direction_sort : typing.Optional[str] + Sort direction for order_by. One of "asc" or "desc". Defaults to + "desc". Named direction_sort to avoid clashing with the traversal + Direction field above. + + filters : typing.Optional[SearchFilters] + Filters constraining the connecting edges (edge types, dates, and the + section-3 node-/episode-anchored fields) and the neighbor nodes + (node_labels/exclude_node_labels). Reuses the graph.search filter + type. + + limit : typing.Optional[int] + Maximum number of neighbor nodes to return. An explicit value is + clamped to 50; when omitted, the default page size (100) applies. + + order_by : typing.Optional[str] + Field to sort neighbor nodes by. One of "uuid" or "created_at". + Defaults to "uuid". + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[typing.List[GraphNodeNeighbor]] + Neighbors + """ + _response = await self._client_wrapper.httpx_client.request( + f"graph/node/{jsonable_encoder(node_uuid)}/neighbors", + method="POST", + json={ + "cursor": cursor, + "direction": direction, + "direction_sort": direction_sort, + "filters": convert_and_respect_annotation_metadata( + object_=filters, annotation=SearchFilters, direction="write" + ), + "limit": limit, + "order_by": order_by, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[GraphNodeNeighbor], + parse_obj_as( + type_=typing.List[GraphNodeNeighbor], # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def get( self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[EntityNode]: diff --git a/src/zep_cloud/graph/raw_client.py b/src/zep_cloud/graph/raw_client.py index ca4908e..4527e28 100644 --- a/src/zep_cloud/graph/raw_client.py +++ b/src/zep_cloud/graph/raw_client.py @@ -32,6 +32,7 @@ from ..types.graph_list_response import GraphListResponse from ..types.graph_search_results import GraphSearchResults from ..types.graph_search_scope import GraphSearchScope +from ..types.graph_subgraph_response import GraphSubgraphResponse from ..types.list_custom_instructions_response import ListCustomInstructionsResponse from ..types.pattern_seeds import PatternSeeds from ..types.recency_weight import RecencyWeight @@ -1455,6 +1456,9 @@ def search( reranker : typing.Optional[Reranker] Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; auto search always uses RRF retrieval and applies its own internal rerank after retrieval. + episode_mentions ranks edge candidates by how many of the episodes listed + in search_filters.episode_uuids mention them; without episode_uuids it has + no effect and results are ranked as if no reranker were specified. return_raw_results : typing.Optional[bool] When scope=auto, include the selected raw graph results alongside the materialized context block. @@ -1544,6 +1548,149 @@ def search( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + def get_subgraph( + self, + *, + seed_node_uuids: typing.Sequence[str], + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + search_filters: typing.Optional[SearchFilters] = OMIT, + user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[GraphSubgraphResponse]: + """ + Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. + + Parameters + ---------- + seed_node_uuids : typing.Sequence[str] + Seed node UUIDs to expand from, in traversal-priority order: seeds are + admitted before any expansion, in this order, and count toward + max_nodes first. 1-20 entries, required. Seeds that do not exist in + the target graph are ignored, not an error. + + depth : typing.Optional[int] + Maximum traversal depth from the seeds. 1-3. Defaults to 1. + + direction : typing.Optional[str] + Edge orientation followed during expansion, relative to each frontier + node: "in" | "out" | "both". Defaults to "both". + + graph_id : typing.Optional[str] + graph_id identifies the target named graph. Exactly one of user_id or + graph_id is required. + + max_edges : typing.Optional[int] + Maximum number of edges in the response. 1-1000. Defaults to 200. + + max_nodes : typing.Optional[int] + Maximum number of nodes in the response, including admitted seeds. + 1-500. Defaults to 100. + + search_filters : typing.Optional[SearchFilters] + Filters constraining traversed edges and included nodes. Reuses the + graph.search filter type. search_filters.episode_metadata_filters is + rejected: it cannot be enforced during graph traversal (spec-2 ยง9.4). + + user_id : typing.Optional[str] + user_id identifies the target user graph. Exactly one of user_id or + graph_id is required. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GraphSubgraphResponse] + Subgraph + """ + _response = self._client_wrapper.httpx_client.request( + "graph/subgraph", + method="POST", + json={ + "depth": depth, + "direction": direction, + "graph_id": graph_id, + "max_edges": max_edges, + "max_nodes": max_nodes, + "search_filters": convert_and_respect_annotation_metadata( + object_=search_filters, annotation=SearchFilters, direction="write" + ), + "seed_node_uuids": seed_node_uuids, + "user_id": user_id, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GraphSubgraphResponse, + parse_obj_as( + type_=GraphSubgraphResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Graph]: """ Returns a graph. @@ -3259,6 +3406,9 @@ async def search( reranker : typing.Optional[Reranker] Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; auto search always uses RRF retrieval and applies its own internal rerank after retrieval. + episode_mentions ranks edge candidates by how many of the episodes listed + in search_filters.episode_uuids mention them; without episode_uuids it has + no effect and results are ranked as if no reranker were specified. return_raw_results : typing.Optional[bool] When scope=auto, include the selected raw graph results alongside the materialized context block. @@ -3348,6 +3498,149 @@ async def search( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + async def get_subgraph( + self, + *, + seed_node_uuids: typing.Sequence[str], + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + search_filters: typing.Optional[SearchFilters] = OMIT, + user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[GraphSubgraphResponse]: + """ + Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. + + Parameters + ---------- + seed_node_uuids : typing.Sequence[str] + Seed node UUIDs to expand from, in traversal-priority order: seeds are + admitted before any expansion, in this order, and count toward + max_nodes first. 1-20 entries, required. Seeds that do not exist in + the target graph are ignored, not an error. + + depth : typing.Optional[int] + Maximum traversal depth from the seeds. 1-3. Defaults to 1. + + direction : typing.Optional[str] + Edge orientation followed during expansion, relative to each frontier + node: "in" | "out" | "both". Defaults to "both". + + graph_id : typing.Optional[str] + graph_id identifies the target named graph. Exactly one of user_id or + graph_id is required. + + max_edges : typing.Optional[int] + Maximum number of edges in the response. 1-1000. Defaults to 200. + + max_nodes : typing.Optional[int] + Maximum number of nodes in the response, including admitted seeds. + 1-500. Defaults to 100. + + search_filters : typing.Optional[SearchFilters] + Filters constraining traversed edges and included nodes. Reuses the + graph.search filter type. search_filters.episode_metadata_filters is + rejected: it cannot be enforced during graph traversal (spec-2 ยง9.4). + + user_id : typing.Optional[str] + user_id identifies the target user graph. Exactly one of user_id or + graph_id is required. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GraphSubgraphResponse] + Subgraph + """ + _response = await self._client_wrapper.httpx_client.request( + "graph/subgraph", + method="POST", + json={ + "depth": depth, + "direction": direction, + "graph_id": graph_id, + "max_edges": max_edges, + "max_nodes": max_nodes, + "search_filters": convert_and_respect_annotation_metadata( + object_=search_filters, annotation=SearchFilters, direction="write" + ), + "seed_node_uuids": seed_node_uuids, + "user_id": user_id, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GraphSubgraphResponse, + parse_obj_as( + type_=GraphSubgraphResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def get( self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[Graph]: diff --git a/src/zep_cloud/types/__init__.py b/src/zep_cloud/types/__init__.py index f393620..535b0a0 100644 --- a/src/zep_cloud/types/__init__.py +++ b/src/zep_cloud/types/__init__.py @@ -48,12 +48,15 @@ from .graph import Graph from .graph_data_type import GraphDataType from .graph_edges_request import GraphEdgesRequest +from .graph_episode_list_request import GraphEpisodeListRequest from .graph_list_response import GraphListResponse +from .graph_node_neighbor import GraphNodeNeighbor from .graph_nodes_request import GraphNodesRequest from .graph_observations_request import GraphObservationsRequest from .graph_search_response_metadata import GraphSearchResponseMetadata from .graph_search_results import GraphSearchResults from .graph_search_scope import GraphSearchScope +from .graph_subgraph_response import GraphSubgraphResponse from .graph_thread_summaries_request import GraphThreadSummariesRequest from .graphiti_metadata_filter_group_type import GraphitiMetadataFilterGroupType from .graphiti_saga_node import GraphitiSagaNode @@ -147,12 +150,15 @@ "Graph", "GraphDataType", "GraphEdgesRequest", + "GraphEpisodeListRequest", "GraphListResponse", + "GraphNodeNeighbor", "GraphNodesRequest", "GraphObservationsRequest", "GraphSearchResponseMetadata", "GraphSearchResults", "GraphSearchScope", + "GraphSubgraphResponse", "GraphThreadSummariesRequest", "GraphitiMetadataFilterGroupType", "GraphitiSagaNode", diff --git a/src/zep_cloud/types/date_filter.py b/src/zep_cloud/types/date_filter.py index 154360a..19ab422 100644 --- a/src/zep_cloud/types/date_filter.py +++ b/src/zep_cloud/types/date_filter.py @@ -15,7 +15,7 @@ class DateFilter(UniversalBaseModel): date: typing.Optional[str] = pydantic.Field(default=None) """ - Date to filter on. Required for non-null operators (=, \<\>, \>, \<, \>=, \<=). + Date to filter on. Required for non-null operators (`=`, `<>`, `>`, `<`, `>=`, `<=`). Should be omitted for IS NULL (or is_null) and IS NOT NULL operators. """ diff --git a/src/zep_cloud/types/entity_edge.py b/src/zep_cloud/types/entity_edge.py index ac88a96..91a79a2 100644 --- a/src/zep_cloud/types/entity_edge.py +++ b/src/zep_cloud/types/entity_edge.py @@ -65,11 +65,38 @@ class EntityEdge(UniversalBaseModel): SelectionRank is the global cross-scope rank assigned by auto scope selection. """ + source_node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + SourceNodeLabels are the labels of the source node at read time. Same + read-time-projection semantics as SourceNodeName (spec-2 ยง4). + """ + + source_node_name: typing.Optional[str] = pydantic.Field(default=None) + """ + SourceNodeName is the name of the source node at read time. It is a + read-time projection of current node state, not a stored edge + attribute: a subsequent node rename is reflected on the next read. + Omitted (the edge is still returned) if the source node cannot be + resolved, for example if it was deleted concurrently (spec-2 ยง4). + """ + source_node_uuid: str = pydantic.Field() """ UUID of the source node """ + target_node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + TargetNodeLabels are the labels of the target node at read time. Same + read-time-projection semantics as SourceNodeName (spec-2 ยง4). + """ + + target_node_name: typing.Optional[str] = pydantic.Field(default=None) + """ + TargetNodeName is the name of the target node at read time. Same + read-time-projection semantics as SourceNodeName (spec-2 ยง4). + """ + target_node_uuid: str = pydantic.Field() """ UUID of the target node diff --git a/src/zep_cloud/types/graph_episode_list_request.py b/src/zep_cloud/types/graph_episode_list_request.py new file mode 100644 index 0000000..e7bd251 --- /dev/null +++ b/src/zep_cloud/types/graph_episode_list_request.py @@ -0,0 +1,45 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class GraphEpisodeListRequest(UniversalBaseModel): + cursor: typing.Optional[str] = pydantic.Field(default=None) + """ + Opaque cursor for pagination, obtained from the Zep-Next-Cursor + response header of the previous page. + """ + + direction: typing.Optional[str] = pydantic.Field(default=None) + """ + Sort direction. One of "asc" or "desc". Defaults to "desc". + """ + + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + Maximum number of episodes to return. An explicit value is clamped to + 50; when omitted, the default page size (100) applies. + """ + + mentioned_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Restricts results to episodes that mention any of the listed node + UUIDs. At most 256 entries; each must be a syntactically valid UUID. + """ + + order_by: typing.Optional[str] = pydantic.Field(default=None) + """ + Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_node_neighbor.py b/src/zep_cloud/types/graph_node_neighbor.py new file mode 100644 index 0000000..22e1f36 --- /dev/null +++ b/src/zep_cloud/types/graph_node_neighbor.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .entity_edge import EntityEdge +from .entity_node import EntityNode + + +class GraphNodeNeighbor(UniversalBaseModel): + edges: typing.Optional[typing.List[EntityEdge]] = None + node: typing.Optional[EntityNode] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_subgraph_response.py b/src/zep_cloud/types/graph_subgraph_response.py new file mode 100644 index 0000000..8be9872 --- /dev/null +++ b/src/zep_cloud/types/graph_subgraph_response.py @@ -0,0 +1,41 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .entity_edge import EntityEdge +from .entity_node import EntityNode + + +class GraphSubgraphResponse(UniversalBaseModel): + edges: typing.Optional[typing.List[EntityEdge]] = pydantic.Field(default=None) + """ + Every traversed edge that passed the request filters. Both endpoints + of every edge are present in Nodes (edge-endpoint closure). + """ + + nodes: typing.Optional[typing.List[EntityNode]] = pydantic.Field(default=None) + """ + Every admitted seed and every node reached within budget. + """ + + truncated: typing.Optional[bool] = pydantic.Field(default=None) + """ + True whenever any budget or internal limit reduced the result. + """ + + truncation_reason: typing.Optional[str] = pydantic.Field(default=None) + """ + Names the binding limit (for example "max_nodes", "max_edges") when + Truncated is true; nil otherwise. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/property_filter.py b/src/zep_cloud/types/property_filter.py index 8ff4827..eda06aa 100644 --- a/src/zep_cloud/types/property_filter.py +++ b/src/zep_cloud/types/property_filter.py @@ -22,7 +22,7 @@ class PropertyFilter(UniversalBaseModel): """ Property value to match on. Accepted types: string, int, float64, bool, or nil. Invalid types (e.g., arrays, objects) will be rejected by validation. - Must be non-nil for non-null operators (=, \<\>, \>, \<, \>=, \<=). + Must be non-nil for non-null operators (`=`, `<>`, `>`, `<`, `>=`, `<=`). """ if IS_PYDANTIC_V2: diff --git a/src/zep_cloud/types/search_filters.py b/src/zep_cloud/types/search_filters.py index faba501..50954d0 100644 --- a/src/zep_cloud/types/search_filters.py +++ b/src/zep_cloud/types/search_filters.py @@ -11,13 +11,20 @@ class SearchFilters(UniversalBaseModel): + connected_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of node UUIDs to filter edges on: an edge matches if its source OR + target node UUID is in this list. Applies to edges only; rejected on + requests whose result type contains no edges. Max 256 entries. + """ + created_at: typing.Optional[typing.List[typing.List[DateFilter]]] = pydantic.Field(default=None) """ 2D array of date filters for the created_at field. The outer array elements are combined with OR logic. The inner array elements are combined with AND logic. - Example: [[\{"\>", date1\}, \{"\<", date2\}], [\{"=", date3\}]] - This translates to: (created_at \> date1 AND created_at \< date2) OR (created_at = date3) + Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` + This translates to: `(created_at > date1 AND created_at < date2) OR (created_at = date3)` """ edge_types: typing.Optional[typing.List[str]] = pydantic.Field(default=None) @@ -36,6 +43,14 @@ class SearchFilters(UniversalBaseModel): matching the metadata predicates. Uses explicit AND/OR groups. This feature is experimental and may change in future releases. """ + episode_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of episode UUIDs to filter on. An edge matches if it was derived + from any listed episode; a node matches if it is mentioned by any + listed episode. Valid for both edge and node result types. Max 256 + entries. + """ + exclude_edge_types: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ List of edge types to exclude from results @@ -51,8 +66,8 @@ class SearchFilters(UniversalBaseModel): 2D array of date filters for the expired_at field. The outer array elements are combined with OR logic. The inner array elements are combined with AND logic. - Example: [[\{"\>", date1\}, \{"\<", date2\}], [\{"=", date3\}]] - This translates to: (expired_at \> date1 AND expired_at \< date2) OR (expired_at = date3) + Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` + This translates to: `(expired_at > date1 AND expired_at < date2) OR (expired_at = date3)` """ invalid_at: typing.Optional[typing.List[typing.List[DateFilter]]] = pydantic.Field(default=None) @@ -60,8 +75,8 @@ class SearchFilters(UniversalBaseModel): 2D array of date filters for the invalid_at field. The outer array elements are combined with OR logic. The inner array elements are combined with AND logic. - Example: [[\{"\>", date1\}, \{"\<", date2\}], [\{"=", date3\}]] - This translates to: (invalid_at \> date1 AND invalid_at \< date2) OR (invalid_at = date3) + Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` + This translates to: `(invalid_at > date1 AND invalid_at < date2) OR (invalid_at = date3)` """ node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) @@ -74,13 +89,27 @@ class SearchFilters(UniversalBaseModel): List of property filters to apply to nodes and edges """ + source_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of node UUIDs to filter edges on: an edge matches if its source + node UUID is in this list. Applies to edges only; rejected on requests + whose result type contains no edges. Max 256 entries. + """ + + target_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of node UUIDs to filter edges on: an edge matches if its target + node UUID is in this list. Applies to edges only; rejected on requests + whose result type contains no edges. Max 256 entries. + """ + valid_at: typing.Optional[typing.List[typing.List[DateFilter]]] = pydantic.Field(default=None) """ 2D array of date filters for the valid_at field. The outer array elements are combined with OR logic. The inner array elements are combined with AND logic. - Example: [[\{"\>", date1\}, \{"\<", date2\}], [\{"=", date3\}]] - This translates to: (valid_at \> date1 AND valid_at \< date2) OR (valid_at = date3) + Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` + This translates to: `(valid_at > date1 AND valid_at < date2) OR (valid_at = date3)` """ if IS_PYDANTIC_V2: