From 472152716a1955e74d3257e05531f634b0c16c6c Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Tue, 11 Aug 2026 20:04:55 +0000
Subject: [PATCH 1/3] [fern-generated] Update SDK
Generated by Fern
CLI Version: unknown
Generators:
- fernapi/fern-python-sdk: 4.25.5
---
reference.md | 534 +++++++++++++++++-
src/zep_cloud/__init__.py | 6 +
src/zep_cloud/core/client_wrapper.py | 4 +-
src/zep_cloud/graph/client.py | 181 ++++++
src/zep_cloud/graph/episode/client.py | 288 +++++++++-
src/zep_cloud/graph/episode/raw_client.py | 400 ++++++++++++-
src/zep_cloud/graph/node/client.py | 175 +++++-
src/zep_cloud/graph/node/raw_client.py | 263 ++++++++-
src/zep_cloud/graph/raw_client.py | 293 ++++++++++
src/zep_cloud/types/__init__.py | 6 +
src/zep_cloud/types/date_filter.py | 2 +-
src/zep_cloud/types/entity_edge.py | 27 +
.../types/graph_episode_list_request.py | 45 ++
src/zep_cloud/types/graph_node_neighbor.py | 22 +
.../types/graph_subgraph_response.py | 41 ++
src/zep_cloud/types/property_filter.py | 2 +-
src/zep_cloud/types/search_filters.py | 45 +-
17 files changed, 2307 insertions(+), 27 deletions(-)
create mode 100644 src/zep_cloud/types/graph_episode_list_request.py
create mode 100644 src/zep_cloud/types/graph_node_neighbor.py
create mode 100644 src/zep_cloud/types/graph_subgraph_response.py
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:
From c1c5d5a6243ffb9940e5781c08ccb7f70a5a9496 Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Tue, 11 Aug 2026 20:04:55 +0000
Subject: [PATCH 2/3] [fern-replay] advance lockfile
---
.fern/replay.lock | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/.fern/replay.lock b/.fern/replay.lock
index 9c4b29f..afed4a4 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: 8a3fb853912eadd78157bed5f9811ae936e834a8
+ tree_hash: a5aa6b923d390b275f7e12ca55ba9b44d0689ffd
+ timestamp: 2026-08-11T20:04:50.130Z
+ cli_version: unknown
+ generator_versions:
+ fernapi/fern-python-sdk: 4.25.5
+current_generation: 8a3fb853912eadd78157bed5f9811ae936e834a8
patches: []
From d7c6dc7eca3defae629f1dc2c4b7381f386bd379 Mon Sep 17 00:00:00 2001
From: "zep-sdk-release-bot[bot]"
Date: Tue, 11 Aug 2026 20:05:04 +0000
Subject: [PATCH 3/3] chore: bump SDK version to 3.28.0
---
pyproject.toml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
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 = []