From 2d58b9980e65540eb84f0aa8ae9a56a161f9cfac Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Wed, 23 Sep 2026 18:32:18 +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 | 350 +++++++++++++++++-
src/zep_cloud/__init__.py | 2 +
src/zep_cloud/batch/client.py | 18 +-
src/zep_cloud/batch/raw_client.py | 10 +
src/zep_cloud/core/client_wrapper.py | 4 +-
src/zep_cloud/graph/__init__.py | 4 +-
src/zep_cloud/graph/client.py | 138 ++++++-
.../graph/document_summary/__init__.py | 4 +
.../graph/document_summary/client.py | 196 ++++++++++
.../graph/document_summary/raw_client.py | 271 ++++++++++++++
src/zep_cloud/graph/episode/client.py | 41 +-
src/zep_cloud/graph/episode/raw_client.py | 50 ++-
src/zep_cloud/graph/node/client.py | 8 +-
src/zep_cloud/graph/node/raw_client.py | 8 +-
src/zep_cloud/graph/raw_client.py | 211 ++++++++++-
src/zep_cloud/thread/client.py | 75 ++++
src/zep_cloud/thread/message/client.py | 2 +
src/zep_cloud/thread/message/raw_client.py | 2 +
src/zep_cloud/thread/raw_client.py | 153 ++++++++
src/zep_cloud/types/__init__.py | 2 +
src/zep_cloud/types/batch_add_item.py | 6 +
src/zep_cloud/types/batch_item_detail.py | 1 +
src/zep_cloud/types/batch_summary.py | 1 +
src/zep_cloud/types/document_summary.py | 51 +++
src/zep_cloud/types/entity_edge.py | 14 +-
src/zep_cloud/types/entity_node.py | 15 +
src/zep_cloud/types/episode.py | 5 +
src/zep_cloud/types/graph.py | 7 +
.../types/graph_episode_list_request.py | 19 +-
src/zep_cloud/types/message.py | 2 +-
src/zep_cloud/types/thread.py | 5 +
.../types/thread_context_response.py | 2 +-
src/zep_cloud/types/thread_summary.py | 2 +-
src/zep_cloud/types/user.py | 6 +
34 files changed, 1639 insertions(+), 46 deletions(-)
create mode 100644 src/zep_cloud/graph/document_summary/__init__.py
create mode 100644 src/zep_cloud/graph/document_summary/client.py
create mode 100644 src/zep_cloud/graph/document_summary/raw_client.py
create mode 100644 src/zep_cloud/types/document_summary.py
diff --git a/reference.md b/reference.md
index d9dba041..18eb3175 100644
--- a/reference.md
+++ b/reference.md
@@ -1218,6 +1218,14 @@ Has no effect on graph_episode items.
-
+**strict_ontology:** `typing.Optional[bool]` — When true, prevents extraction of generic Entity nodes that do not match the configured ontology.
+
+
+
+
+
+-
+
**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -2480,6 +2488,17 @@ client.graph.add(
-
+**document_id:** `typing.Optional[str]`
+
+Optional document ID that groups episodes as chunks of the same document
+on a graph. Parallel to thread_id for message threads.
+
+
+
+
+
+-
+
**graph_id:** `typing.Optional[str]` — graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -2597,6 +2616,14 @@ client.graph.add_batch(
-
+**document_id:** `typing.Optional[str]` — Optional document ID applied to every episode in this batch request.
+
+
+
+
+
+-
+
**graph_id:** `typing.Optional[str]` — graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -3062,6 +3089,85 @@ client.graph.create(
+
+
+
+
+client.graph.get_episodes_for_document(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns episodes associated with a document on a graph. Documents group episodes as chunks, parallel to how threads group messages.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from zep_cloud import Zep
+
+client = Zep(
+ api_key="YOUR_API_KEY",
+)
+client.graph.get_episodes_for_document(
+ document_id="document_id",
+ graph_id="graph_id",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**document_id:** `str` — Document ID
+
+
+
+
+
+-
+
+**graph_id:** `str` — Graph ID
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -3078,7 +3184,14 @@ client.graph.create(
-
-Returns all graphs. In order to list users, use user.list_ordered instead
+Returns a paginated directory of live standalone graphs in the
+authenticated project. Optional `search` matches `graph_id`, `name`, and
+`description` (metadata only; not graph contents).
+
+Default `pageSize` is 50 (range 1–100). To list users, use
+`user.list_ordered` instead. See the
+[graph directory guide](/graph-directory) for pagination, relevance
+ordering, and Memory MCP exposure.
@@ -3274,6 +3387,7 @@ client.graph.add_nodes(
-
+Deprecated. Pattern detection is not part of Public API v4.
Detects structural patterns in a knowledge graph including relationship frequencies,
multi-hop paths, co-occurrences, hubs, and clusters.
When a query is provided, uses hybrid search to discover seed nodes,
@@ -3710,7 +3824,7 @@ Maximum number of nodes in the response, including admitted seeds.
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).
+rejected: it cannot be enforced during graph traversal.
@@ -4741,6 +4855,76 @@ client.thread.get_user_context(
+
+
+
+
+client.thread.get_episodes(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns graph episodes associated with a thread. Parallel to get_episodes_for_document for documents.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from zep_cloud import Zep
+
+client = Zep(
+ api_key="YOUR_API_KEY",
+)
+client.thread.get_episodes(
+ thread_id="threadId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**thread_id:** `str` — The ID of the thread
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -6056,6 +6240,132 @@ client.user.warm(
+
+
+
+
+## Graph DocumentSummary
+client.graph.document_summary.get_by_graph_id(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns incremental document summaries associated with the graph. Document summaries are derived similarly to thread summaries.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from zep_cloud import Zep
+
+client = Zep(
+ api_key="YOUR_API_KEY",
+)
+client.graph.document_summary.get_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. Encodes the sort field, direction, and continuation position.
+
+
+
+
+
+-
+
+**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc" (default "desc").
+
+
+
+
+
+-
+
+**filters:** `typing.Optional[SearchFilters]` — Optional filters applied to the listed artifacts. Reuses the graph.search filter type.
+
+
+
+
+
+-
+
+**limit:** `typing.Optional[int]` — Maximum number of items to return
+
+
+
+
+
+-
+
+**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid").
+
+
+
+
+
+-
+
+**uuid_cursor:** `typing.Optional[str]`
+
+UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page.
+
+Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -6726,6 +7036,17 @@ response header of the previous page.
-
+**episode_metadata_filters:** `typing.Optional[MetadataFilterGroup]`
+
+Restricts results to episodes whose stored metadata matches this
+predicate. Same type and limits as graph.search episode_metadata_filters.
+
+
+
+
+
+-
+
**limit:** `typing.Optional[int]`
Maximum number of episodes to return. An explicit value is clamped to
@@ -6740,7 +7061,9 @@ Maximum number of episodes to return. An explicit value is clamped to
**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.
+UUIDs. The list can also contain episode UUIDs: an episode UUID
+matches that episode, so one request can return a known set of
+episodes. At most 256 entries; each must be a syntactically valid UUID.
@@ -6924,6 +7247,17 @@ response header of the previous page.
-
+**episode_metadata_filters:** `typing.Optional[MetadataFilterGroup]`
+
+Restricts results to episodes whose stored metadata matches this
+predicate. Same type and limits as graph.search episode_metadata_filters.
+
+
+
+
+
+-
+
**limit:** `typing.Optional[int]`
Maximum number of episodes to return. An explicit value is clamped to
@@ -6938,7 +7272,9 @@ Maximum number of episodes to return. An explicit value is clamped to
**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.
+UUIDs. The list can also contain episode UUIDs: an episode UUID
+matches that episode, so one request can return a known set of
+episodes. At most 256 entries; each must be a syntactically valid UUID.
@@ -7588,7 +7924,7 @@ client.graph.node.get_edges(
-
-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.
+Deprecated. Read the `episodes` field on the node; when `episodes_truncated` is true, use the episode list SDK methods `graph.episode.list_by_graph_id` or `graph.episode.list_by_user_id` with the `mentioned_node_uuids` filter. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
@@ -7742,7 +8078,7 @@ 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- and episode-anchored UUID fields) and the neighbor nodes
(node_labels/exclude_node_labels). Reuses the graph.search filter
type.
@@ -8660,7 +8996,7 @@ client.thread.message.update(
-
-**metadata:** `typing.Dict[str, typing.Optional[typing.Any]]`
+**metadata:** `typing.Dict[str, typing.Optional[typing.Any]]` — Metadata to store on the message. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars.
diff --git a/src/zep_cloud/__init__.py b/src/zep_cloud/__init__.py
index 9b7b03c9..98bdfb33 100644
--- a/src/zep_cloud/__init__.py
+++ b/src/zep_cloud/__init__.py
@@ -32,6 +32,7 @@
DerivedNode,
DetectConfig,
DetectPatternsResponse,
+ DocumentSummary,
EdgeType,
EntityEdge,
EntityEdgeSourceTarget,
@@ -143,6 +144,7 @@
"DerivedNode",
"DetectConfig",
"DetectPatternsResponse",
+ "DocumentSummary",
"EdgeType",
"EntityEdge",
"EntityEdgeSourceTarget",
diff --git a/src/zep_cloud/batch/client.py b/src/zep_cloud/batch/client.py
index 4b56e20a..66b1c9e2 100644
--- a/src/zep_cloud/batch/client.py
+++ b/src/zep_cloud/batch/client.py
@@ -83,6 +83,7 @@ def create(
*,
ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
+ strict_ontology: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> BatchSummary:
"""
@@ -98,6 +99,9 @@ def create(
metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
+ strict_ontology : typing.Optional[bool]
+ When true, prevents extraction of generic Entity nodes that do not match the configured ontology.
+
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -116,7 +120,10 @@ def create(
client.batch.create()
"""
_response = self._raw_client.create(
- ignore_roles=ignore_roles, metadata=metadata, request_options=request_options
+ ignore_roles=ignore_roles,
+ metadata=metadata,
+ strict_ontology=strict_ontology,
+ request_options=request_options,
)
return _response.data
@@ -387,6 +394,7 @@ async def create(
*,
ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
+ strict_ontology: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> BatchSummary:
"""
@@ -402,6 +410,9 @@ async def create(
metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
+ strict_ontology : typing.Optional[bool]
+ When true, prevents extraction of generic Entity nodes that do not match the configured ontology.
+
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -428,7 +439,10 @@ async def main() -> None:
asyncio.run(main())
"""
_response = await self._raw_client.create(
- ignore_roles=ignore_roles, metadata=metadata, request_options=request_options
+ ignore_roles=ignore_roles,
+ metadata=metadata,
+ strict_ontology=strict_ontology,
+ request_options=request_options,
)
return _response.data
diff --git a/src/zep_cloud/batch/raw_client.py b/src/zep_cloud/batch/raw_client.py
index d530e651..7765bac3 100644
--- a/src/zep_cloud/batch/raw_client.py
+++ b/src/zep_cloud/batch/raw_client.py
@@ -129,6 +129,7 @@ def create(
*,
ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
+ strict_ontology: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> HttpResponse[BatchSummary]:
"""
@@ -144,6 +145,9 @@ def create(
metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
+ strict_ontology : typing.Optional[bool]
+ When true, prevents extraction of generic Entity nodes that do not match the configured ontology.
+
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -158,6 +162,7 @@ def create(
json={
"ignore_roles": ignore_roles,
"metadata": metadata,
+ "strict_ontology": strict_ontology,
},
headers={
"content-type": "application/json",
@@ -822,6 +827,7 @@ async def create(
*,
ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
+ strict_ontology: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> AsyncHttpResponse[BatchSummary]:
"""
@@ -837,6 +843,9 @@ async def create(
metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
+ strict_ontology : typing.Optional[bool]
+ When true, prevents extraction of generic Entity nodes that do not match the configured ontology.
+
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -851,6 +860,7 @@ async def create(
json={
"ignore_roles": ignore_roles,
"metadata": metadata,
+ "strict_ontology": strict_ontology,
},
headers={
"content-type": "application/json",
diff --git a/src/zep_cloud/core/client_wrapper.py b/src/zep_cloud/core/client_wrapper.py
index dde7c3ad..e4684068 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.28.0",
+ "User-Agent": "zep-cloud/3.29.0",
"X-Fern-Language": "Python",
"X-Fern-SDK-Name": "zep-cloud",
- "X-Fern-SDK-Version": "3.28.0",
+ "X-Fern-SDK-Version": "3.29.0",
**(self.get_custom_headers() or {}),
}
headers["Authorization"] = f"Api-Key {self.api_key}"
diff --git a/src/zep_cloud/graph/__init__.py b/src/zep_cloud/graph/__init__.py
index 49f0683f..ff7e8d17 100644
--- a/src/zep_cloud/graph/__init__.py
+++ b/src/zep_cloud/graph/__init__.py
@@ -2,6 +2,6 @@
# isort: skip_file
-from . import edge, episode, node, observation, thread_summary
+from . import document_summary, edge, episode, node, observation, thread_summary
-__all__ = ["edge", "episode", "node", "observation", "thread_summary"]
+__all__ = ["document_summary", "edge", "episode", "node", "observation", "thread_summary"]
diff --git a/src/zep_cloud/graph/client.py b/src/zep_cloud/graph/client.py
index 0e12d30d..2d518b2b 100644
--- a/src/zep_cloud/graph/client.py
+++ b/src/zep_cloud/graph/client.py
@@ -16,6 +16,7 @@
from ..types.entity_type_response import EntityTypeResponse
from ..types.episode import Episode
from ..types.episode_data import EpisodeData
+from ..types.episode_response import EpisodeResponse
from ..types.graph import Graph
from ..types.graph_data_type import GraphDataType
from ..types.graph_list_response import GraphListResponse
@@ -28,6 +29,7 @@
from ..types.reranker import Reranker
from ..types.search_filters import SearchFilters
from ..types.success_response import SuccessResponse
+from .document_summary.client import AsyncDocumentSummaryClient, DocumentSummaryClient
from .edge.client import AsyncEdgeClient, EdgeClient
from .episode.client import AsyncEpisodeClient, EpisodeClient
from .node.client import AsyncNodeClient, NodeClient
@@ -42,6 +44,8 @@
class GraphClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._raw_client = RawGraphClient(client_wrapper=client_wrapper)
+ self.document_summary = DocumentSummaryClient(client_wrapper=client_wrapper)
+
self.edge = EdgeClient(client_wrapper=client_wrapper)
self.episode = EpisodeClient(client_wrapper=client_wrapper)
@@ -298,6 +302,7 @@ def add(
data: str,
type: GraphDataType,
created_at: typing.Optional[str] = OMIT,
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
source_description: typing.Optional[str] = OMIT,
@@ -316,6 +321,10 @@ def add(
created_at : typing.Optional[str]
+ document_id : typing.Optional[str]
+ Optional document ID that groups episodes as chunks of the same document
+ on a graph. Parallel to thread_id for message threads.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -354,6 +363,7 @@ def add(
data=data,
type=type,
created_at=created_at,
+ document_id=document_id,
graph_id=graph_id,
metadata=metadata,
source_description=source_description,
@@ -367,6 +377,7 @@ def add_batch(
self,
*,
episodes: typing.Sequence[EpisodeData],
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
strict_ontology: typing.Optional[bool] = OMIT,
user_id: typing.Optional[str] = OMIT,
@@ -381,6 +392,9 @@ def add_batch(
----------
episodes : typing.Sequence[EpisodeData]
+ document_id : typing.Optional[str]
+ Optional document ID applied to every episode in this batch request.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -416,6 +430,7 @@ def add_batch(
"""
_response = self._raw_client.add_batch(
episodes=episodes,
+ document_id=document_id,
graph_id=graph_id,
strict_ontology=strict_ontology,
user_id=user_id,
@@ -667,6 +682,45 @@ def create(
)
return _response.data
+ def get_episodes_for_document(
+ self, document_id: str, *, graph_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> EpisodeResponse:
+ """
+ Returns episodes associated with a document on a graph. Documents group episodes as chunks, parallel to how threads group messages.
+
+ Parameters
+ ----------
+ document_id : str
+ Document ID
+
+ graph_id : str
+ Graph ID
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ EpisodeResponse
+ Episodes
+
+ Examples
+ --------
+ from zep_cloud import Zep
+
+ client = Zep(
+ api_key="YOUR_API_KEY",
+ )
+ client.graph.get_episodes_for_document(
+ document_id="document_id",
+ graph_id="graph_id",
+ )
+ """
+ _response = self._raw_client.get_episodes_for_document(
+ document_id, graph_id=graph_id, request_options=request_options
+ )
+ return _response.data
+
def list_all(
self,
*,
@@ -678,7 +732,14 @@ def list_all(
request_options: typing.Optional[RequestOptions] = None,
) -> GraphListResponse:
"""
- Returns all graphs. In order to list users, use user.list_ordered instead
+ Returns a paginated directory of live standalone graphs in the
+ authenticated project. Optional `search` matches `graph_id`, `name`, and
+ `description` (metadata only; not graph contents).
+
+ Default `pageSize` is 50 (range 1–100). To list users, use
+ `user.list_ordered` instead. See the
+ [graph directory guide](/graph-directory) for pagination, relevance
+ ordering, and Memory MCP exposure.
Parameters
----------
@@ -795,6 +856,7 @@ def detect_patterns(
request_options: typing.Optional[RequestOptions] = None,
) -> DetectPatternsResponse:
"""
+ Deprecated. Pattern detection is not part of Public API v4.
Detects structural patterns in a knowledge graph including relationship frequencies,
multi-hop paths, co-occurrences, hubs, and clusters.
When a query is provided, uses hybrid search to discover seed nodes,
@@ -1018,7 +1080,7 @@ def get_subgraph(
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).
+ rejected: it cannot be enforced during graph traversal.
user_id : typing.Optional[str]
user_id identifies the target user graph. Exactly one of user_id or
@@ -1201,6 +1263,8 @@ def warm(self, graph_id: str, *, request_options: typing.Optional[RequestOptions
class AsyncGraphClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
self._raw_client = AsyncRawGraphClient(client_wrapper=client_wrapper)
+ self.document_summary = AsyncDocumentSummaryClient(client_wrapper=client_wrapper)
+
self.edge = AsyncEdgeClient(client_wrapper=client_wrapper)
self.episode = AsyncEpisodeClient(client_wrapper=client_wrapper)
@@ -1497,6 +1561,7 @@ async def add(
data: str,
type: GraphDataType,
created_at: typing.Optional[str] = OMIT,
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
source_description: typing.Optional[str] = OMIT,
@@ -1515,6 +1580,10 @@ async def add(
created_at : typing.Optional[str]
+ document_id : typing.Optional[str]
+ Optional document ID that groups episodes as chunks of the same document
+ on a graph. Parallel to thread_id for message threads.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -1561,6 +1630,7 @@ async def main() -> None:
data=data,
type=type,
created_at=created_at,
+ document_id=document_id,
graph_id=graph_id,
metadata=metadata,
source_description=source_description,
@@ -1574,6 +1644,7 @@ async def add_batch(
self,
*,
episodes: typing.Sequence[EpisodeData],
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
strict_ontology: typing.Optional[bool] = OMIT,
user_id: typing.Optional[str] = OMIT,
@@ -1588,6 +1659,9 @@ async def add_batch(
----------
episodes : typing.Sequence[EpisodeData]
+ document_id : typing.Optional[str]
+ Optional document ID applied to every episode in this batch request.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -1631,6 +1705,7 @@ async def main() -> None:
"""
_response = await self._raw_client.add_batch(
episodes=episodes,
+ document_id=document_id,
graph_id=graph_id,
strict_ontology=strict_ontology,
user_id=user_id,
@@ -1906,6 +1981,53 @@ async def main() -> None:
)
return _response.data
+ async def get_episodes_for_document(
+ self, document_id: str, *, graph_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> EpisodeResponse:
+ """
+ Returns episodes associated with a document on a graph. Documents group episodes as chunks, parallel to how threads group messages.
+
+ Parameters
+ ----------
+ document_id : str
+ Document ID
+
+ graph_id : str
+ Graph ID
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ EpisodeResponse
+ Episodes
+
+ Examples
+ --------
+ import asyncio
+
+ from zep_cloud import AsyncZep
+
+ client = AsyncZep(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.graph.get_episodes_for_document(
+ document_id="document_id",
+ graph_id="graph_id",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_episodes_for_document(
+ document_id, graph_id=graph_id, request_options=request_options
+ )
+ return _response.data
+
async def list_all(
self,
*,
@@ -1917,7 +2039,14 @@ async def list_all(
request_options: typing.Optional[RequestOptions] = None,
) -> GraphListResponse:
"""
- Returns all graphs. In order to list users, use user.list_ordered instead
+ Returns a paginated directory of live standalone graphs in the
+ authenticated project. Optional `search` matches `graph_id`, `name`, and
+ `description` (metadata only; not graph contents).
+
+ Default `pageSize` is 50 (range 1–100). To list users, use
+ `user.list_ordered` instead. See the
+ [graph directory guide](/graph-directory) for pagination, relevance
+ ordering, and Memory MCP exposure.
Parameters
----------
@@ -2050,6 +2179,7 @@ async def detect_patterns(
request_options: typing.Optional[RequestOptions] = None,
) -> DetectPatternsResponse:
"""
+ Deprecated. Pattern detection is not part of Public API v4.
Detects structural patterns in a knowledge graph including relationship frequencies,
multi-hop paths, co-occurrences, hubs, and clusters.
When a query is provided, uses hybrid search to discover seed nodes,
@@ -2289,7 +2419,7 @@ async def get_subgraph(
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).
+ rejected: it cannot be enforced during graph traversal.
user_id : typing.Optional[str]
user_id identifies the target user graph. Exactly one of user_id or
diff --git a/src/zep_cloud/graph/document_summary/__init__.py b/src/zep_cloud/graph/document_summary/__init__.py
new file mode 100644
index 00000000..5cde0202
--- /dev/null
+++ b/src/zep_cloud/graph/document_summary/__init__.py
@@ -0,0 +1,4 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
diff --git a/src/zep_cloud/graph/document_summary/client.py b/src/zep_cloud/graph/document_summary/client.py
new file mode 100644
index 00000000..8a771fcb
--- /dev/null
+++ b/src/zep_cloud/graph/document_summary/client.py
@@ -0,0 +1,196 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.request_options import RequestOptions
+from ...types.document_summary import DocumentSummary
+from ...types.search_filters import SearchFilters
+from .raw_client import AsyncRawDocumentSummaryClient, RawDocumentSummaryClient
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class DocumentSummaryClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawDocumentSummaryClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawDocumentSummaryClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawDocumentSummaryClient
+ """
+ return self._raw_client
+
+ def get_by_graph_id(
+ self,
+ graph_id: str,
+ *,
+ cursor: typing.Optional[str] = OMIT,
+ direction: typing.Optional[str] = OMIT,
+ filters: typing.Optional[SearchFilters] = OMIT,
+ limit: typing.Optional[int] = OMIT,
+ order_by: typing.Optional[str] = OMIT,
+ uuid_cursor: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> typing.List[DocumentSummary]:
+ """
+ Returns incremental document summaries associated with the graph. Document summaries are derived similarly to thread summaries.
+
+ 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. Encodes the sort field, direction, and continuation position.
+
+ direction : typing.Optional[str]
+ Sort direction. One of "asc" or "desc" (default "desc").
+
+ filters : typing.Optional[SearchFilters]
+ Optional filters applied to the listed artifacts. Reuses the graph.search filter type.
+
+ limit : typing.Optional[int]
+ Maximum number of items to return
+
+ order_by : typing.Optional[str]
+ Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid").
+
+ uuid_cursor : typing.Optional[str]
+ UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page.
+
+ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[DocumentSummary]
+ Document summaries
+
+ Examples
+ --------
+ from zep_cloud import Zep
+
+ client = Zep(
+ api_key="YOUR_API_KEY",
+ )
+ client.graph.document_summary.get_by_graph_id(
+ graph_id="graph_id",
+ )
+ """
+ _response = self._raw_client.get_by_graph_id(
+ graph_id,
+ cursor=cursor,
+ direction=direction,
+ filters=filters,
+ limit=limit,
+ order_by=order_by,
+ uuid_cursor=uuid_cursor,
+ request_options=request_options,
+ )
+ return _response.data
+
+
+class AsyncDocumentSummaryClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawDocumentSummaryClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawDocumentSummaryClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawDocumentSummaryClient
+ """
+ return self._raw_client
+
+ async def get_by_graph_id(
+ self,
+ graph_id: str,
+ *,
+ cursor: typing.Optional[str] = OMIT,
+ direction: typing.Optional[str] = OMIT,
+ filters: typing.Optional[SearchFilters] = OMIT,
+ limit: typing.Optional[int] = OMIT,
+ order_by: typing.Optional[str] = OMIT,
+ uuid_cursor: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> typing.List[DocumentSummary]:
+ """
+ Returns incremental document summaries associated with the graph. Document summaries are derived similarly to thread summaries.
+
+ 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. Encodes the sort field, direction, and continuation position.
+
+ direction : typing.Optional[str]
+ Sort direction. One of "asc" or "desc" (default "desc").
+
+ filters : typing.Optional[SearchFilters]
+ Optional filters applied to the listed artifacts. Reuses the graph.search filter type.
+
+ limit : typing.Optional[int]
+ Maximum number of items to return
+
+ order_by : typing.Optional[str]
+ Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid").
+
+ uuid_cursor : typing.Optional[str]
+ UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page.
+
+ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ typing.List[DocumentSummary]
+ Document summaries
+
+ Examples
+ --------
+ import asyncio
+
+ from zep_cloud import AsyncZep
+
+ client = AsyncZep(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.graph.document_summary.get_by_graph_id(
+ graph_id="graph_id",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_by_graph_id(
+ graph_id,
+ cursor=cursor,
+ direction=direction,
+ filters=filters,
+ limit=limit,
+ order_by=order_by,
+ uuid_cursor=uuid_cursor,
+ request_options=request_options,
+ )
+ return _response.data
diff --git a/src/zep_cloud/graph/document_summary/raw_client.py b/src/zep_cloud/graph/document_summary/raw_client.py
new file mode 100644
index 00000000..c6ffd1f0
--- /dev/null
+++ b/src/zep_cloud/graph/document_summary/raw_client.py
@@ -0,0 +1,271 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError as core_api_error_ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
+from ...errors.bad_request_error import BadRequestError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...types.api_error import ApiError as types_api_error_ApiError
+from ...types.document_summary import DocumentSummary
+from ...types.search_filters import SearchFilters
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawDocumentSummaryClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_by_graph_id(
+ self,
+ graph_id: str,
+ *,
+ cursor: typing.Optional[str] = OMIT,
+ direction: typing.Optional[str] = OMIT,
+ filters: typing.Optional[SearchFilters] = OMIT,
+ limit: typing.Optional[int] = OMIT,
+ order_by: typing.Optional[str] = OMIT,
+ uuid_cursor: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[typing.List[DocumentSummary]]:
+ """
+ Returns incremental document summaries associated with the graph. Document summaries are derived similarly to thread summaries.
+
+ 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. Encodes the sort field, direction, and continuation position.
+
+ direction : typing.Optional[str]
+ Sort direction. One of "asc" or "desc" (default "desc").
+
+ filters : typing.Optional[SearchFilters]
+ Optional filters applied to the listed artifacts. Reuses the graph.search filter type.
+
+ limit : typing.Optional[int]
+ Maximum number of items to return
+
+ order_by : typing.Optional[str]
+ Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid").
+
+ uuid_cursor : typing.Optional[str]
+ UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page.
+
+ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[typing.List[DocumentSummary]]
+ Document summaries
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"graph/document-summary/graph/{jsonable_encoder(graph_id)}",
+ method="POST",
+ json={
+ "cursor": cursor,
+ "direction": direction,
+ "filters": convert_and_respect_annotation_metadata(
+ object_=filters, annotation=SearchFilters, direction="write"
+ ),
+ "limit": limit,
+ "order_by": order_by,
+ "uuid_cursor": uuid_cursor,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ typing.List[DocumentSummary],
+ parse_obj_as(
+ type_=typing.List[DocumentSummary], # 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
+ )
+
+
+class AsyncRawDocumentSummaryClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_by_graph_id(
+ self,
+ graph_id: str,
+ *,
+ cursor: typing.Optional[str] = OMIT,
+ direction: typing.Optional[str] = OMIT,
+ filters: typing.Optional[SearchFilters] = OMIT,
+ limit: typing.Optional[int] = OMIT,
+ order_by: typing.Optional[str] = OMIT,
+ uuid_cursor: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[typing.List[DocumentSummary]]:
+ """
+ Returns incremental document summaries associated with the graph. Document summaries are derived similarly to thread summaries.
+
+ 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. Encodes the sort field, direction, and continuation position.
+
+ direction : typing.Optional[str]
+ Sort direction. One of "asc" or "desc" (default "desc").
+
+ filters : typing.Optional[SearchFilters]
+ Optional filters applied to the listed artifacts. Reuses the graph.search filter type.
+
+ limit : typing.Optional[int]
+ Maximum number of items to return
+
+ order_by : typing.Optional[str]
+ Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid").
+
+ uuid_cursor : typing.Optional[str]
+ UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page.
+
+ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[typing.List[DocumentSummary]]
+ Document summaries
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"graph/document-summary/graph/{jsonable_encoder(graph_id)}",
+ method="POST",
+ json={
+ "cursor": cursor,
+ "direction": direction,
+ "filters": convert_and_respect_annotation_metadata(
+ object_=filters, annotation=SearchFilters, direction="write"
+ ),
+ "limit": limit,
+ "order_by": order_by,
+ "uuid_cursor": uuid_cursor,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ typing.List[DocumentSummary],
+ parse_obj_as(
+ type_=typing.List[DocumentSummary], # 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
+ )
diff --git a/src/zep_cloud/graph/episode/client.py b/src/zep_cloud/graph/episode/client.py
index 06419888..cee42952 100644
--- a/src/zep_cloud/graph/episode/client.py
+++ b/src/zep_cloud/graph/episode/client.py
@@ -7,6 +7,7 @@
from ...types.episode import Episode
from ...types.episode_mentions import EpisodeMentions
from ...types.episode_response import EpisodeResponse
+from ...types.metadata_filter_group import MetadataFilterGroup
from ...types.success_response import SuccessResponse
from .raw_client import AsyncRawEpisodeClient, RawEpisodeClient
@@ -76,6 +77,7 @@ def list_by_graph_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -96,13 +98,19 @@ def list_by_graph_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -130,6 +138,7 @@ def list_by_graph_id(
graph_id,
cursor=cursor,
direction=direction,
+ episode_metadata_filters=episode_metadata_filters,
limit=limit,
mentioned_node_uuids=mentioned_node_uuids,
order_by=order_by,
@@ -184,6 +193,7 @@ def list_by_user_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -204,13 +214,19 @@ def list_by_user_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -238,6 +254,7 @@ def list_by_user_id(
user_id,
cursor=cursor,
direction=direction,
+ episode_metadata_filters=episode_metadata_filters,
limit=limit,
mentioned_node_uuids=mentioned_node_uuids,
order_by=order_by,
@@ -452,6 +469,7 @@ async def list_by_graph_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -472,13 +490,19 @@ async def list_by_graph_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -514,6 +538,7 @@ async def main() -> None:
graph_id,
cursor=cursor,
direction=direction,
+ episode_metadata_filters=episode_metadata_filters,
limit=limit,
mentioned_node_uuids=mentioned_node_uuids,
order_by=order_by,
@@ -576,6 +601,7 @@ async def list_by_user_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -596,13 +622,19 @@ async def list_by_user_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -638,6 +670,7 @@ async def main() -> None:
user_id,
cursor=cursor,
direction=direction,
+ episode_metadata_filters=episode_metadata_filters,
limit=limit,
mentioned_node_uuids=mentioned_node_uuids,
order_by=order_by,
diff --git a/src/zep_cloud/graph/episode/raw_client.py b/src/zep_cloud/graph/episode/raw_client.py
index 0c449529..1ae6fd2c 100644
--- a/src/zep_cloud/graph/episode/raw_client.py
+++ b/src/zep_cloud/graph/episode/raw_client.py
@@ -9,6 +9,7 @@
from ...core.jsonable_encoder import jsonable_encoder
from ...core.pydantic_utilities import parse_obj_as
from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
from ...errors.bad_request_error import BadRequestError
from ...errors.forbidden_error import ForbiddenError
from ...errors.internal_server_error import InternalServerError
@@ -17,6 +18,7 @@
from ...types.episode import Episode
from ...types.episode_mentions import EpisodeMentions
from ...types.episode_response import EpisodeResponse
+from ...types.metadata_filter_group import MetadataFilterGroup
from ...types.success_response import SuccessResponse
# this is used as the default value for optional parameters
@@ -108,6 +110,7 @@ def list_by_graph_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -128,13 +131,19 @@ def list_by_graph_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -153,6 +162,9 @@ def list_by_graph_id(
json={
"cursor": cursor,
"direction": direction,
+ "episode_metadata_filters": convert_and_respect_annotation_metadata(
+ object_=episode_metadata_filters, annotation=MetadataFilterGroup, direction="write"
+ ),
"limit": limit,
"mentioned_node_uuids": mentioned_node_uuids,
"order_by": order_by,
@@ -282,6 +294,7 @@ def list_by_user_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -302,13 +315,19 @@ def list_by_user_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -327,6 +346,9 @@ def list_by_user_id(
json={
"cursor": cursor,
"direction": direction,
+ "episode_metadata_filters": convert_and_respect_annotation_metadata(
+ object_=episode_metadata_filters, annotation=MetadataFilterGroup, direction="write"
+ ),
"limit": limit,
"mentioned_node_uuids": mentioned_node_uuids,
"order_by": order_by,
@@ -766,6 +788,7 @@ async def list_by_graph_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -786,13 +809,19 @@ async def list_by_graph_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -811,6 +840,9 @@ async def list_by_graph_id(
json={
"cursor": cursor,
"direction": direction,
+ "episode_metadata_filters": convert_and_respect_annotation_metadata(
+ object_=episode_metadata_filters, annotation=MetadataFilterGroup, direction="write"
+ ),
"limit": limit,
"mentioned_node_uuids": mentioned_node_uuids,
"order_by": order_by,
@@ -940,6 +972,7 @@ async def list_by_user_id(
*,
cursor: typing.Optional[str] = OMIT,
direction: typing.Optional[str] = OMIT,
+ episode_metadata_filters: typing.Optional[MetadataFilterGroup] = OMIT,
limit: typing.Optional[int] = OMIT,
mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT,
order_by: typing.Optional[str] = OMIT,
@@ -960,13 +993,19 @@ async def list_by_user_id(
direction : typing.Optional[str]
Sort direction. One of "asc" or "desc". Defaults to "desc".
+ episode_metadata_filters : typing.Optional[MetadataFilterGroup]
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. 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".
@@ -985,6 +1024,9 @@ async def list_by_user_id(
json={
"cursor": cursor,
"direction": direction,
+ "episode_metadata_filters": convert_and_respect_annotation_metadata(
+ object_=episode_metadata_filters, annotation=MetadataFilterGroup, direction="write"
+ ),
"limit": limit,
"mentioned_node_uuids": mentioned_node_uuids,
"order_by": order_by,
diff --git a/src/zep_cloud/graph/node/client.py b/src/zep_cloud/graph/node/client.py
index 8fafd397..3cd22131 100644
--- a/src/zep_cloud/graph/node/client.py
+++ b/src/zep_cloud/graph/node/client.py
@@ -212,7 +212,7 @@ def get_episodes(
self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None
) -> EpisodeResponse:
"""
- 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.
+ Deprecated. Read the `episodes` field on the node; when `episodes_truncated` is true, use the episode list SDK methods `graph.episode.list_by_graph_id` or `graph.episode.list_by_user_id` with the `mentioned_node_uuids` filter. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
Parameters
----------
@@ -277,7 +277,7 @@ def get_neighbors(
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- and episode-anchored UUID fields) and the neighbor nodes
(node_labels/exclude_node_labels). Reuses the graph.search filter
type.
@@ -657,7 +657,7 @@ async def get_episodes(
self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None
) -> EpisodeResponse:
"""
- 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.
+ Deprecated. Read the `episodes` field on the node; when `episodes_truncated` is true, use the episode list SDK methods `graph.episode.list_by_graph_id` or `graph.episode.list_by_user_id` with the `mentioned_node_uuids` filter. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
Parameters
----------
@@ -730,7 +730,7 @@ async def get_neighbors(
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- and episode-anchored UUID fields) and the neighbor nodes
(node_labels/exclude_node_labels). Reuses the graph.search filter
type.
diff --git a/src/zep_cloud/graph/node/raw_client.py b/src/zep_cloud/graph/node/raw_client.py
index 879bf2f6..20e6ce39 100644
--- a/src/zep_cloud/graph/node/raw_client.py
+++ b/src/zep_cloud/graph/node/raw_client.py
@@ -310,7 +310,7 @@ def get_episodes(
self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None
) -> HttpResponse[EpisodeResponse]:
"""
- 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.
+ Deprecated. Read the `episodes` field on the node; when `episodes_truncated` is true, use the episode list SDK methods `graph.episode.list_by_graph_id` or `graph.episode.list_by_user_id` with the `mentioned_node_uuids` filter. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
Parameters
----------
@@ -407,7 +407,7 @@ def get_neighbors(
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- and episode-anchored UUID fields) and the neighbor nodes
(node_labels/exclude_node_labels). Reuses the graph.search filter
type.
@@ -1039,7 +1039,7 @@ async def get_episodes(
self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None
) -> AsyncHttpResponse[EpisodeResponse]:
"""
- 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.
+ Deprecated. Read the `episodes` field on the node; when `episodes_truncated` is true, use the episode list SDK methods `graph.episode.list_by_graph_id` or `graph.episode.list_by_user_id` with the `mentioned_node_uuids` filter. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header.
Parameters
----------
@@ -1136,7 +1136,7 @@ async def get_neighbors(
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- and episode-anchored UUID fields) and the neighbor nodes
(node_labels/exclude_node_labels). Reuses the graph.search filter
type.
diff --git a/src/zep_cloud/graph/raw_client.py b/src/zep_cloud/graph/raw_client.py
index 4527e28d..221611e7 100644
--- a/src/zep_cloud/graph/raw_client.py
+++ b/src/zep_cloud/graph/raw_client.py
@@ -27,6 +27,7 @@
from ..types.entity_type_response import EntityTypeResponse
from ..types.episode import Episode
from ..types.episode_data import EpisodeData
+from ..types.episode_response import EpisodeResponse
from ..types.graph import Graph
from ..types.graph_data_type import GraphDataType
from ..types.graph_list_response import GraphListResponse
@@ -523,6 +524,7 @@ def add(
data: str,
type: GraphDataType,
created_at: typing.Optional[str] = OMIT,
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
source_description: typing.Optional[str] = OMIT,
@@ -541,6 +543,10 @@ def add(
created_at : typing.Optional[str]
+ document_id : typing.Optional[str]
+ Optional document ID that groups episodes as chunks of the same document
+ on a graph. Parallel to thread_id for message threads.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -569,6 +575,7 @@ def add(
json={
"created_at": created_at,
"data": data,
+ "document_id": document_id,
"graph_id": graph_id,
"metadata": metadata,
"source_description": source_description,
@@ -627,6 +634,7 @@ def add_batch(
self,
*,
episodes: typing.Sequence[EpisodeData],
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
strict_ontology: typing.Optional[bool] = OMIT,
user_id: typing.Optional[str] = OMIT,
@@ -641,6 +649,9 @@ def add_batch(
----------
episodes : typing.Sequence[EpisodeData]
+ document_id : typing.Optional[str]
+ Optional document ID applied to every episode in this batch request.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -662,6 +673,7 @@ def add_batch(
"graph-batch",
method="POST",
json={
+ "document_id": document_id,
"episodes": convert_and_respect_annotation_metadata(
object_=episodes, annotation=typing.Sequence[EpisodeData], direction="write"
),
@@ -1073,6 +1085,88 @@ def create(
status_code=_response.status_code, headers=dict(_response.headers), body=_response_json
)
+ def get_episodes_for_document(
+ self, document_id: str, *, graph_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[EpisodeResponse]:
+ """
+ Returns episodes associated with a document on a graph. Documents group episodes as chunks, parallel to how threads group messages.
+
+ Parameters
+ ----------
+ document_id : str
+ Document ID
+
+ graph_id : str
+ Graph ID
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[EpisodeResponse]
+ Episodes
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"graph/documents/{jsonable_encoder(document_id)}/episodes",
+ method="GET",
+ params={
+ "graph_id": graph_id,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ EpisodeResponse,
+ parse_obj_as(
+ type_=EpisodeResponse, # 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 list_all(
self,
*,
@@ -1084,7 +1178,14 @@ def list_all(
request_options: typing.Optional[RequestOptions] = None,
) -> HttpResponse[GraphListResponse]:
"""
- Returns all graphs. In order to list users, use user.list_ordered instead
+ Returns a paginated directory of live standalone graphs in the
+ authenticated project. Optional `search` matches `graph_id`, `name`, and
+ `description` (metadata only; not graph contents).
+
+ Default `pageSize` is 50 (range 1–100). To list users, use
+ `user.list_ordered` instead. See the
+ [graph directory guide](/graph-directory) for pagination, relevance
+ ordering, and Memory MCP exposure.
Parameters
----------
@@ -1266,6 +1367,7 @@ def detect_patterns(
request_options: typing.Optional[RequestOptions] = None,
) -> HttpResponse[DetectPatternsResponse]:
"""
+ Deprecated. Pattern detection is not part of Public API v4.
Detects structural patterns in a knowledge graph including relationship frequencies,
multi-hop paths, co-occurrences, hubs, and clusters.
When a query is provided, uses hybrid search to discover seed nodes,
@@ -1593,7 +1695,7 @@ def get_subgraph(
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).
+ rejected: it cannot be enforced during graph traversal.
user_id : typing.Optional[str]
user_id identifies the target user graph. Exactly one of user_id or
@@ -2473,6 +2575,7 @@ async def add(
data: str,
type: GraphDataType,
created_at: typing.Optional[str] = OMIT,
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
source_description: typing.Optional[str] = OMIT,
@@ -2491,6 +2594,10 @@ async def add(
created_at : typing.Optional[str]
+ document_id : typing.Optional[str]
+ Optional document ID that groups episodes as chunks of the same document
+ on a graph. Parallel to thread_id for message threads.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -2519,6 +2626,7 @@ async def add(
json={
"created_at": created_at,
"data": data,
+ "document_id": document_id,
"graph_id": graph_id,
"metadata": metadata,
"source_description": source_description,
@@ -2577,6 +2685,7 @@ async def add_batch(
self,
*,
episodes: typing.Sequence[EpisodeData],
+ document_id: typing.Optional[str] = OMIT,
graph_id: typing.Optional[str] = OMIT,
strict_ontology: typing.Optional[bool] = OMIT,
user_id: typing.Optional[str] = OMIT,
@@ -2591,6 +2700,9 @@ async def add_batch(
----------
episodes : typing.Sequence[EpisodeData]
+ document_id : typing.Optional[str]
+ Optional document ID applied to every episode in this batch request.
+
graph_id : typing.Optional[str]
graph_id is the ID of the graph to which the data will be added. If adding to the user graph, please use user_id field instead.
@@ -2612,6 +2724,7 @@ async def add_batch(
"graph-batch",
method="POST",
json={
+ "document_id": document_id,
"episodes": convert_and_respect_annotation_metadata(
object_=episodes, annotation=typing.Sequence[EpisodeData], direction="write"
),
@@ -3023,6 +3136,88 @@ async def create(
status_code=_response.status_code, headers=dict(_response.headers), body=_response_json
)
+ async def get_episodes_for_document(
+ self, document_id: str, *, graph_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[EpisodeResponse]:
+ """
+ Returns episodes associated with a document on a graph. Documents group episodes as chunks, parallel to how threads group messages.
+
+ Parameters
+ ----------
+ document_id : str
+ Document ID
+
+ graph_id : str
+ Graph ID
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[EpisodeResponse]
+ Episodes
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"graph/documents/{jsonable_encoder(document_id)}/episodes",
+ method="GET",
+ params={
+ "graph_id": graph_id,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ EpisodeResponse,
+ parse_obj_as(
+ type_=EpisodeResponse, # 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 list_all(
self,
*,
@@ -3034,7 +3229,14 @@ async def list_all(
request_options: typing.Optional[RequestOptions] = None,
) -> AsyncHttpResponse[GraphListResponse]:
"""
- Returns all graphs. In order to list users, use user.list_ordered instead
+ Returns a paginated directory of live standalone graphs in the
+ authenticated project. Optional `search` matches `graph_id`, `name`, and
+ `description` (metadata only; not graph contents).
+
+ Default `pageSize` is 50 (range 1–100). To list users, use
+ `user.list_ordered` instead. See the
+ [graph directory guide](/graph-directory) for pagination, relevance
+ ordering, and Memory MCP exposure.
Parameters
----------
@@ -3216,6 +3418,7 @@ async def detect_patterns(
request_options: typing.Optional[RequestOptions] = None,
) -> AsyncHttpResponse[DetectPatternsResponse]:
"""
+ Deprecated. Pattern detection is not part of Public API v4.
Detects structural patterns in a knowledge graph including relationship frequencies,
multi-hop paths, co-occurrences, hubs, and clusters.
When a query is provided, uses hybrid search to discover seed nodes,
@@ -3543,7 +3746,7 @@ async def get_subgraph(
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).
+ rejected: it cannot be enforced during graph traversal.
user_id : typing.Optional[str]
user_id identifies the target user graph. Exactly one of user_id or
diff --git a/src/zep_cloud/thread/client.py b/src/zep_cloud/thread/client.py
index e4a8add5..66e5ab88 100644
--- a/src/zep_cloud/thread/client.py
+++ b/src/zep_cloud/thread/client.py
@@ -5,6 +5,7 @@
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.request_options import RequestOptions
from ..types.add_thread_messages_response import AddThreadMessagesResponse
+from ..types.episode_response import EpisodeResponse
from ..types.message import Message
from ..types.message_list_response import MessageListResponse
from ..types.role_type import RoleType
@@ -200,6 +201,39 @@ def get_user_context(
)
return _response.data
+ def get_episodes(
+ self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> EpisodeResponse:
+ """
+ Returns graph episodes associated with a thread. Parallel to get_episodes_for_document for documents.
+
+ Parameters
+ ----------
+ thread_id : str
+ The ID of the thread
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ EpisodeResponse
+ Episodes
+
+ Examples
+ --------
+ from zep_cloud import Zep
+
+ client = Zep(
+ api_key="YOUR_API_KEY",
+ )
+ client.thread.get_episodes(
+ thread_id="threadId",
+ )
+ """
+ _response = self._raw_client.get_episodes(thread_id, request_options=request_options)
+ return _response.data
+
def get(
self,
thread_id: str,
@@ -635,6 +669,47 @@ async def main() -> None:
)
return _response.data
+ async def get_episodes(
+ self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> EpisodeResponse:
+ """
+ Returns graph episodes associated with a thread. Parallel to get_episodes_for_document for documents.
+
+ Parameters
+ ----------
+ thread_id : str
+ The ID of the thread
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ EpisodeResponse
+ Episodes
+
+ Examples
+ --------
+ import asyncio
+
+ from zep_cloud import AsyncZep
+
+ client = AsyncZep(
+ api_key="YOUR_API_KEY",
+ )
+
+
+ async def main() -> None:
+ await client.thread.get_episodes(
+ thread_id="threadId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_episodes(thread_id, request_options=request_options)
+ return _response.data
+
async def get(
self,
thread_id: str,
diff --git a/src/zep_cloud/thread/message/client.py b/src/zep_cloud/thread/message/client.py
index 0c8adcba..17e3fb9d 100644
--- a/src/zep_cloud/thread/message/client.py
+++ b/src/zep_cloud/thread/message/client.py
@@ -42,6 +42,7 @@ def update(
The UUID of the message.
metadata : typing.Dict[str, typing.Optional[typing.Any]]
+ Metadata to store on the message. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -98,6 +99,7 @@ async def update(
The UUID of the message.
metadata : typing.Dict[str, typing.Optional[typing.Any]]
+ Metadata to store on the message. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
diff --git a/src/zep_cloud/thread/message/raw_client.py b/src/zep_cloud/thread/message/raw_client.py
index 20029489..aa21ec8a 100644
--- a/src/zep_cloud/thread/message/raw_client.py
+++ b/src/zep_cloud/thread/message/raw_client.py
@@ -38,6 +38,7 @@ def update(
The UUID of the message.
metadata : typing.Dict[str, typing.Optional[typing.Any]]
+ Metadata to store on the message. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -121,6 +122,7 @@ async def update(
The UUID of the message.
metadata : typing.Dict[str, typing.Optional[typing.Any]]
+ Metadata to store on the message. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
diff --git a/src/zep_cloud/thread/raw_client.py b/src/zep_cloud/thread/raw_client.py
index 94237e62..6ee7901a 100644
--- a/src/zep_cloud/thread/raw_client.py
+++ b/src/zep_cloud/thread/raw_client.py
@@ -16,6 +16,7 @@
from ..errors.not_found_error import NotFoundError
from ..types.add_thread_messages_response import AddThreadMessagesResponse
from ..types.api_error import ApiError as types_api_error_ApiError
+from ..types.episode_response import EpisodeResponse
from ..types.message import Message
from ..types.message_list_response import MessageListResponse
from ..types.role_type import RoleType
@@ -335,6 +336,82 @@ def get_user_context(
status_code=_response.status_code, headers=dict(_response.headers), body=_response_json
)
+ def get_episodes(
+ self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[EpisodeResponse]:
+ """
+ Returns graph episodes associated with a thread. Parallel to get_episodes_for_document for documents.
+
+ Parameters
+ ----------
+ thread_id : str
+ The ID of the thread
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[EpisodeResponse]
+ Episodes
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"threads/{jsonable_encoder(thread_id)}/episodes",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ EpisodeResponse,
+ parse_obj_as(
+ type_=EpisodeResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ 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,
thread_id: str,
@@ -973,6 +1050,82 @@ async def get_user_context(
status_code=_response.status_code, headers=dict(_response.headers), body=_response_json
)
+ async def get_episodes(
+ self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[EpisodeResponse]:
+ """
+ Returns graph episodes associated with a thread. Parallel to get_episodes_for_document for documents.
+
+ Parameters
+ ----------
+ thread_id : str
+ The ID of the thread
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[EpisodeResponse]
+ Episodes
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"threads/{jsonable_encoder(thread_id)}/episodes",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ EpisodeResponse,
+ parse_obj_as(
+ type_=EpisodeResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ 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,
thread_id: str,
diff --git a/src/zep_cloud/types/__init__.py b/src/zep_cloud/types/__init__.py
index 535b0a0d..9a8e0913 100644
--- a/src/zep_cloud/types/__init__.py
+++ b/src/zep_cloud/types/__init__.py
@@ -31,6 +31,7 @@
from .derived_node import DerivedNode
from .detect_config import DetectConfig
from .detect_patterns_response import DetectPatternsResponse
+from .document_summary import DocumentSummary
from .edge_type import EdgeType
from .entity_edge import EntityEdge
from .entity_edge_source_target import EntityEdgeSourceTarget
@@ -133,6 +134,7 @@
"DerivedNode",
"DetectConfig",
"DetectPatternsResponse",
+ "DocumentSummary",
"EdgeType",
"EntityEdge",
"EntityEdgeSourceTarget",
diff --git a/src/zep_cloud/types/batch_add_item.py b/src/zep_cloud/types/batch_add_item.py
index a95cb4ab..687a33fc 100644
--- a/src/zep_cloud/types/batch_add_item.py
+++ b/src/zep_cloud/types/batch_add_item.py
@@ -14,6 +14,12 @@ class BatchAddItem(UniversalBaseModel):
created_at: typing.Optional[str] = None
data: typing.Optional[str] = None
data_type: typing.Optional[GraphDataType] = None
+ document_id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Optional document ID for graph_episode items. Groups episodes as document
+ chunks. Ignored for thread_message items.
+ """
+
graph_id: typing.Optional[str] = None
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
name: typing.Optional[str] = None
diff --git a/src/zep_cloud/types/batch_item_detail.py b/src/zep_cloud/types/batch_item_detail.py
index 439cd2fb..5d646aa9 100644
--- a/src/zep_cloud/types/batch_item_detail.py
+++ b/src/zep_cloud/types/batch_item_detail.py
@@ -10,6 +10,7 @@
class BatchItemDetail(UniversalBaseModel):
created_at: typing.Optional[str] = None
+ document_id: typing.Optional[str] = None
episode_uuid: typing.Optional[str] = pydantic.Field(default=None)
"""
EpisodeUUID is the UUID of the episode that will be (or has been) created
diff --git a/src/zep_cloud/types/batch_summary.py b/src/zep_cloud/types/batch_summary.py
index aaf0d40e..0ad20440 100644
--- a/src/zep_cloud/types/batch_summary.py
+++ b/src/zep_cloud/types/batch_summary.py
@@ -19,6 +19,7 @@ class BatchSummary(UniversalBaseModel):
processed_at: typing.Optional[str] = None
progress: typing.Optional[BatchProgress] = None
status: typing.Optional[BatchStatus] = None
+ strict_ontology: typing.Optional[bool] = None
updated_at: typing.Optional[str] = None
if IS_PYDANTIC_V2:
diff --git a/src/zep_cloud/types/document_summary.py b/src/zep_cloud/types/document_summary.py
new file mode 100644
index 00000000..a9dd72cf
--- /dev/null
+++ b/src/zep_cloud/types/document_summary.py
@@ -0,0 +1,51 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class DocumentSummary(UniversalBaseModel):
+ created_at: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ CreatedAt is when the summary node was first created.
+ """
+
+ document_id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ DocumentID is the customer-facing document identifier.
+ """
+
+ last_summarized_at: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ LastSummarizedAt is the wall-clock timestamp of the most recent
+ summary update.
+ """
+
+ last_summarized_episode_valid_at: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ LastSummarizedEpisodeValidAt is the maximum episode reference time
+ (valid_at) covered by the most recent summary.
+ """
+
+ summary: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Summary is the incremental summary content.
+ """
+
+ uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = pydantic.Field(default=None)
+ """
+ UUID of the document summary (derived) node.
+ """
+
+ 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/entity_edge.py b/src/zep_cloud/types/entity_edge.py
index 91a79a29..df80e16f 100644
--- a/src/zep_cloud/types/entity_edge.py
+++ b/src/zep_cloud/types/entity_edge.py
@@ -34,6 +34,12 @@ class EntityEdge(UniversalBaseModel):
Fact representing the edge and nodes that it connects
"""
+ hyperedge_uuid: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ HyperedgeUUID groups the pairwise edges projected from the same atomic
+ multi-entity fact. Omitted when the edge is not part of a hyperedge.
+ """
+
invalid_at: typing.Optional[str] = pydantic.Field(default=None)
"""
Datetime of when the fact stopped being true
@@ -68,7 +74,7 @@ class EntityEdge(UniversalBaseModel):
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).
+ read-time-projection semantics as SourceNodeName.
"""
source_node_name: typing.Optional[str] = pydantic.Field(default=None)
@@ -77,7 +83,7 @@ class EntityEdge(UniversalBaseModel):
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).
+ resolved, for example if it was deleted concurrently.
"""
source_node_uuid: str = pydantic.Field()
@@ -88,13 +94,13 @@ class EntityEdge(UniversalBaseModel):
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).
+ read-time-projection semantics as SourceNodeName.
"""
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).
+ read-time-projection semantics as SourceNodeName.
"""
target_node_uuid: str = pydantic.Field()
diff --git a/src/zep_cloud/types/entity_node.py b/src/zep_cloud/types/entity_node.py
index abed7274..9161cc17 100644
--- a/src/zep_cloud/types/entity_node.py
+++ b/src/zep_cloud/types/entity_node.py
@@ -19,6 +19,21 @@ class EntityNode(UniversalBaseModel):
Creation time of the node
"""
+ episodes: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
+ """
+ The UUIDs of the live episodes that mention this node, newest first. The
+ list is complete when `episodes_truncated` is false. The list is empty
+ when the node has more than 100 source episodes; list episodes with the
+ `mentioned_node_uuids` filter to read them.
+ """
+
+ episodes_truncated: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ True when the node has more than 100 source episodes, so `episodes` is
+ empty, or when provenance is unavailable. False means `episodes` is the
+ complete set.
+ """
+
labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
"""
Labels associated with the node
diff --git a/src/zep_cloud/types/episode.py b/src/zep_cloud/types/episode.py
index fa179eb7..9584ce87 100644
--- a/src/zep_cloud/types/episode.py
+++ b/src/zep_cloud/types/episode.py
@@ -13,6 +13,11 @@
class Episode(UniversalBaseModel):
content: str
created_at: str
+ document_id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Optional document ID, will be present if the episode is part of a document
+ """
+
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
processed: typing.Optional[bool] = None
relevance: typing.Optional[float] = pydantic.Field(default=None)
diff --git a/src/zep_cloud/types/graph.py b/src/zep_cloud/types/graph.py
index dd05ec34..38dc6dca 100644
--- a/src/zep_cloud/types/graph.py
+++ b/src/zep_cloud/types/graph.py
@@ -9,6 +9,13 @@
class Graph(UniversalBaseModel):
+ canonical_graph_uuid: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ CanonicalGraphUUID is graphs.uuid, the v4 graph address (spec-3 §13.5).
+ Omitted when the graphs row does not yet exist. Distinct from UUID,
+ which is the group-row identifier.
+ """
+
created_at: typing.Optional[str] = None
description: typing.Optional[str] = None
graph_id: typing.Optional[str] = None
diff --git a/src/zep_cloud/types/graph_episode_list_request.py b/src/zep_cloud/types/graph_episode_list_request.py
index e7bd251d..3a85f828 100644
--- a/src/zep_cloud/types/graph_episode_list_request.py
+++ b/src/zep_cloud/types/graph_episode_list_request.py
@@ -1,9 +1,11 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
+
import typing
import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel, update_forward_refs
class GraphEpisodeListRequest(UniversalBaseModel):
@@ -18,6 +20,12 @@ class GraphEpisodeListRequest(UniversalBaseModel):
Sort direction. One of "asc" or "desc". Defaults to "desc".
"""
+ episode_metadata_filters: typing.Optional["MetadataFilterGroup"] = pydantic.Field(default=None)
+ """
+ Restricts results to episodes whose stored metadata matches this
+ predicate. Same type and limits as graph.search episode_metadata_filters.
+ """
+
limit: typing.Optional[int] = pydantic.Field(default=None)
"""
Maximum number of episodes to return. An explicit value is clamped to
@@ -27,7 +35,9 @@ class GraphEpisodeListRequest(UniversalBaseModel):
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.
+ UUIDs. The list can also contain episode UUIDs: an episode UUID
+ matches that episode, so one request can return a known set of
+ episodes. At most 256 entries; each must be a syntactically valid UUID.
"""
order_by: typing.Optional[str] = pydantic.Field(default=None)
@@ -43,3 +53,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+from .metadata_filter_group import MetadataFilterGroup # noqa: E402, F401, I001
+
+update_forward_refs(GraphEpisodeListRequest)
diff --git a/src/zep_cloud/types/message.py b/src/zep_cloud/types/message.py
index 6fa51810..5edc1414 100644
--- a/src/zep_cloud/types/message.py
+++ b/src/zep_cloud/types/message.py
@@ -22,7 +22,7 @@ class Message(UniversalBaseModel):
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
"""
- The metadata associated with the message.
+ The metadata associated with the message. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars.
"""
name: typing.Optional[str] = pydantic.Field(default=None)
diff --git a/src/zep_cloud/types/thread.py b/src/zep_cloud/types/thread.py
index 964b51c9..ef3e5602 100644
--- a/src/zep_cloud/types/thread.py
+++ b/src/zep_cloud/types/thread.py
@@ -10,6 +10,11 @@
class Thread(UniversalBaseModel):
created_at: typing.Optional[str] = None
+ graph_uuid: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ GraphUUID is the graphs.uuid of the owning user's graph (spec-3 section 13.5).
+ """
+
project_uuid: typing.Optional[str] = None
thread_id: typing.Optional[str] = None
user_id: typing.Optional[str] = None
diff --git a/src/zep_cloud/types/thread_context_response.py b/src/zep_cloud/types/thread_context_response.py
index f6cc4d9b..dbd84361 100644
--- a/src/zep_cloud/types/thread_context_response.py
+++ b/src/zep_cloud/types/thread_context_response.py
@@ -9,7 +9,7 @@
class ThreadContextResponse(UniversalBaseModel):
context: typing.Optional[str] = pydantic.Field(default=None)
"""
- Context block containing relevant facts, entities, and messages/episodes from the user graph. Meant to be replaced in the system prompt on every chat turn.
+ Context block containing relevant facts, entities, and messages/episodes from the user graph. Pass it through the model provider's untrusted-data channel.
"""
if IS_PYDANTIC_V2:
diff --git a/src/zep_cloud/types/thread_summary.py b/src/zep_cloud/types/thread_summary.py
index db33c75d..88385d63 100644
--- a/src/zep_cloud/types/thread_summary.py
+++ b/src/zep_cloud/types/thread_summary.py
@@ -44,7 +44,7 @@ class ThreadSummary(UniversalBaseModel):
uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = pydantic.Field(default=None)
"""
- UUID of the thread summary node.
+ UUID of the derived thread summary node.
"""
if IS_PYDANTIC_V2:
diff --git a/src/zep_cloud/types/user.py b/src/zep_cloud/types/user.py
index 50b8df9a..5ccefd3f 100644
--- a/src/zep_cloud/types/user.py
+++ b/src/zep_cloud/types/user.py
@@ -14,6 +14,12 @@ class User(UniversalBaseModel):
disable_default_ontology: typing.Optional[bool] = None
email: typing.Optional[str] = None
first_name: typing.Optional[str] = None
+ graph_uuid: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ GraphUUID is the graphs.uuid of the user's graph (spec-3 section 13.5).
+ Omitted when the graph row does not exist. Read-only; never accepted as input.
+ """
+
id: typing.Optional[int] = None
last_name: typing.Optional[str] = None
metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
From cc5adb04a77f70b6a4fe0a96cd5ce973ad0bbb1c Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Wed, 23 Sep 2026 18:32:19 +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 afed4a45..a21a790c 100644
--- a/.fern/replay.lock
+++ b/.fern/replay.lock
@@ -24,5 +24,11 @@ generations:
cli_version: unknown
generator_versions:
fernapi/fern-python-sdk: 4.25.5
-current_generation: 8a3fb853912eadd78157bed5f9811ae936e834a8
+ - commit_sha: c78e60a610fc85f34bc472c3338458a2b92d5936
+ tree_hash: 562cd14134ac13986361bb7ea200734775c03b2b
+ timestamp: 2026-09-23T18:32:15.305Z
+ cli_version: unknown
+ generator_versions:
+ fernapi/fern-python-sdk: 4.25.5
+current_generation: c78e60a610fc85f34bc472c3338458a2b92d5936
patches: []
From 7a52092b15facfa8aeb43e0bd0b663a91126e676 Mon Sep 17 00:00:00 2001
From: "zep-sdk-release-bot[bot]"
Date: Wed, 23 Sep 2026 18:32:25 +0000
Subject: [PATCH 3/3] chore: bump SDK version to 3.29.0
---
pyproject.toml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 1e936748..70bd5399 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,10 @@
[project]
name = "zep-cloud"
-version = "3.28.0"
+version = "3.29.0"
[tool.poetry]
name = "zep-cloud"
-version = "3.28.0"
+version = "3.29.0"
description = ""
readme = "README.md"
authors = []